From bf2a04ff66b02e9119bfbb384f5c304ab5feff99 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Fri, 29 Jun 2018 19:41:34 +0200 Subject: [PATCH] Add method _get_at: _get or create an entry. --- m-dict.h | 81 ++++++++++++++++++++++++++++++++++++++++++++++ tests/test-mdict.c | 50 ++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+) diff --git a/m-dict.h b/m-dict.h index 8f77ccf0..24e97f7b 100644 --- a/m-dict.h +++ b/m-dict.h @@ -353,6 +353,35 @@ if (M_UNLIKELY (map->used > map->upper_limit) ) \ M_C(name,_int_resize_up)(map); \ DICTI_CONTRACT(name, map); \ + } \ + \ + static inline value_type * \ + M_C(name, _get_at)(dict_t map, key_type const key) \ + { \ + DICTI_CONTRACT(name, map); \ + \ + size_t hash = M_GET_HASH key_oplist(key); \ + size_t i = hash & (M_C(name, _array_list_pair_size)(map->table) - 1); \ + M_C(name, _list_pair_t) *list_ptr = \ + M_C(name, _array_list_pair_get)(map->table, i); \ + M_C(name, _list_pair_it_t) it; \ + for(M_C(name, _list_pair_it)(it, *list_ptr); \ + !M_C(name, _list_pair_end_p)(it); \ + M_C(name, _list_pair_next)(it)) { \ + M_C(name, _pair_ptr) ref = *M_C(name, _list_pair_ref)(it); \ + M_IF(isStoreHash)(if (ref->hash != hash) continue;, ) \ + if (M_GET_EQUAL key_oplist(ref->key, key)) { \ + return &ref->M_IF(isSet)(key, value); \ + } \ + } \ + M_C(name, _pair_t) *ref = M_C(name, _list_pair_push_new)(*list_ptr);\ + M_IF(isStoreHash)(M_C(name, _pair_set_hash)(*ref, hash);,) \ + M_C(name, _pair_set_key)(*ref, key); \ + map->used ++; \ + if (M_UNLIKELY (map->used > map->upper_limit) ) \ + M_C(name,_int_resize_up)(map); \ + DICTI_CONTRACT(name, map); \ + return &(*ref)->M_IF(isSet)(key, value); \ } \ \ static inline bool \ @@ -956,6 +985,58 @@ typedef enum { M_C(name,_int_resize_up)(dict, newSize, true); \ } \ DICTI_OA_CONTRACT(dict); \ + } \ + \ + static inline value_type * \ + M_C(name,_get_at)(dict_t dict, key_type const key) \ + { \ + DICTI_OA_CONTRACT(dict); \ + /* NOTE: key can not be the representation of empty or deleted */ \ + assert (!oor_equal_p(key, DICTI_OA_EMPTY)); \ + assert (!oor_equal_p(key, DICTI_OA_DELETED)); \ + \ + M_C(name, _pair_t) *const data = dict->data; \ + const size_t mask = dict->mask; \ + size_t p = M_GET_HASH key_oplist (key) & mask; \ + \ + if (M_GET_EQUAL key_oplist (data[p].key, key)) { \ + return &data[p].value; \ + } \ + if (M_UNLIKELY (!oor_equal_p(data[p].key, DICTI_OA_EMPTY) ) ) { \ + size_t delPos = -1; \ + if (oor_equal_p(data[p].key, DICTI_OA_DELETED)) delPos = p; \ + size_t s = 1; \ + do { \ + p = (p + DICTI_OA_PROBING(s)) & mask; \ + if (M_GET_EQUAL key_oplist (data[p].key, key)) { \ + return &data[p].value; \ + } \ + assert (s <= dict->mask); \ + if (oor_equal_p(data[p].key, DICTI_OA_DELETED) && delPos == (size_t)-1) delPos = p; \ + } while (!oor_equal_p(data[p].key, DICTI_OA_EMPTY) ); \ + if (delPos != (size_t) -1) { \ + p = delPos; \ + dict->count_delete --; \ + } \ + } \ + \ + M_GET_INIT_SET key_oplist (data[p].key, key); \ + M_GET_INIT value_oplist (data[p].value); \ + dict->count++; \ + dict->count_delete ++; \ + \ + if (M_UNLIKELY (dict->count_delete >= dict->upper_limit)) { \ + size_t newSize = dict->mask+1; \ + if (dict->count > (dict->mask / 2)) { \ + newSize += newSize; \ + if (M_UNLIKELY (newSize <= dict->mask+1)) { \ + M_MEMORY_FULL((size_t)-1); \ + } \ + } \ + M_C(name,_int_resize_up)(dict, newSize, true); \ + } \ + DICTI_OA_CONTRACT(dict); \ + return &data[p].value; \ } \ \ static inline void \ diff --git a/tests/test-mdict.c b/tests/test-mdict.c index 8dafa997..17ff9dba 100644 --- a/tests/test-mdict.c +++ b/tests/test-mdict.c @@ -133,11 +133,17 @@ static void test_set(void) string_printf(str, "%d", i); dict_setstr_set_at(set, str); } + assert(dict_setstr_size(set) == 100); for(int i = 0; i < 100; i++) { string_printf(str, "%d", i); string_t *p = dict_setstr_get(set, str); + assert (p != NULL); + assert(string_equal_p (*p, str)); + p = dict_setstr_get_at(set, str); + assert (p != NULL); assert(string_equal_p (*p, str)); } + assert(dict_setstr_size(set) == 100); } } @@ -151,6 +157,18 @@ static void test_init(void) dict_str_set_at (d1, str1, str2); } assert (dict_str_size (d1) == 100); + + for(size_t i = 0; i < 100; i++) { + string_printf(str1, "%d", 2*i); + string_printf(str2, "%d", 2*i+1); + string_t *p = dict_str_get (d1, str1); + assert (p != NULL); + assert (string_equal_p(*p, str2)); + p = dict_str_get_at (d1, str1); + assert (p != NULL); + assert (string_equal_p(*p, str2)); + } + dict_str_t d3; dict_str_init_set (d3, d1); assert (dict_str_equal_p (d3, d1)); @@ -193,6 +211,23 @@ static void test_init(void) dict_str_clean (d2); assert (dict_str_size (d2) == 0); + assert (dict_str_size (d1) == 100); + for(size_t i = 100; i < 200; i++) { + string_printf(str1, "%d", 2*i); + string_printf(*dict_str_get_at (d1, str1), "%d", 2*i+1); + } + assert (dict_str_size (d1) == 200); + for(size_t i = 100; i < 200; i++) { + string_printf(str1, "%d", 2*i); + string_printf(str2, "%d", 2*i+1); + string_t *p = dict_str_get (d1, str1); + assert (p != NULL); + assert (string_equal_p(*p, str2)); + p = dict_str_get_at (d1, str1); + assert (p != NULL); + assert (string_equal_p(*p, str2)); + } + //assert (dict_str_hash (d2) != 0); } } @@ -301,6 +336,21 @@ static void test_oa(void) assert (p == NULL); } } + assert(dict_oa_int_size(d) == 50); + + for(size_t i = 1 ; i < 150; i+= 3) + *dict_oa_int_get_at(d, i) = i*i; + assert(dict_oa_int_size(d) == 100); + for(size_t i = 0 ; i < 150; i++) { + int *p = dict_oa_int_get(d, i); + if ((i % 3) != 2) { + assert (p != NULL); + assert (*p == M_ASSIGN_CAST(int, i*i)); + } else { + assert (p == NULL); + } + } + assert(dict_oa_int_size(d) == 100); dict_oa_int_clear(d); }