diff --git a/fx.collections/array.c b/fx.collections/array.c index 79f13cd..5f8443f 100644 --- a/fx.collections/array.c +++ b/fx.collections/array.c @@ -17,7 +17,7 @@ struct fx_array_p { }; struct fx_array_iterator_p { - fx_array *_a; + const fx_array *_a; struct fx_array_p *_a_p; /** The index of the current value */ @@ -170,9 +170,7 @@ static fx_value array_get(struct fx_array_p *array, size_t at) return FX_VALUE_EMPTY; } - fx_value result; - fx_value_copy(&result, &array->ar_data[at]); - return result; + return fx_value_copy_return(array->ar_data[at]); } static size_t array_get_size(const struct fx_array_p *array) @@ -373,7 +371,7 @@ static fx_status array_to_string( /*** ITERATOR FUNCTIONS *******************************************************/ -static fx_iterator *iterable_begin(fx_object *obj) +static const fx_iterator *iterable_begin(const fx_object *obj) { fx_array_iterator *it_obj = fx_object_create(FX_TYPE_ARRAY_ITERATOR); struct fx_array_iterator_p *it = fx_object_get_private( @@ -437,7 +435,7 @@ static enum fx_status iterator_erase(fx_iterator *obj) return FX_SUCCESS; } -static fx_value iterator_get_value(const fx_iterator *obj) +static const fx_value *iterator_get_value(const fx_iterator *obj) { struct fx_array_iterator_p *it = fx_object_get_private( obj, @@ -445,10 +443,10 @@ static fx_value iterator_get_value(const fx_iterator *obj) struct fx_array_p *array = it->_a_p; if (it->i >= array->ar_len) { - return FX_VALUE_EMPTY; + return NULL; } - return *it->value; + return it->value; } static enum fx_status iterator_is_valid(const fx_iterator *obj) diff --git a/fx.collections/hashmap.c b/fx.collections/hashmap.c index 06a47d5..f91f615 100644 --- a/fx.collections/hashmap.c +++ b/fx.collections/hashmap.c @@ -32,8 +32,9 @@ struct fx_hashmap_p { struct fx_hashmap_iterator_p { size_t i; fx_hashmap_item item; + fx_value item_value; - fx_hashmap *_h; + const fx_hashmap *_h; struct fx_hashmap_p *_h_p; fx_bst_node *_cbn; fx_queue_entry *_cqe; @@ -420,7 +421,7 @@ bool fx_hashmap_is_empty(const fx_hashmap *hashmap) FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_HASHMAP, hashmap_is_empty, hashmap); } -fx_iterator *fx_hashmap_begin(fx_hashmap *hashmap) +const fx_iterator *fx_hashmap_begin(const fx_hashmap *hashmap) { fx_hashmap_iterator *it_obj = fx_object_create( FX_TYPE_HASHMAP_ITERATOR); @@ -617,12 +618,13 @@ static enum fx_status iterator_erase(fx_iterator *obj) return FX_SUCCESS; } -static fx_value iterator_get_value(const fx_iterator *obj) +static const fx_value *iterator_get_value(const fx_iterator *obj) { struct fx_hashmap_iterator_p *it = fx_object_get_private( obj, FX_TYPE_HASHMAP_ITERATOR); - return FX_POINTER(&it->item); + it->item_value = FX_POINTER(&it->item); + return &it->item_value; } /*** CLASS DEFINITION *********************************************************/ @@ -635,7 +637,6 @@ FX_TYPE_CLASS_BEGIN(fx_hashmap) FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_iterable, FX_TYPE_ITERABLE) FX_INTERFACE_ENTRY(it_begin) = fx_hashmap_begin; - FX_INTERFACE_ENTRY(it_cbegin) = fx_hashmap_cbegin; FX_TYPE_VTABLE_INTERFACE_END(fx_iterable, FX_TYPE_ITERABLE) FX_TYPE_CLASS_END(fx_hashmap) diff --git a/fx.collections/hashtable.c b/fx.collections/hashtable.c index ccb1fb3..8ce5798 100644 --- a/fx.collections/hashtable.c +++ b/fx.collections/hashtable.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -47,8 +48,9 @@ struct fx_hashtable_p { struct fx_hashtable_iterator_p { size_t i; fx_hashtable_item *item; + fx_value item_value; - fx_hashtable *_h; + const fx_hashtable *_h; struct fx_hashtable_p *_h_p; }; @@ -67,12 +69,14 @@ static fx_status convert_key_to_index( } size_t index = hash % table_size, i = 1; - while (table[index].i_item && i < table_size) { + bool index_found = false; + while (table[index].i_item && i <= table_size) { const struct fx_hashtable_item_p *item = fx_object_get_private( table[index].i_item, FX_TYPE_HASHTABLE_ITEM); int cmp = fx_value_compare(&item->i_key, v); if (cmp == 0) { + index_found = true; break; } @@ -80,11 +84,16 @@ static fx_status convert_key_to_index( i++; } + if (!index_found) { + return FX_ERR_NO_ENTRY; + } + + assert(index < table_size); *out_index = index; return FX_SUCCESS; } -static fx_status find_key( +static fx_status allocate_index_for_key( const fx_value *v, struct table_item *table, size_t table_size, @@ -96,15 +105,12 @@ static fx_status find_key( return status; } - bool found = false; - size_t index = hash % table_size, i = 1; - while (table[index].i_item && i < table_size) { - const struct fx_hashtable_item_p *item = fx_object_get_private( - table[index].i_item, - FX_TYPE_HASHTABLE_ITEM); - int cmp = fx_value_compare(&item->i_key, v); - if (cmp == 0) { - found = true; + size_t index = hash % table_size; + bool ok = false; + + for (size_t i = 1; i < table_size; i++) { + if (!table[index].i_item) { + ok = true; break; } @@ -112,10 +118,11 @@ static fx_status find_key( i++; } - if (!found) { - return FX_ERR_NO_ENTRY; + if (!ok) { + return FX_ERR_NO_SPACE; } + assert(index < table_size); *out_index = index; return FX_SUCCESS; } @@ -126,10 +133,9 @@ static fx_status add_item_to_table( size_t table_capacity) { size_t index = 0; - struct fx_hashtable_item_p *item_p = fx_object_get_private( - item, - FX_TYPE_HASHTABLE_ITEM); - fx_status status = convert_key_to_index( + struct fx_hashtable_item_p *item_p + = fx_object_get_private(item, FX_TYPE_HASHTABLE_ITEM); + fx_status status = allocate_index_for_key( &item_p->i_key, table, table_capacity, @@ -231,29 +237,47 @@ static fx_status hashtable_put( if (!FX_OK(status)) { return status; } + + capacity = primes[hashtable->t_max_index]; } size_t index = 0; - status = convert_key_to_index( - key, - hashtable->t_items, - capacity, - &index); - if (!FX_OK(status)) { - return status; - } + do { + status = allocate_index_for_key( + key, + hashtable->t_items, + capacity, + &index); + if (status == FX_ERR_NO_SPACE) { + status = resize_table( + hashtable, + hashtable->t_max_index + 1); + if (!FX_OK(status)) { + return status; + } + + capacity = primes[hashtable->t_max_index]; + continue; + } + + if (!FX_OK(status)) { + return status; + } + + break; + } while (1); fx_hashtable_item *item = fx_object_create(FX_TYPE_HASHTABLE_ITEM); if (!item) { return FX_ERR_NO_MEMORY; } - struct fx_hashtable_item_p *item_p = fx_object_get_private( - item, - FX_TYPE_HASHTABLE_ITEM); + struct fx_hashtable_item_p *item_p + = fx_object_get_private(item, FX_TYPE_HASHTABLE_ITEM); fx_value_copy(&item_p->i_key, key); fx_value_copy(&item_p->i_value, value); + assert(hashtable->t_items[index].i_item == NULL); hashtable->t_items[index].i_item = item; hashtable->t_count++; return FX_SUCCESS; @@ -279,9 +303,8 @@ static const fx_value *hashtable_get( return NULL; } - const struct fx_hashtable_item_p *item_p = fx_object_get_private( - item, - FX_TYPE_HASHTABLE_ITEM); + const struct fx_hashtable_item_p *item_p + = fx_object_get_private(item, FX_TYPE_HASHTABLE_ITEM); return &item_p->i_value; } @@ -295,14 +318,16 @@ static bool hashtable_is_empty(const struct fx_hashtable_p *hashtable) return hashtable->t_count == 0; } -static fx_value hashtable_item_get_key(const struct fx_hashtable_item_p *item) +static const fx_value *hashtable_item_get_key( + const struct fx_hashtable_item_p *item) { - return item->i_key; + return &item->i_key; } -static fx_value hashtable_item_get_value(const struct fx_hashtable_item_p *item) +static const fx_value *hashtable_item_get_value( + const struct fx_hashtable_item_p *item) { - return item->i_value; + return &item->i_value; } /*** PUBLIC FUNCTIONS *********************************************************/ @@ -347,7 +372,7 @@ bool fx_hashtable_is_empty(const fx_hashtable *hashtable) hashtable); } -fx_value fx_hashtable_item_get_key(const fx_hashtable_item *item) +const fx_value *fx_hashtable_item_get_key(const fx_hashtable_item *item) { FX_CLASS_DISPATCH_STATIC_0( FX_TYPE_HASHTABLE_ITEM, @@ -355,7 +380,7 @@ fx_value fx_hashtable_item_get_key(const fx_hashtable_item *item) item); } -fx_value fx_hashtable_item_get_value(const fx_hashtable_item *item) +const fx_value *fx_hashtable_item_get_value(const fx_hashtable_item *item) { FX_CLASS_DISPATCH_STATIC_0( FX_TYPE_HASHTABLE_ITEM, @@ -363,13 +388,12 @@ fx_value fx_hashtable_item_get_value(const fx_hashtable_item *item) item); } -fx_iterator *fx_hashtable_begin(fx_hashtable *hashtable) +const fx_iterator *fx_hashtable_begin(const fx_hashtable *hashtable) { - fx_hashtable_iterator *it_obj = fx_object_create( - FX_TYPE_HASHTABLE_ITERATOR); - struct fx_hashtable_iterator_p *it = fx_object_get_private( - it_obj, - FX_TYPE_HASHTABLE_ITERATOR); + fx_hashtable_iterator *it_obj + = fx_object_create(FX_TYPE_HASHTABLE_ITERATOR); + struct fx_hashtable_iterator_p *it + = fx_object_get_private(it_obj, FX_TYPE_HASHTABLE_ITERATOR); it->_h = hashtable; it->_h_p = fx_object_get_private(hashtable, FX_TYPE_HASHTABLE); @@ -387,6 +411,7 @@ fx_iterator *fx_hashtable_begin(fx_hashtable *hashtable) it->i++; } + it->item_value = FX_VALUE_OBJECT_REF(table[it->i].i_item); return it_obj; } @@ -405,6 +430,30 @@ static void hashtable_init(fx_object *obj, void *priv) static void hashtable_fini(fx_object *obj, void *priv) { struct fx_hashtable_p *map = priv; + + size_t capacity = primes[map->t_max_index]; + size_t nr_destroyed = 0; + for (size_t i = 0; i < capacity; i++) { + if (map->t_items[i].i_item) { + nr_destroyed++; + fx_hashtable_item_unref(map->t_items[i].i_item); + } + } + + free(map->t_items); +} + +static void hashtable_item_fini(fx_object *obj, void *priv) +{ + struct fx_hashtable_item_p *item = priv; + fx_value_unset(&item->i_key); + fx_value_unset(&item->i_value); +} + +static void hashtable_iterator_fini(fx_object *obj, void *priv) +{ + struct fx_hashtable_iterator_p *it = priv; + fx_value_unset(&it->item_value); } static fx_status to_string( @@ -412,9 +461,8 @@ static fx_status to_string( fx_stream *out, const char *format) { - struct fx_hashtable_p *hashtable = fx_object_get_private( - obj->v_object, - FX_TYPE_HASHTABLE); + struct fx_hashtable_p *hashtable + = fx_object_get_private(obj->v_object, FX_TYPE_HASHTABLE); if (!hashtable->t_count) { fx_stream_write_cstr(out, "{}", NULL); @@ -434,9 +482,8 @@ static fx_status to_string( } nr_written++; - struct fx_hashtable_item_p *item_p = fx_object_get_private( - item, - FX_TYPE_HASHTABLE_ITEM); + struct fx_hashtable_item_p *item_p + = fx_object_get_private(item, FX_TYPE_HASHTABLE_ITEM); const char *cstr = NULL; fx_value_get_cstr(&item_p->i_key, &cstr); @@ -487,9 +534,8 @@ static fx_status get_key( return FX_ERR_NOT_SUPPORTED; } - struct fx_hashtable_item_p *item_p = fx_object_get_private( - item, - FX_TYPE_HASHTABLE_ITEM); + struct fx_hashtable_item_p *item_p + = fx_object_get_private(item, FX_TYPE_HASHTABLE_ITEM); fx_value_copy(out, &item_p->i_key); return FX_SUCCESS; @@ -506,9 +552,8 @@ static fx_status get_value( return FX_ERR_NOT_SUPPORTED; } - struct fx_hashtable_item_p *item_p = fx_object_get_private( - item, - FX_TYPE_HASHTABLE_ITEM); + struct fx_hashtable_item_p *item_p + = fx_object_get_private(item, FX_TYPE_HASHTABLE_ITEM); fx_value_copy(out, &item_p->i_value); return FX_SUCCESS; @@ -518,9 +563,10 @@ static fx_status get_value( static enum fx_status iterator_move_next(const fx_iterator *obj) { - struct fx_hashtable_iterator_p *it = fx_object_get_private( - obj, - FX_TYPE_HASHTABLE_ITERATOR); + struct fx_hashtable_iterator_p *it + = fx_object_get_private(obj, FX_TYPE_HASHTABLE_ITERATOR); + + fx_value_unset(&it->item_value); struct table_item *table = it->_h_p->t_items; size_t capacity = primes[it->_h_p->t_max_index]; @@ -533,14 +579,14 @@ static enum fx_status iterator_move_next(const fx_iterator *obj) return FX_ERR_NO_DATA; } + it->item_value = FX_VALUE_OBJECT_REF(table[it->i].i_item); return FX_SUCCESS; } static enum fx_status iterator_erase(fx_iterator *obj) { - struct fx_hashtable_iterator_p *it = fx_object_get_private( - obj, - FX_TYPE_HASHTABLE_ITERATOR); + struct fx_hashtable_iterator_p *it + = fx_object_get_private(obj, FX_TYPE_HASHTABLE_ITERATOR); struct table_item *table = it->_h_p->t_items; size_t capacity = primes[it->_h_p->t_max_index]; @@ -562,19 +608,18 @@ static enum fx_status iterator_erase(fx_iterator *obj) return FX_SUCCESS; } -static fx_value iterator_get_value(const fx_iterator *obj) +static const fx_value *iterator_get_value(const fx_iterator *obj) { - struct fx_hashtable_iterator_p *it = fx_object_get_private( - obj, - FX_TYPE_HASHTABLE_ITERATOR); + struct fx_hashtable_iterator_p *it + = fx_object_get_private(obj, FX_TYPE_HASHTABLE_ITERATOR); struct table_item *table = it->_h_p->t_items; size_t capacity = primes[it->_h_p->t_max_index]; if (table[it->i].i_item) { - return FX_VALUE_OBJECT(table[it->i].i_item); + return &it->item_value; } - return FX_VALUE_EMPTY; + return NULL; } /*** CLASS DEFINITION *********************************************************/ @@ -619,6 +664,7 @@ FX_TYPE_DEFINITION_BEGIN(fx_hashtable_iterator) FX_TYPE_EXTENDS(FX_TYPE_ITERATOR); FX_TYPE_CLASS(fx_hashtable_iterator_class); FX_TYPE_INSTANCE_PRIVATE(struct fx_hashtable_iterator_p); + FX_TYPE_INSTANCE_FINI(hashtable_iterator_fini); FX_TYPE_DEFINITION_END(fx_hashtable_iterator) // ---- fx_hashtable_item DEFINITION @@ -637,4 +683,5 @@ FX_TYPE_DEFINITION_BEGIN(fx_hashtable_item) FX_TYPE_EXTENDS(FX_TYPE_OBJECT); FX_TYPE_CLASS(fx_hashtable_item_class); FX_TYPE_INSTANCE_PRIVATE(struct fx_hashtable_item_p); + FX_TYPE_INSTANCE_FINI(hashtable_item_fini); FX_TYPE_DEFINITION_END(fx_hashtable_item) diff --git a/fx.collections/include/fx/collections/hashmap.h b/fx.collections/include/fx/collections/hashmap.h index 3d7e874..1eafc45 100644 --- a/fx.collections/include/fx/collections/hashmap.h +++ b/fx.collections/include/fx/collections/hashmap.h @@ -83,7 +83,7 @@ FX_API bool fx_hashmap_has_key( FX_API size_t fx_hashmap_get_size(const fx_hashmap *hashmap); FX_API bool fx_hashmap_is_empty(const fx_hashmap *hashmap); -FX_API fx_iterator *fx_hashmap_begin(fx_hashmap *hashmap); +FX_API const fx_iterator *fx_hashmap_begin(const fx_hashmap *hashmap); FX_API const fx_iterator *fx_hashmap_cbegin(const fx_hashmap *hashmap); FX_DECLS_END; diff --git a/fx.collections/include/fx/collections/hashtable.h b/fx.collections/include/fx/collections/hashtable.h index a5ef4a2..0aa7f16 100644 --- a/fx.collections/include/fx/collections/hashtable.h +++ b/fx.collections/include/fx/collections/hashtable.h @@ -45,10 +45,11 @@ FX_API const fx_value *fx_hashtable_get( FX_API size_t fx_hashtable_get_count(const fx_hashtable *hashtable); FX_API bool fx_hashtable_is_empty(const fx_hashtable *hashtable); -FX_API fx_iterator *fx_hashtable_begin(fx_hashtable *hashtable); +FX_API const fx_iterator *fx_hashtable_begin(const fx_hashtable *hashtable); -FX_API fx_value fx_hashtable_item_get_key(const fx_hashtable_item *item); -FX_API fx_value fx_hashtable_item_get_value(const fx_hashtable_item *item); +FX_API const fx_value *fx_hashtable_item_get_key(const fx_hashtable_item *item); +FX_API const fx_value *fx_hashtable_item_get_value( + const fx_hashtable_item *item); FX_DECLS_END; diff --git a/fx.collections/include/fx/collections/list.h b/fx.collections/include/fx/collections/list.h index 6a02ad1..f0e89d6 100644 --- a/fx.collections/include/fx/collections/list.h +++ b/fx.collections/include/fx/collections/list.h @@ -59,8 +59,7 @@ FX_API void fx_list_delete_all(fx_list *q); FX_API void *fx_list_entry_value(const fx_list_entry *entry); -FX_API fx_iterator *fx_list_begin(fx_list *q); -FX_API const fx_iterator *fx_list_cbegin(const fx_list *q); +FX_API const fx_iterator *fx_list_begin(const fx_list *q); FX_DECLS_END; diff --git a/fx.collections/list.c b/fx.collections/list.c index 4a75b65..4efaa10 100644 --- a/fx.collections/list.c +++ b/fx.collections/list.c @@ -23,6 +23,7 @@ struct fx_list_iterator_p { size_t i; void *item; + fx_value item_value; fx_list_entry *entry; }; @@ -401,27 +402,7 @@ void *fx_list_entry_value(const struct fx_list_entry *entry) return entry ? entry->e_data : NULL; } -fx_iterator *fx_list_begin(fx_list *q) -{ - fx_list_iterator *it_obj = fx_object_create(FX_TYPE_LIST_ITERATOR); - struct fx_list_iterator_p *it = fx_object_get_private( - it_obj, - FX_TYPE_LIST_ITERATOR); - - it->_q = q; - it->_q_p = fx_object_get_private(q, FX_TYPE_LIST); - it->_q_entry = fx_queue_first(&it->_q_p->l_queue); - - it->i = 0; - it->entry = fx_unbox(struct fx_list_entry, it->_q_entry, e_entry); - if (it->entry) { - it->item = it->entry->e_data; - } - - return 0; -} - -const fx_iterator *fx_list_cbegin(const fx_list *q) +const fx_iterator *fx_list_begin(const fx_list *q) { fx_list_iterator *it_obj = fx_object_create(FX_TYPE_LIST_ITERATOR); struct fx_list_iterator_p *it = fx_object_get_private( @@ -508,13 +489,14 @@ static enum fx_status iterator_erase(fx_iterator *obj) return FX_SUCCESS; } -static fx_value iterator_get_value(const fx_iterator *obj) +static const fx_value *iterator_get_value(const fx_iterator *obj) { struct fx_list_iterator_p *it = fx_object_get_private( obj, FX_TYPE_LIST_ITERATOR); - return FX_POINTER(it->item); + it->item_value = FX_POINTER(it->item); + return &it->item_value; } /*** CLASS DEFINITION *********************************************************/ @@ -527,7 +509,6 @@ FX_TYPE_CLASS_BEGIN(fx_list) FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_iterable, FX_TYPE_ITERABLE) FX_INTERFACE_ENTRY(it_begin) = fx_list_begin; - FX_INTERFACE_ENTRY(it_cbegin) = fx_list_cbegin; FX_TYPE_VTABLE_INTERFACE_END(fx_iterable, FX_TYPE_ITERABLE) FX_TYPE_CLASS_END(fx_list) diff --git a/fx.collections/test/hashtables.c b/fx.collections/test/hashtables.c index 0034262..75b3643 100644 --- a/fx.collections/test/hashtables.c +++ b/fx.collections/test/hashtables.c @@ -19,13 +19,13 @@ int main(void) printf("no value\n"); } - fx_iterator *it = fx_hashtable_begin(ht); + const fx_iterator *it = fx_hashtable_begin(ht); fx_foreach(val, it) { fx_hashtable_item *item = NULL; - fx_value_get_object(&val, &item); + fx_value_get_object(val, &item); printf("item %p\n", item); - fx_value key, value; + const fx_value *key, *value; key = fx_hashtable_item_get_key(item); value = fx_hashtable_item_get_value(item); @@ -34,10 +34,10 @@ int main(void) fx_foreach(prop_val, prop_it) { fx_property *prop; - fx_value_get_object(&prop_val, &prop); + fx_value_get_object(prop_val, &prop); printf("%s = ", fx_property_get_name(prop)); fx_value value = FX_VALUE_EMPTY; - fx_property_get_value(prop, &val, &value); + fx_property_get_value(prop, val, &value); fx_value_to_string(&value, fx_stdout, NULL); printf("\n"); }