added hash,copy methods for lists and maps. The hash method is now obligatory
This commit is contained in:
@@ -15,11 +15,15 @@ static int count(Object *self);
|
|||||||
static void print(Object *obj, FILE *fp);
|
static void print(Object *obj, FILE *fp);
|
||||||
static void walk(Object *self, void (*callback)(Object **referer, void *userp), void *userp);
|
static void walk(Object *self, void (*callback)(Object **referer, void *userp), void *userp);
|
||||||
static void walkexts(Object *self, void (*callback)(void **referer, unsigned int size, void *userp), void *userp);
|
static void walkexts(Object *self, void (*callback)(void **referer, unsigned int size, void *userp), void *userp);
|
||||||
|
static Object *copy(Object *self, Heap *heap, Error *err);
|
||||||
|
static int hash(Object *self);
|
||||||
|
|
||||||
static TypeObject t_list = {
|
static TypeObject t_list = {
|
||||||
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
|
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
|
||||||
.name = "list",
|
.name = "list",
|
||||||
.size = sizeof (ListObject),
|
.size = sizeof (ListObject),
|
||||||
|
.copy = copy,
|
||||||
|
.hash = hash,
|
||||||
.select = select,
|
.select = select,
|
||||||
.insert = insert,
|
.insert = insert,
|
||||||
.count = count,
|
.count = count,
|
||||||
@@ -28,6 +32,43 @@ static TypeObject t_list = {
|
|||||||
.walkexts = walkexts,
|
.walkexts = walkexts,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int hash(Object *self)
|
||||||
|
{
|
||||||
|
assert(self != NULL);
|
||||||
|
assert(self->type == &t_list);
|
||||||
|
|
||||||
|
ListObject *ls = (ListObject*) self;
|
||||||
|
|
||||||
|
int h = 0;
|
||||||
|
// The hash is the sum of the nested
|
||||||
|
// hashes. It's not a smart solution
|
||||||
|
// but it works for now.
|
||||||
|
for(int i = 0; i < ls->count; i += 1)
|
||||||
|
h += Object_Hash(ls->vals[i]);
|
||||||
|
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Object *copy(Object *self, Heap *heap, Error *err)
|
||||||
|
{
|
||||||
|
(void) heap;
|
||||||
|
(void) err;
|
||||||
|
|
||||||
|
ListObject *ls = (ListObject*) self;
|
||||||
|
ListObject *ls2 = (ListObject*) Object_NewList(ls->count, heap, err);
|
||||||
|
if(ls2 == NULL) return NULL;
|
||||||
|
|
||||||
|
for(int i = 0; i < ls->count; i += 1)
|
||||||
|
{
|
||||||
|
ls2->vals[i] = Object_Copy(ls->vals[i], heap, err);
|
||||||
|
if(err->occurred) return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ls2->count = ls->count;
|
||||||
|
|
||||||
|
return (Object*) ls2;
|
||||||
|
}
|
||||||
|
|
||||||
static inline int calc_capacity(int mapper_size)
|
static inline int calc_capacity(int mapper_size)
|
||||||
{
|
{
|
||||||
return mapper_size * 2.0 / 3.0;
|
return mapper_size * 2.0 / 3.0;
|
||||||
|
|||||||
+47
-12
@@ -16,11 +16,15 @@ static int count(Object *self);
|
|||||||
static void print(Object *self, FILE *fp);
|
static void print(Object *self, FILE *fp);
|
||||||
static void walk(Object *self, void (*callback)(Object **referer, void *userp), void *userp);
|
static void walk(Object *self, void (*callback)(Object **referer, void *userp), void *userp);
|
||||||
static void walkexts(Object *self, void (*callback)(void **referer, unsigned int size, void *userp), void *userp);
|
static void walkexts(Object *self, void (*callback)(void **referer, unsigned int size, void *userp), void *userp);
|
||||||
|
static Object *copy(Object *self, Heap *heap, Error *err);
|
||||||
|
static int hash(Object *self);
|
||||||
|
|
||||||
static TypeObject t_map = {
|
static TypeObject t_map = {
|
||||||
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
|
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
|
||||||
.name = "map",
|
.name = "map",
|
||||||
.size = sizeof (MapObject),
|
.size = sizeof (MapObject),
|
||||||
|
.copy = copy,
|
||||||
|
.hash = hash,
|
||||||
.select = select,
|
.select = select,
|
||||||
.insert = insert,
|
.insert = insert,
|
||||||
.count = count,
|
.count = count,
|
||||||
@@ -34,6 +38,46 @@ static inline int calc_capacity(int mapper_size)
|
|||||||
return mapper_size * 2.0 / 3.0;
|
return mapper_size * 2.0 / 3.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Object *copy(Object *self, Heap *heap, Error *err)
|
||||||
|
{
|
||||||
|
MapObject *m1 = (MapObject*) self;
|
||||||
|
Object *m2 = Object_NewMap(m1->count, heap, err);
|
||||||
|
if(m2 == NULL) return NULL;
|
||||||
|
|
||||||
|
for(int i = 0; i < m1->count; i += 1)
|
||||||
|
{
|
||||||
|
Object *key, *key_cpy;
|
||||||
|
Object *val, *val_cpy;
|
||||||
|
|
||||||
|
key = m1->keys[i];
|
||||||
|
val = m1->vals[i];
|
||||||
|
|
||||||
|
key_cpy = Object_Copy(key, heap, err);
|
||||||
|
if(key_cpy == NULL) return NULL;
|
||||||
|
|
||||||
|
val_cpy = Object_Copy(val, heap, err);
|
||||||
|
if(val_cpy == NULL) return NULL;
|
||||||
|
|
||||||
|
if(!Object_Insert(m2, key_cpy, val_cpy, heap, err))
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (Object*) m2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hash(Object *self)
|
||||||
|
{
|
||||||
|
MapObject *m = (MapObject*) self;
|
||||||
|
|
||||||
|
int h = 0;
|
||||||
|
// The hash of the map is the sum of the
|
||||||
|
// hashes of each key and each item.
|
||||||
|
for(int i = 0; i < m->count; i += 1)
|
||||||
|
h += Object_Hash(m->keys[i])
|
||||||
|
+ Object_Hash(m->vals[i]);
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
Object *Object_NewMap(int num, Heap *heap, Error *error)
|
Object *Object_NewMap(int num, Heap *heap, Error *error)
|
||||||
{
|
{
|
||||||
// Handle default args.
|
// Handle default args.
|
||||||
@@ -107,13 +151,9 @@ static Object *select(Object *self, Object *key, Heap *heap, Error *error)
|
|||||||
MapObject *map = (MapObject*) self;
|
MapObject *map = (MapObject*) self;
|
||||||
|
|
||||||
unsigned int mask = map->mapper_size - 1;
|
unsigned int mask = map->mapper_size - 1;
|
||||||
unsigned int hash = Object_Hash(key, error);
|
unsigned int hash = Object_Hash(key);
|
||||||
unsigned int pert = hash;
|
unsigned int pert = hash;
|
||||||
|
|
||||||
if(error->occurred)
|
|
||||||
// No hash function.
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
int i = hash & mask;
|
int i = hash & mask;
|
||||||
|
|
||||||
while(1)
|
while(1)
|
||||||
@@ -181,8 +221,7 @@ static _Bool grow(MapObject *map, Heap *heap, Error *error)
|
|||||||
// This won't trigger an error because the key
|
// This won't trigger an error because the key
|
||||||
// surely has a hash method since we already
|
// surely has a hash method since we already
|
||||||
// hashed it once.
|
// hashed it once.
|
||||||
int hash = Object_Hash(keys[i], error);
|
int hash = Object_Hash(keys[i]);
|
||||||
assert(error->occurred == 0);
|
|
||||||
|
|
||||||
int mask = new_mapper_size - 1;
|
int mask = new_mapper_size - 1;
|
||||||
int pert = hash;
|
int pert = hash;
|
||||||
@@ -229,13 +268,9 @@ static _Bool insert(Object *self, Object *key, Object *val, Heap *heap, Error *e
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
unsigned int mask = map->mapper_size - 1;
|
unsigned int mask = map->mapper_size - 1;
|
||||||
unsigned int hash = Object_Hash(key, error);
|
unsigned int hash = Object_Hash(key);
|
||||||
unsigned int pert = hash;
|
unsigned int pert = hash;
|
||||||
|
|
||||||
if(error->occurred)
|
|
||||||
// No hash function.
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
int i = hash & mask;
|
int i = hash & mask;
|
||||||
|
|
||||||
while(1)
|
while(1)
|
||||||
|
|||||||
+18
-2
@@ -3,12 +3,16 @@
|
|||||||
#include "objects.h"
|
#include "objects.h"
|
||||||
|
|
||||||
static _Bool op_eql(Object *self, Object *other);
|
static _Bool op_eql(Object *self, Object *other);
|
||||||
static void print(Object *obj, FILE *fp);
|
static void print(Object *obj, FILE *fp);
|
||||||
|
static int hash(Object *self);
|
||||||
|
static Object *copy(Object *self, Heap *heap, Error *err);
|
||||||
|
|
||||||
static TypeObject t_none = {
|
static TypeObject t_none = {
|
||||||
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
|
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
|
||||||
.name = "none",
|
.name = "none",
|
||||||
.size = sizeof (Object),
|
.size = sizeof (Object),
|
||||||
|
.hash = hash,
|
||||||
|
.copy = copy,
|
||||||
.print = print,
|
.print = print,
|
||||||
.op_eql = op_eql,
|
.op_eql = op_eql,
|
||||||
};
|
};
|
||||||
@@ -18,6 +22,19 @@ static Object the_none_object = {
|
|||||||
.flags = Object_STATIC,
|
.flags = Object_STATIC,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int hash(Object *self)
|
||||||
|
{
|
||||||
|
assert(self == &the_none_object);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Object *copy(Object *self, Heap *heap, Error *err)
|
||||||
|
{
|
||||||
|
(void) heap;
|
||||||
|
(void) err;
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
Object *Object_NewNone(Heap *heap, Error *error)
|
Object *Object_NewNone(Heap *heap, Error *error)
|
||||||
{
|
{
|
||||||
(void) heap;
|
(void) heap;
|
||||||
@@ -25,7 +42,6 @@ Object *Object_NewNone(Heap *heap, Error *error)
|
|||||||
return &the_none_object;
|
return &the_none_object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void print(Object *obj, FILE *fp)
|
static void print(Object *obj, FILE *fp)
|
||||||
{
|
{
|
||||||
assert(fp != NULL);
|
assert(fp != NULL);
|
||||||
|
|||||||
@@ -64,19 +64,12 @@ unsigned int Object_GetDeepSize(const Object *obj, Error *err)
|
|||||||
return type->deepsize(obj);
|
return type->deepsize(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Object_Hash(Object *obj, Error *err)
|
int Object_Hash(Object *obj)
|
||||||
{
|
{
|
||||||
assert(obj != NULL);
|
assert(obj != NULL);
|
||||||
|
|
||||||
const TypeObject *type = Object_GetType(obj);
|
const TypeObject *type = Object_GetType(obj);
|
||||||
assert(type != NULL);
|
assert(type != NULL);
|
||||||
|
assert(type->hash != NULL);
|
||||||
if(type->hash == NULL)
|
|
||||||
{
|
|
||||||
Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(obj), __func__);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return type->hash(obj);
|
return type->hash(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ const char* Object_GetName(const Object *obj);
|
|||||||
unsigned int Object_GetSize(const Object *obj, Error *err);
|
unsigned int Object_GetSize(const Object *obj, Error *err);
|
||||||
unsigned int Object_GetDeepSize(const Object *obj, Error *err);
|
unsigned int Object_GetDeepSize(const Object *obj, Error *err);
|
||||||
void *Object_GetBufferAddrAndSize(Object *obj, int *size, Error *error);
|
void *Object_GetBufferAddrAndSize(Object *obj, int *size, Error *error);
|
||||||
int Object_Hash (Object *obj, Error *err);
|
int Object_Hash (Object *obj);
|
||||||
Object* Object_Copy (Object *obj, Heap *heap, 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_Call (Object *obj, Object **argv, unsigned int argc, Heap *heap, Error *err);
|
||||||
void Object_Print (Object *obj, FILE *fp);
|
void Object_Print (Object *obj, FILE *fp);
|
||||||
|
|||||||
@@ -80,6 +80,7 @@
|
|||||||
({'': none});
|
({'': none});
|
||||||
({1: none});
|
({1: none});
|
||||||
({1.0: none});
|
({1.0: none});
|
||||||
|
({none: none});
|
||||||
({true: none});
|
({true: none});
|
||||||
({false: none});
|
({false: none});
|
||||||
({[]: none});
|
({[]: none});
|
||||||
|
|||||||
Reference in New Issue
Block a user