From 7412f91d7da597bcd81dc60135f8876f89fa9775 Mon Sep 17 00:00:00 2001 From: cozis Date: Wed, 9 Mar 2022 13:05:05 +0100 Subject: [PATCH] added hash,copy methods for lists and maps. The hash method is now obligatory --- src/objects/o_list.c | 41 ++++++++++++++++++++++++++++++ src/objects/o_map.c | 59 ++++++++++++++++++++++++++++++++++--------- src/objects/o_none.c | 20 +++++++++++++-- src/objects/objects.c | 11 ++------ src/objects/objects.h | 2 +- tests/test.noja | 1 + 6 files changed, 110 insertions(+), 24 deletions(-) diff --git a/src/objects/o_list.c b/src/objects/o_list.c index c8f2384..f1cb15b 100644 --- a/src/objects/o_list.c +++ b/src/objects/o_list.c @@ -15,11 +15,15 @@ static int count(Object *self); static void print(Object *obj, FILE *fp); 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 Object *copy(Object *self, Heap *heap, Error *err); +static int hash(Object *self); static TypeObject t_list = { .base = (Object) { .type = &t_type, .flags = Object_STATIC }, .name = "list", .size = sizeof (ListObject), + .copy = copy, + .hash = hash, .select = select, .insert = insert, .count = count, @@ -28,6 +32,43 @@ static TypeObject t_list = { .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) { return mapper_size * 2.0 / 3.0; diff --git a/src/objects/o_map.c b/src/objects/o_map.c index 06026b1..7a532f3 100644 --- a/src/objects/o_map.c +++ b/src/objects/o_map.c @@ -16,11 +16,15 @@ static int count(Object *self); static void print(Object *self, FILE *fp); 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 Object *copy(Object *self, Heap *heap, Error *err); +static int hash(Object *self); static TypeObject t_map = { .base = (Object) { .type = &t_type, .flags = Object_STATIC }, .name = "map", .size = sizeof (MapObject), + .copy = copy, + .hash = hash, .select = select, .insert = insert, .count = count, @@ -34,6 +38,46 @@ static inline int calc_capacity(int mapper_size) 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) { // Handle default args. @@ -107,13 +151,9 @@ static Object *select(Object *self, Object *key, Heap *heap, Error *error) MapObject *map = (MapObject*) self; unsigned int mask = map->mapper_size - 1; - unsigned int hash = Object_Hash(key, error); + unsigned int hash = Object_Hash(key); unsigned int pert = hash; - if(error->occurred) - // No hash function. - return 0; - int i = hash & mask; while(1) @@ -181,8 +221,7 @@ static _Bool grow(MapObject *map, Heap *heap, Error *error) // 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 hash = Object_Hash(keys[i]); int mask = new_mapper_size - 1; int pert = hash; @@ -229,13 +268,9 @@ static _Bool insert(Object *self, Object *key, Object *val, Heap *heap, Error *e return 0; unsigned int mask = map->mapper_size - 1; - unsigned int hash = Object_Hash(key, error); + unsigned int hash = Object_Hash(key); unsigned int pert = hash; - if(error->occurred) - // No hash function. - return 0; - int i = hash & mask; while(1) diff --git a/src/objects/o_none.c b/src/objects/o_none.c index 6c36025..d0e0a19 100644 --- a/src/objects/o_none.c +++ b/src/objects/o_none.c @@ -3,12 +3,16 @@ #include "objects.h" 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 = { .base = (Object) { .type = &t_type, .flags = Object_STATIC }, .name = "none", .size = sizeof (Object), + .hash = hash, + .copy = copy, .print = print, .op_eql = op_eql, }; @@ -18,6 +22,19 @@ static Object the_none_object = { .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) { (void) heap; @@ -25,7 +42,6 @@ Object *Object_NewNone(Heap *heap, Error *error) return &the_none_object; } - static void print(Object *obj, FILE *fp) { assert(fp != NULL); diff --git a/src/objects/objects.c b/src/objects/objects.c index 2f3c5ea..675247c 100644 --- a/src/objects/objects.c +++ b/src/objects/objects.c @@ -64,19 +64,12 @@ unsigned int Object_GetDeepSize(const Object *obj, Error *err) return type->deepsize(obj); } -int Object_Hash(Object *obj, Error *err) +int Object_Hash(Object *obj) { assert(obj != NULL); - const TypeObject *type = Object_GetType(obj); assert(type != NULL); - - if(type->hash == NULL) - { - Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(obj), __func__); - return -1; - } - + assert(type->hash != NULL); return type->hash(obj); } diff --git a/src/objects/objects.h b/src/objects/objects.h index 72d9815..bdb36b3 100644 --- a/src/objects/objects.h +++ b/src/objects/objects.h @@ -90,7 +90,7 @@ 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); 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_Call (Object *obj, Object **argv, unsigned int argc, Heap *heap, Error *err); void Object_Print (Object *obj, FILE *fp); diff --git a/tests/test.noja b/tests/test.noja index 5d2d8ba..75e5924 100644 --- a/tests/test.noja +++ b/tests/test.noja @@ -80,6 +80,7 @@ ({'': none}); ({1: none}); ({1.0: none}); + ({none: none}); ({true: none}); ({false: none}); ({[]: none});