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 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;
|
||||
|
||||
+47
-12
@@ -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)
|
||||
|
||||
+18
-2
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user