hashmap: Improve cursor / peek API

- peek functions will now return pointers directly
- cursor access methods can now return an error, if the cursor is already
  at the end

Also rewrote some cursor loops to use the HASHMAP_EACH macro.
This commit is contained in:
Laria 2022-04-11 23:31:20 +02:00
parent f26759b3f0
commit 6add5e47b9
6 changed files with 70 additions and 74 deletions

View file

@ -239,12 +239,12 @@ void
apfl_gc_scope_traverse(struct scope *scope, gc_visitor cb, void *opaque)
{
HASHMAP_EACH(&scope->map, cur) {
struct apfl_string **k;
apfl_hashmap_cursor_peek_key(cur, (void **)&k);
struct apfl_string **k = apfl_hashmap_cursor_peek_key(cur);
assert(k != NULL);
cb(opaque, GC_OBJECT_FROM(*k, GC_TYPE_STRING));
variable *v;
apfl_hashmap_cursor_peek_value(cur, (void **)&v);
variable *v = apfl_hashmap_cursor_peek_value(cur);
assert(v != NULL);
cb(opaque, GC_OBJECT_FROM(*v, GC_TYPE_VAR));
}
}

View file

@ -238,7 +238,7 @@ visit_roots(struct gc *gc, gc_visitor visitor, void *opaque)
{
HASHMAP_EACH(&gc->roots, cur) {
struct gc_object *obj;
apfl_hashmap_cursor_get_key(cur, &obj);
assert(apfl_hashmap_cursor_get_key(cur, &obj));
visitor(opaque, obj);
}

View file

@ -210,28 +210,23 @@ prepare_set_in_bucket(
return true;
}
static bool
peek_in_bucket(const struct apfl_hashmap map, struct apfl_hashmap_bucket *bucket, const void *key, void **value_ptr)
static void *
peek_in_bucket(const struct apfl_hashmap map, struct apfl_hashmap_bucket *bucket, const void *key)
{
size_t i;
if (!find_key_in_bucket(map, bucket, key, &i)) {
return false;
return NULL;
}
if (value_ptr != NULL) {
size_t valsize = map.valsize;
*value_ptr = KVADDR(bucket->values, valsize, i);
}
return true;
return KVADDR(bucket->values, map.valsize, i);
}
static bool
get_in_bucket(const struct apfl_hashmap map, struct apfl_hashmap_bucket *bucket, const void *key, void *value)
{
void *value_ptr;
void *value_ptr = peek_in_bucket(map, bucket, key);
if (!peek_in_bucket(map, bucket, key, &value_ptr)) {
if (value_ptr == NULL) {
return false;
}
@ -329,10 +324,10 @@ apfl_hashmap_delete(struct apfl_hashmap *map, const void *key)
delete_in_bucket(*map, bucket_by_key(*map, key), key);
}
bool
apfl_hashmap_peek(const struct apfl_hashmap *map, const void *key, void **value_ptr)
void *
apfl_hashmap_peek(const struct apfl_hashmap *map, const void *key)
{
return get_in_bucket(*map, bucket_by_key(*map, key), key, value_ptr);
return peek_in_bucket(*map, bucket_by_key(*map, key), key);
}
bool
@ -528,41 +523,47 @@ apfl_hashmap_cursor_next(struct apfl_hashmap_cursor *cursor)
struct apfl_hashmap_bucket *bucket = cursor_get_bucket(cursor); \
\
if (bucket == NULL) { \
return; /* End already reached */ \
return NULL; /* End already reached */ \
} \
\
if (cursor.i >= bucket->len) { \
return; \
return NULL; \
} \
\
size_t size = cursor.map->sizememb; \
\
out = KVADDR(bucket->bucketmemb, size, cursor.i);
return KVADDR(bucket->bucketmemb, size, cursor.i);
void
apfl_hashmap_cursor_peek_key(struct apfl_hashmap_cursor cursor, void **key_ptr)
void *
apfl_hashmap_cursor_peek_key(struct apfl_hashmap_cursor cursor)
{
CURSOR_PEEK(cursor, *key_ptr, keys, keysize)
}
void
apfl_hashmap_cursor_peek_value(struct apfl_hashmap_cursor cursor, void **value_ptr)
void *
apfl_hashmap_cursor_peek_value(struct apfl_hashmap_cursor cursor)
{
CURSOR_PEEK(cursor, *value_ptr, values, valsize)
}
void
bool
apfl_hashmap_cursor_get_key(struct apfl_hashmap_cursor cursor, void *key)
{
void *key_ptr;
apfl_hashmap_cursor_peek_key(cursor, &key_ptr);
void *key_ptr = apfl_hashmap_cursor_peek_key(cursor);
if (key_ptr == NULL) {
return false;
}
copy_key(*cursor.map, key, key_ptr);
return true;
}
void
bool
apfl_hashmap_cursor_get_value(struct apfl_hashmap_cursor cursor, void *value)
{
void *value_ptr;
apfl_hashmap_cursor_peek_value(cursor, &value_ptr);
void *value_ptr = apfl_hashmap_cursor_peek_value(cursor);
if (value_ptr == NULL) {
return false;
}
copy_value(*cursor.map, value, value_ptr);
return true;
}

View file

@ -73,7 +73,7 @@ bool apfl_hashmap_init(
size_t valsize
);
void apfl_hashmap_delete(struct apfl_hashmap *, const void *key);
bool apfl_hashmap_peek(const struct apfl_hashmap *, const void *key, void **value_ptr);
void *apfl_hashmap_peek(const struct apfl_hashmap *, const void *key);
bool apfl_hashmap_get(const struct apfl_hashmap *, const void *key, void *value);
bool apfl_hashmap_set(struct apfl_hashmap *, void *key, void *value);
size_t apfl_hashmap_count(const struct apfl_hashmap);
@ -93,10 +93,14 @@ bool apfl_hashmap_copy(struct apfl_hashmap *dst, struct apfl_hashmap src);
struct apfl_hashmap_cursor apfl_hashmap_get_cursor(struct apfl_hashmap *);
bool apfl_hashmap_cursor_is_end(struct apfl_hashmap_cursor);
void apfl_hashmap_cursor_next(struct apfl_hashmap_cursor *);
void apfl_hashmap_cursor_peek_key(struct apfl_hashmap_cursor, void **key_ptr);
void apfl_hashmap_cursor_peek_value(struct apfl_hashmap_cursor, void **value_ptr);
void apfl_hashmap_cursor_get_key(struct apfl_hashmap_cursor, void *key);
void apfl_hashmap_cursor_get_value(struct apfl_hashmap_cursor, void *value);
// The returned pointer will only be NULL, if the iterator is at the end.
void *apfl_hashmap_cursor_peek_key(struct apfl_hashmap_cursor);
void *apfl_hashmap_cursor_peek_value(struct apfl_hashmap_cursor);
// These will only return false, if the iterator is at the end.
bool apfl_hashmap_cursor_get_key(struct apfl_hashmap_cursor, void *key);
bool apfl_hashmap_cursor_get_value(struct apfl_hashmap_cursor, void *value);
#define HASHMAP_EACH(map_ptr,cur) \
for ( \

View file

@ -1,3 +1,4 @@
#include <assert.h>
#include <string.h>
#include "test.h"
@ -282,15 +283,11 @@ TEST(int2int_iterating, t) {
bool seen_1 = false;
bool seen_0 = false;
for (
struct apfl_hashmap_cursor it = apfl_hashmap_get_cursor(&map);
!apfl_hashmap_cursor_is_end(it);
apfl_hashmap_cursor_next(&it)
) {
HASHMAP_EACH(&map, it) {
int k, v;
apfl_hashmap_cursor_get_key(it, &k);
apfl_hashmap_cursor_get_value(it, &v);
assert(apfl_hashmap_cursor_get_key(it, &k));
assert(apfl_hashmap_cursor_get_value(it, &v));
switch (k) {
ITERATING_SWITCH_CASE(t, 123, seen_123, 456, v)
@ -487,16 +484,12 @@ TEST(str2str_iterating, t) {
bool seen_baz = false;
bool seen_blank = false;
for (
struct apfl_hashmap_cursor it = apfl_hashmap_get_cursor(&map);
!apfl_hashmap_cursor_is_end(it);
apfl_hashmap_cursor_next(&it)
) {
HASHMAP_EACH(&map, it) {
char *k;
char *v;
apfl_hashmap_cursor_get_key(it, &k);
apfl_hashmap_cursor_get_value(it, &v);
assert(apfl_hashmap_cursor_get_key(it, &k));
assert(apfl_hashmap_cursor_get_value(it, &v));
if (strcmp(k, "foo") == 0) {
ITERATING_SEEN_CHECK(t, "foo", seen_foo, "abc", v)

View file

@ -111,14 +111,13 @@ print(unsigned indent, FILE *out, struct apfl_value value, bool skip_first_inden
return;
}
struct apfl_hashmap_cursor cur = apfl_hashmap_get_cursor(&value.dict->map);
apfl_print_indented(first_indent, out, "[\n");
for (; !apfl_hashmap_cursor_is_end(cur); apfl_hashmap_cursor_next(&cur)) {
struct apfl_value *k;
struct apfl_value *v;
apfl_hashmap_cursor_peek_key(cur, (void **)&k);
apfl_hashmap_cursor_peek_value(cur, (void **)&v);
HASHMAP_EACH(&value.dict->map, cur) {
struct apfl_value *k = apfl_hashmap_cursor_peek_key(cur);
assert(k != NULL);
struct apfl_value *v = apfl_hashmap_cursor_peek_value(cur);
assert(v != NULL);
print(indent+1, out, *k, false);
fprintf(out, " -> ");
@ -173,17 +172,15 @@ dict_eq(const apfl_dict a, const apfl_dict b)
return true;
}
struct apfl_hashmap_cursor cur = apfl_hashmap_get_cursor(&a->map);
size_t total = 0;
for (; !apfl_hashmap_cursor_is_end(cur); apfl_hashmap_cursor_next(&cur)) {
struct apfl_value *key;
struct apfl_value *val;
HASHMAP_EACH(&a->map, cur) {
struct apfl_value *key = apfl_hashmap_cursor_peek_key(cur);
assert(key != NULL);
struct apfl_value *val = apfl_hashmap_cursor_peek_value(cur);
assert(val != NULL);
apfl_hashmap_cursor_peek_key(cur, (void **)&key);
apfl_hashmap_cursor_peek_value(cur, (void **)&val);
struct apfl_value *other_val;
if (!apfl_hashmap_peek(&b->map, &key, (void **)&other_val)) {
struct apfl_value *other_val = apfl_hashmap_peek(&b->map, key);
if (other_val == NULL) {
return false;
}
@ -339,10 +336,12 @@ dict_get_for_editing(struct gc *gc, struct dict_header **_dict)
HASHMAP_EACH(&copy.map, cur) {
struct apfl_value *item;
apfl_hashmap_cursor_peek_key(cur, (void **)&item);
item = apfl_hashmap_cursor_peek_key(cur);
assert(item != NULL);
*item = apfl_value_set_cow_flag(*item);
apfl_hashmap_cursor_peek_value(cur, (void **)&item);
item = apfl_hashmap_cursor_peek_value(cur);
assert(item != NULL);
*item = apfl_value_set_cow_flag(*item);
}
@ -522,11 +521,10 @@ void
apfl_gc_dict_traverse(struct dict_header *dict, gc_visitor cb, void *opaque)
{
HASHMAP_EACH(&dict->map, cur) {
struct apfl_value *k;
struct apfl_value *v;
apfl_hashmap_cursor_peek_key(cur, (void **)&k);
apfl_hashmap_cursor_peek_value(cur, (void **)&v);
struct apfl_value *k = apfl_hashmap_cursor_peek_key(cur);
assert(k != NULL);
struct apfl_value *v = apfl_hashmap_cursor_peek_value(cur);
assert(v != NULL);
call_visitor_for_value(cb, opaque, *k);
call_visitor_for_value(cb, opaque, *v);