first commit
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "objects.h"
|
||||
|
||||
typedef struct OflowAlloc OflowAlloc;
|
||||
struct OflowAlloc {
|
||||
OflowAlloc *prev;
|
||||
char body[];
|
||||
};
|
||||
|
||||
struct xHeap {
|
||||
int size;
|
||||
int used;
|
||||
void *body;
|
||||
OflowAlloc *oflow;
|
||||
};
|
||||
|
||||
Heap *Heap_New(int size)
|
||||
{
|
||||
if(size < 0)
|
||||
size = 65536;
|
||||
|
||||
Heap *heap = malloc(sizeof(Heap));
|
||||
|
||||
if(heap == NULL)
|
||||
return NULL;
|
||||
|
||||
heap->size = size;
|
||||
heap->used = 0;
|
||||
heap->body = malloc(size);
|
||||
heap->oflow = 0;
|
||||
|
||||
if(heap->body == NULL)
|
||||
{
|
||||
free(heap);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return heap;
|
||||
}
|
||||
|
||||
void Heap_Free(Heap *heap)
|
||||
{
|
||||
while(heap->oflow)
|
||||
{
|
||||
OflowAlloc *prev = heap->oflow->prev;
|
||||
free(heap->oflow);
|
||||
heap->oflow = prev;
|
||||
}
|
||||
|
||||
free(heap->body);
|
||||
free(heap);
|
||||
}
|
||||
|
||||
void *Heap_Malloc(Heap *heap, const Type *type, Error *err)
|
||||
{
|
||||
void *addr = Heap_RawMalloc(heap, type->size, err);
|
||||
|
||||
if(addr == NULL)
|
||||
return NULL;
|
||||
|
||||
Object *obj = addr;
|
||||
|
||||
obj->type = type;
|
||||
obj->flags = 0;
|
||||
|
||||
if(type->init && !type->init(obj, err))
|
||||
return NULL;
|
||||
|
||||
obj->type = type;
|
||||
obj->flags = 0;
|
||||
|
||||
return (Object*) addr;
|
||||
}
|
||||
|
||||
void *Heap_RawMalloc(Heap *heap, int size, Error *err)
|
||||
{
|
||||
assert(err);
|
||||
assert(heap);
|
||||
assert(size > -1);
|
||||
|
||||
void *addr;
|
||||
|
||||
if(heap->used + size >= heap->size)
|
||||
{
|
||||
OflowAlloc *oflow = malloc(sizeof(OflowAlloc) + size);
|
||||
|
||||
if(oflow == 0)
|
||||
return 0;
|
||||
|
||||
oflow->prev = heap->oflow;
|
||||
heap->oflow = oflow;
|
||||
|
||||
addr = oflow->body;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(heap->used & 7)
|
||||
heap->used = (heap->used & ~7) + 8;
|
||||
|
||||
addr = heap->body + heap->used;
|
||||
heap->used += size;
|
||||
}
|
||||
|
||||
assert(((intptr_t) addr) % 8 == 0);
|
||||
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
#include <assert.h>
|
||||
#include "objects.h"
|
||||
|
||||
static double to_float(Object *obj, Error *err);
|
||||
|
||||
typedef struct {
|
||||
Object base;
|
||||
double val;
|
||||
} FloatObject;
|
||||
|
||||
static const Type t_float = {
|
||||
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
|
||||
.name = "float",
|
||||
.size = sizeof (FloatObject),
|
||||
.atomic = ATMTP_FLOAT,
|
||||
.to_float = to_float,
|
||||
};
|
||||
|
||||
static double to_float(Object *obj, Error *err)
|
||||
{
|
||||
assert(obj);
|
||||
assert(err);
|
||||
assert(Object_GetType(obj) == &t_float);
|
||||
|
||||
(void) err;
|
||||
|
||||
return ((FloatObject*) obj)->val;
|
||||
}
|
||||
|
||||
Object *Object_FromFloat(double val, Heap *heap, Error *error)
|
||||
{
|
||||
FloatObject *obj = (FloatObject*) Heap_Malloc(heap, &t_float, error);
|
||||
|
||||
if(obj == 0)
|
||||
return 0;
|
||||
|
||||
obj->val = val;
|
||||
|
||||
return (Object*) obj;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "objects.h"
|
||||
|
||||
static long long int to_int(Object *obj, Error *err);
|
||||
|
||||
typedef struct {
|
||||
Object base;
|
||||
long long int val;
|
||||
} IntObject;
|
||||
|
||||
static const Type t_int = {
|
||||
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
|
||||
.name = "int",
|
||||
.size = sizeof (IntObject),
|
||||
.atomic = ATMTP_INT,
|
||||
.to_int = to_int,
|
||||
};
|
||||
|
||||
static long long int to_int(Object *obj, Error *err)
|
||||
{
|
||||
assert(obj);
|
||||
assert(err);
|
||||
assert(Object_GetType(obj) == &t_int);
|
||||
|
||||
(void) err;
|
||||
|
||||
return ((IntObject*) obj)->val;
|
||||
}
|
||||
|
||||
Object *Object_FromInt(long long int val, Heap *heap, Error *error)
|
||||
{
|
||||
IntObject *obj = (IntObject*) Heap_Malloc(heap, &t_int, error);
|
||||
|
||||
if(obj == 0)
|
||||
return 0;
|
||||
|
||||
obj->val = val;
|
||||
|
||||
return (Object*) obj;
|
||||
}
|
||||
@@ -0,0 +1,261 @@
|
||||
#include <assert.h>
|
||||
#include "../utils/defs.h"
|
||||
#include "objects.h"
|
||||
|
||||
typedef struct {
|
||||
Object base;
|
||||
int mapper_size, count;
|
||||
int *mapper;
|
||||
Object **keys;
|
||||
Object **vals;
|
||||
} MapObject;
|
||||
|
||||
static Object *select(Object *self, Object *key, Heap *heap, Error *err);
|
||||
static _Bool insert(Object *self, Object *key, Object *val, Heap *heap, Error *err);
|
||||
static int count(Object *self);
|
||||
|
||||
static const Type t_map = {
|
||||
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
|
||||
.name = "map",
|
||||
.size = sizeof (MapObject),
|
||||
.select = select,
|
||||
.insert = insert,
|
||||
.count = count,
|
||||
};
|
||||
|
||||
static inline int calc_capacity(int mapper_size)
|
||||
{
|
||||
return mapper_size * 2.0 / 3.0;
|
||||
}
|
||||
|
||||
Object *Object_NewMap(int num, Heap *heap, Error *error)
|
||||
{
|
||||
// Handle default args.
|
||||
if(num < 0)
|
||||
num = 0;
|
||||
|
||||
// Calculate initial mapper size.
|
||||
int mapper_size, capacity;
|
||||
{
|
||||
mapper_size = 8;
|
||||
while(calc_capacity(mapper_size) < num)
|
||||
mapper_size <<= 1;
|
||||
|
||||
capacity = calc_capacity(mapper_size);
|
||||
}
|
||||
|
||||
// Make the thing.
|
||||
MapObject *obj = (MapObject*) Heap_Malloc(heap, &t_map, error);
|
||||
{
|
||||
if(obj == 0)
|
||||
return 0;
|
||||
|
||||
obj->mapper_size = mapper_size;
|
||||
obj->count = 0;
|
||||
obj->mapper = Heap_RawMalloc(heap, sizeof(int) * capacity, error);
|
||||
obj->keys = Heap_RawMalloc(heap, sizeof(Object*) * capacity, error);
|
||||
obj->vals = Heap_RawMalloc(heap, sizeof(Object*) * capacity, error);
|
||||
|
||||
if(obj->mapper == NULL || obj->keys == NULL || obj->vals == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for(int i = 0; i < mapper_size; i += 1)
|
||||
obj->mapper[i] = -1;
|
||||
|
||||
return (Object*) obj;
|
||||
}
|
||||
|
||||
static Object *select(Object *self, Object *key, Heap *heap, Error *error)
|
||||
{
|
||||
assert(self != NULL);
|
||||
assert(self->type == &t_map);
|
||||
assert(key != NULL);
|
||||
assert(heap != NULL);
|
||||
assert(error != NULL);
|
||||
|
||||
MapObject *map = (MapObject*) self;
|
||||
|
||||
int mask = map->mapper_size - 1;
|
||||
int hash = Object_Hash(key, error);
|
||||
int pert = hash;
|
||||
|
||||
if(error->occurred)
|
||||
// No hash function.
|
||||
return 0;
|
||||
|
||||
int i = hash & mask;
|
||||
|
||||
while(1)
|
||||
{
|
||||
int k = map->mapper[i];
|
||||
|
||||
if(k == -1)
|
||||
{
|
||||
// Empty slot.
|
||||
// This key is not present.
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Found an item.
|
||||
// Is it the right one?
|
||||
|
||||
assert(k >= 0);
|
||||
|
||||
if(Object_Compare(key, map->keys[i], error))
|
||||
// Found it!
|
||||
return map->vals[i];
|
||||
|
||||
if(error->occurred)
|
||||
// Key doesn't implement compare.
|
||||
return 0;
|
||||
|
||||
// Not the one we wanted.
|
||||
}
|
||||
|
||||
pert >>= 5;
|
||||
i = (i * 5 + pert + 1) & mask;
|
||||
}
|
||||
|
||||
UNREACHABLE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static _Bool grow(MapObject *map, Heap *heap, Error *error)
|
||||
{
|
||||
assert(map != NULL);
|
||||
|
||||
int new_mapper_size = map->mapper_size << 1;
|
||||
int new_capacity = calc_capacity(new_mapper_size);
|
||||
|
||||
int *mapper = Heap_RawMalloc(heap, sizeof(int) * new_mapper_size, error);
|
||||
Object **keys = Heap_RawMalloc(heap, sizeof(Object*) * new_capacity, error);
|
||||
Object **vals = Heap_RawMalloc(heap, sizeof(Object*) * new_capacity, error);
|
||||
|
||||
if(mapper == NULL || keys == NULL || vals == NULL)
|
||||
return 0;
|
||||
|
||||
for(int i = 0; i < map->count; i += 1)
|
||||
{
|
||||
keys[i] = map->keys[i];
|
||||
vals[i] = map->vals[i];
|
||||
}
|
||||
|
||||
for(int i = 0; i < new_mapper_size; i += 1)
|
||||
mapper[i] = -1;
|
||||
|
||||
// Rehash everything.
|
||||
for(int i = 0; i < map->count; i += 1)
|
||||
{
|
||||
// This won't trigger an error because the key
|
||||
// surely has a hash method since we already
|
||||
// hashed it once.
|
||||
int hash = Object_Hash(keys[i], error);
|
||||
assert(error->occurred == 0);
|
||||
|
||||
int mask = new_mapper_size - 1;
|
||||
int pert = hash;
|
||||
|
||||
int j = hash & mask;
|
||||
|
||||
while(1)
|
||||
{
|
||||
if(mapper[j] == -1)
|
||||
{
|
||||
// No collision.
|
||||
// Insert here.
|
||||
mapper[j] = i;
|
||||
break;
|
||||
}
|
||||
|
||||
// Collided. Find a new place.
|
||||
pert >>= 5;
|
||||
j = (j * 5 + pert + 1) & mask;
|
||||
}
|
||||
}
|
||||
|
||||
// Done.
|
||||
map->mapper = mapper;
|
||||
map->mapper_size = new_mapper_size;
|
||||
map->keys = keys;
|
||||
map->vals = vals;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static _Bool insert(Object *self, Object *key, Object *val, Heap *heap, Error *error)
|
||||
{
|
||||
assert(error != NULL);
|
||||
assert(key != NULL);
|
||||
assert(val != NULL);
|
||||
assert(heap != NULL);
|
||||
assert(self != NULL);
|
||||
assert(self->type == &t_map);
|
||||
|
||||
MapObject *map = (MapObject*) self;
|
||||
|
||||
if(map->count == calc_capacity(map->mapper_size))
|
||||
if(!grow(map, heap, error))
|
||||
return 0;
|
||||
|
||||
int mask = map->mapper_size - 1;
|
||||
int hash = Object_Hash(key, error);
|
||||
int pert = hash;
|
||||
|
||||
if(error->occurred)
|
||||
// No hash function.
|
||||
return 0;
|
||||
|
||||
int i = hash & mask;
|
||||
|
||||
while(1)
|
||||
{
|
||||
int k = map->mapper[i];
|
||||
|
||||
if(k == -1)
|
||||
{
|
||||
// Empty slot. We can insert it here.
|
||||
Object *key_copy = Object_Copy(key, heap, error);
|
||||
|
||||
if(key_copy == NULL)
|
||||
return NULL;
|
||||
|
||||
map->mapper[i] = map->count;
|
||||
map->keys[map->count] = key_copy;
|
||||
map->vals[map->count] = val;
|
||||
map->count += 1;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(k >= 0);
|
||||
|
||||
if(Object_Compare(key, map->keys[i], error))
|
||||
{
|
||||
// Already inserted.
|
||||
// Overwrite the value.
|
||||
map->vals[i] = val;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(error->occurred)
|
||||
// Key doesn't implement compare.
|
||||
return 0;
|
||||
|
||||
// Collision.
|
||||
}
|
||||
|
||||
pert >>= 5;
|
||||
i = (i * 5 + pert + 1) & mask;
|
||||
}
|
||||
|
||||
UNREACHABLE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int count(Object *self)
|
||||
{
|
||||
MapObject *map = (MapObject*) self;
|
||||
|
||||
return map->count;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "objects.h"
|
||||
|
||||
static const Type t_none = {
|
||||
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
|
||||
.name = "none",
|
||||
.size = sizeof (Object),
|
||||
};
|
||||
|
||||
static Object the_none_object = {
|
||||
.type = &t_none,
|
||||
.flags = Object_STATIC,
|
||||
};
|
||||
|
||||
Object *Object_NewNone(Heap *heap, Error *error)
|
||||
{
|
||||
(void) heap;
|
||||
(void) error;
|
||||
return &the_none_object;
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "../utils/defs.h"
|
||||
#include "../utils/hash.h"
|
||||
#include "objects.h"
|
||||
|
||||
typedef struct {
|
||||
Object base;
|
||||
int size;
|
||||
char *body;
|
||||
} StringObject;
|
||||
|
||||
static int hash(Object *self);
|
||||
static int count(Object *self);
|
||||
|
||||
static const Type t_string = {
|
||||
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
|
||||
.name = "string",
|
||||
.size = sizeof (StringObject),
|
||||
.hash = hash,
|
||||
.count = count,
|
||||
};
|
||||
|
||||
Object *Object_FromString(const char *str, int len, Heap *heap, Error *error)
|
||||
{
|
||||
assert(str != NULL);
|
||||
assert(heap != NULL);
|
||||
assert(error != NULL);
|
||||
|
||||
if(len < 0)
|
||||
len = strlen(str);
|
||||
|
||||
StringObject *strobj = Heap_Malloc(heap, &t_string, error);
|
||||
|
||||
if(strobj == NULL)
|
||||
return NULL;
|
||||
|
||||
strobj->body = Heap_RawMalloc(heap, len+1, error);
|
||||
strobj->size = len;
|
||||
|
||||
if(strobj->body == NULL)
|
||||
return NULL;
|
||||
|
||||
memcpy(strobj->body, str, len);
|
||||
|
||||
strobj->body[len] = '\0';
|
||||
|
||||
return (Object*) strobj;
|
||||
}
|
||||
|
||||
static int count(Object *self)
|
||||
{
|
||||
assert(self != NULL);
|
||||
assert(self->type == &t_string);
|
||||
|
||||
StringObject *strobj = (StringObject*) self;
|
||||
|
||||
return strobj->size;
|
||||
}
|
||||
|
||||
static int hash(Object *self)
|
||||
{
|
||||
assert(self != NULL);
|
||||
assert(self->type == &t_string);
|
||||
|
||||
StringObject *strobj = (StringObject*) self;
|
||||
|
||||
return hashbytes((unsigned char*) strobj->body, strobj->size);
|
||||
}
|
||||
@@ -0,0 +1,286 @@
|
||||
#include <assert.h>
|
||||
#include "../utils/defs.h"
|
||||
#include "objects.h"
|
||||
|
||||
const Type t_type = {
|
||||
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
|
||||
.name = "type",
|
||||
.size = sizeof (Type),
|
||||
};
|
||||
|
||||
const char *Object_GetName(const Object *obj)
|
||||
{
|
||||
assert(obj);
|
||||
|
||||
const Type *type = Object_GetType(obj);
|
||||
assert(type);
|
||||
|
||||
const char *name = type->name;
|
||||
assert(name);
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
const Type *Object_GetType(const Object *obj)
|
||||
{
|
||||
assert(obj);
|
||||
assert(obj->type);
|
||||
return obj->type;
|
||||
}
|
||||
|
||||
unsigned int Object_GetSize(const Object *obj, Error *err)
|
||||
{
|
||||
assert(err);
|
||||
assert(obj);
|
||||
|
||||
const Type *type = Object_GetType(obj);
|
||||
assert(type);
|
||||
|
||||
return type->size;
|
||||
}
|
||||
|
||||
unsigned int Object_GetDeepSize(const Object *obj, Error *err)
|
||||
{
|
||||
assert(err);
|
||||
assert(obj);
|
||||
|
||||
const Type *type = Object_GetType(obj);
|
||||
assert(type);
|
||||
|
||||
if(type->deepsize == NULL)
|
||||
{
|
||||
Error_Report(err, "Object %s doesn't implement %s", Object_GetName(obj), __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return type->deepsize(obj);
|
||||
}
|
||||
|
||||
int Object_Hash(Object *obj, Error *err)
|
||||
{
|
||||
assert(obj);
|
||||
|
||||
const Type *type = Object_GetType(obj);
|
||||
assert(type);
|
||||
|
||||
if(type->hash == NULL)
|
||||
{
|
||||
Error_Report(err, "Object %s doesn't implement %s", Object_GetName(obj), __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return type->hash(obj);
|
||||
}
|
||||
|
||||
Object *Object_Copy(Object *obj, Heap *heap, Error *err)
|
||||
{
|
||||
assert(err);
|
||||
assert(obj);
|
||||
|
||||
const Type *type = Object_GetType(obj);
|
||||
assert(type);
|
||||
|
||||
if(type->copy == NULL)
|
||||
{
|
||||
Error_Report(err, "Object %s doesn't implement %s", Object_GetName(obj), __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return type->copy(obj, heap, err);
|
||||
}
|
||||
|
||||
Object *Object_Call(Object *obj, Object **argv, unsigned int argc, Heap *heap, Error *err)
|
||||
{
|
||||
assert(err);
|
||||
assert(obj);
|
||||
|
||||
const Type *type = Object_GetType(obj);
|
||||
assert(type);
|
||||
|
||||
if(type->call == NULL)
|
||||
{
|
||||
Error_Report(err, "Object %s doesn't implement %s", Object_GetName(obj), __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return type->call(obj, argv, argc, heap, err);
|
||||
}
|
||||
|
||||
Object *Object_Select(Object *coll, Object *key, Heap *heap, Error *err)
|
||||
{
|
||||
assert(err);
|
||||
assert(key);
|
||||
assert(coll);
|
||||
|
||||
const Type *type = Object_GetType(coll);
|
||||
assert(type);
|
||||
|
||||
if(type->select == NULL)
|
||||
{
|
||||
Error_Report(err, "Object %s doesn't implement %s", Object_GetName(coll), __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return type->select(coll, key, heap, err);
|
||||
}
|
||||
|
||||
Object *Object_Delete(Object *coll, Object *key, Heap *heap, Error *err)
|
||||
{
|
||||
assert(err);
|
||||
assert(key);
|
||||
assert(coll);
|
||||
|
||||
const Type *type = Object_GetType(coll);
|
||||
assert(type);
|
||||
|
||||
if(type->delete == NULL)
|
||||
{
|
||||
Error_Report(err, "Object %s doesn't implement %s", Object_GetName(coll), __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return type->delete(coll, key, heap, err);
|
||||
}
|
||||
|
||||
_Bool Object_Insert(Object *coll, Object *key, Object *val, Heap *heap, Error *err)
|
||||
{
|
||||
assert(err);
|
||||
assert(key);
|
||||
assert(coll);
|
||||
|
||||
const Type *type = Object_GetType(coll);
|
||||
assert(type);
|
||||
|
||||
if(type->insert == NULL)
|
||||
{
|
||||
Error_Report(err, "Object %s doesn't implement %s", Object_GetName(coll), __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return type->insert(coll, key, val, heap, err);
|
||||
}
|
||||
|
||||
int Object_Count(Object *coll, Error *err)
|
||||
{
|
||||
assert(err);
|
||||
assert(coll);
|
||||
|
||||
const Type *type = Object_GetType(coll);
|
||||
assert(type);
|
||||
|
||||
if(type->count == NULL)
|
||||
{
|
||||
Error_Report(err, "Object %s doesn't implement %s", Object_GetName(coll), __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return type->count(coll);
|
||||
}
|
||||
|
||||
Object *Object_Next(Object *iter, Heap *heap, Error *err)
|
||||
{
|
||||
assert(err);
|
||||
assert(iter);
|
||||
|
||||
const Type *type = Object_GetType(iter);
|
||||
assert(type);
|
||||
|
||||
if(type->next == NULL)
|
||||
{
|
||||
Error_Report(err, "Object %s doesn't implement %s", Object_GetName(iter), __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return type->next(iter, heap, err);
|
||||
}
|
||||
|
||||
Object *Object_Prev(Object *iter, Heap *heap, Error *err)
|
||||
{
|
||||
assert(err);
|
||||
assert(iter);
|
||||
|
||||
const Type *type = Object_GetType(iter);
|
||||
assert(type);
|
||||
|
||||
if(type->prev == NULL)
|
||||
{
|
||||
Error_Report(err, "Object %s doesn't implement %s", Object_GetName(iter), __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return type->prev(iter, heap, err);
|
||||
}
|
||||
|
||||
_Bool Object_IsInt(Object *obj)
|
||||
{
|
||||
assert(obj != NULL);
|
||||
assert(obj->type != NULL);
|
||||
return obj->type->atomic == ATMTP_INT;
|
||||
}
|
||||
|
||||
_Bool Object_IsFloat(Object *obj)
|
||||
{
|
||||
assert(obj != NULL);
|
||||
assert(obj->type != NULL);
|
||||
return obj->type->atomic == ATMTP_FLOAT;
|
||||
}
|
||||
|
||||
long long int Object_ToInt(Object *obj, Error *err)
|
||||
{
|
||||
assert(err);
|
||||
assert(obj);
|
||||
|
||||
if(!Object_IsInt(obj))
|
||||
{
|
||||
Error_Report(err, 0, "Object is not an integer");
|
||||
return 0;
|
||||
}
|
||||
|
||||
const Type *type = Object_GetType(obj);
|
||||
assert(type);
|
||||
|
||||
if(type->to_int == NULL)
|
||||
{
|
||||
Error_Report(err, "Object %s doesn't implement %s", Object_GetName(obj), __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return type->to_int(obj, err);
|
||||
}
|
||||
|
||||
double Object_ToFloat(Object *obj, Error *err)
|
||||
{
|
||||
assert(err);
|
||||
assert(obj);
|
||||
|
||||
if(!Object_IsFloat(obj))
|
||||
{
|
||||
Error_Report(err, 0, "Object is not a floating");
|
||||
return 0;
|
||||
}
|
||||
|
||||
const Type *type = Object_GetType(obj);
|
||||
assert(type);
|
||||
|
||||
if(type->to_float == NULL)
|
||||
{
|
||||
Error_Report(err, "Object %s doesn't implement %s", Object_GetName(obj), __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return type->to_float(obj, err);
|
||||
}
|
||||
|
||||
_Bool Object_Compare(Object *obj1, Object *obj2, Error *error)
|
||||
{
|
||||
if(obj1->type != obj2->type)
|
||||
return 0;
|
||||
|
||||
if(obj1->type->op_eql == NULL)
|
||||
{
|
||||
Error_Report(error, "Object %s doesn't implement %s", Object_GetName(obj1), __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return obj1->type->op_eql(obj1, obj2);
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
#ifndef OBJECT_H
|
||||
#define OBJECT_H
|
||||
|
||||
#include "../utils/error.h"
|
||||
|
||||
typedef struct Type Type;
|
||||
typedef struct Object Object;
|
||||
typedef struct xHeap Heap;
|
||||
|
||||
struct Object {
|
||||
const Type *type;
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
ATMTP_NOTATOMIC = 0,
|
||||
ATMTP_INT,
|
||||
ATMTP_FLOAT,
|
||||
} AtomicType;
|
||||
|
||||
struct Type {
|
||||
|
||||
Object base;
|
||||
|
||||
// Any.
|
||||
const char *name;
|
||||
unsigned int size;
|
||||
AtomicType atomic;
|
||||
|
||||
_Bool (*init)(Object *self, Error *err);
|
||||
_Bool (*free)(Object *self, Error *err);
|
||||
int (*hash)(Object *self);
|
||||
Object* (*copy)(Object *self, Heap *heap, Error *err);
|
||||
Object* (*call)(Object *self, Object **argv, unsigned int argc, Heap *heap, Error *err);
|
||||
unsigned int (*deepsize)(const Object *self);
|
||||
|
||||
// Collections.
|
||||
Object *(*select)(Object *self, Object *key, Heap *heap, Error *err);
|
||||
Object *(*delete)(Object *self, Object *key, Heap *heap, Error *err);
|
||||
_Bool (*insert)(Object *self, Object *key, Object *val, Heap *heap, Error *err);
|
||||
int (*count)(Object *self);
|
||||
|
||||
// Iterators.
|
||||
Object *(*next)(Object *self, Heap *heap, Error *err);
|
||||
Object *(*prev)(Object *self, Heap *heap, Error *err);
|
||||
|
||||
// Some.
|
||||
union {
|
||||
long long int (*to_int)(Object *self, Error *err);
|
||||
double (*to_float)(Object *self, Error *err);
|
||||
char *(*to_string)(Object *self, int *size, Heap *heap, Error *err);
|
||||
};
|
||||
|
||||
_Bool (*op_eql)(Object *self, Object *other);
|
||||
};
|
||||
|
||||
enum {
|
||||
Object_STATIC = 1,
|
||||
};
|
||||
|
||||
Heap* Heap_New(int size);
|
||||
void Heap_Free(Heap *heap);
|
||||
void* Heap_Malloc (Heap *heap, const Type *type, Error *err);
|
||||
void* Heap_RawMalloc(Heap *heap, int size, Error *err);
|
||||
|
||||
const Type* Object_GetType(const Object *obj);
|
||||
const char* Object_GetName(const Object *obj);
|
||||
unsigned int Object_GetSize(const Object *obj, Error *err);
|
||||
unsigned int Object_GetDeepSize(const Object *obj, Error *err);
|
||||
int Object_Hash (Object *obj, Error *err);
|
||||
Object* Object_Copy (Object *obj, Heap *heap, Error *err);
|
||||
Object* Object_Call (Object *obj, Object **argv, unsigned int argc, Heap *heap, Error *err);
|
||||
Object* Object_Select(Object *coll, Object *key, Heap *heap, Error *err);
|
||||
Object* Object_Delete(Object *coll, Object *key, Heap *heap, Error *err);
|
||||
_Bool Object_Insert(Object *coll, Object *key, Object *val, Heap *heap, Error *err);
|
||||
int Object_Count (Object *coll, Error *err);
|
||||
Object* Object_Next (Object *iter, Heap *heap, Error *err);
|
||||
Object* Object_Prev (Object *iter, Heap *heap, Error *err);
|
||||
|
||||
Object* Object_NewMap(int num, Heap *heap, Error *error);
|
||||
Object* Object_NewNone(Heap *heap, Error *error);
|
||||
|
||||
Object* Object_FromInt (long long int val, Heap *heap, Error *error);
|
||||
Object* Object_FromFloat (double val, Heap *heap, Error *error);
|
||||
Object* Object_FromString(const char *str, int len, Heap *heap, Error *error);
|
||||
|
||||
_Bool Object_IsInt (Object *obj);
|
||||
_Bool Object_IsFloat(Object *obj);
|
||||
|
||||
long long int Object_ToInt (Object *obj, Error *err);
|
||||
double Object_ToFloat(Object *obj, Error *err);
|
||||
|
||||
_Bool Object_Compare(Object *obj1, Object *obj2, Error *error);
|
||||
|
||||
extern const Type t_type;
|
||||
#endif
|
||||
Reference in New Issue
Block a user