fx.collections: update iterator semantics

This commit is contained in:
2026-05-28 20:52:40 +01:00
parent 883b0b24b1
commit ff0d40b324
8 changed files with 143 additions and 116 deletions
+115 -68
View File
@@ -1,3 +1,4 @@
#include <assert.h>
#include <fx/collections/hashtable.h>
#include <fx/misc.h>
#include <fx/reflection/property.h>
@@ -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)