diff --git a/doc/API.txt b/doc/API.txt index 1dea4f45..98d39908 100644 --- a/doc/API.txt +++ b/doc/API.txt @@ -12,4 +12,7 @@ V0.2.*: * worker_sync takes a 'worker_t' as an additional parameter The interface is similar to dict _get_at, making the API cleaner and more generic. _set_at2(a,i,x) ==> set(*_get_at(a,i),x) + * DICT SET _set_at method has been renamed as _push + Since there is no key, it is a push method, not a _set_at method. + diff --git a/m-dict.h b/m-dict.h index b2bdccae..51a96bc7 100644 --- a/m-dict.h +++ b/m-dict.h @@ -112,8 +112,8 @@ USAGE: DICT_SET_OPLIST(name[, oplist of the key type]) */ #define DICT_SET_OPLIST(...) \ M_IF_NARGS_EQ1(__VA_ARGS__) \ - (DICTI_OPLIST(__VA_ARGS__, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST ), \ - DICTI_OPLIST(__VA_ARGS__ , M_RET_ARG2 (__VA_ARGS__, ) )) + (DICTI_SET_OPLIST(__VA_ARGS__, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST ), \ + DICTI_SET_OPLIST(__VA_ARGS__ , M_RET_ARG2 (__VA_ARGS__, ) )) /* Define a dictionary with the key key_type to the value value_type @@ -286,6 +286,8 @@ M_C(name, _array_list_pair_get)(map->table, i); \ if (M_C(name, _list_pair_empty_p)(*list)) \ continue; \ + /* We need to scan each item and recompute its hash to know \ + if it remains inplace or shall be moved to the upper part.*/ \ M_C(name, _list_pair_it_t) it; \ M_C(name, _list_pair_it)(it, *list); \ while (!M_C(name, _list_pair_end_p)(it)) { \ @@ -296,6 +298,7 @@ M_C(name, _list_pair_t) *new_list = \ M_C(name, _array_list_pair_get)(map->table, i + old_size); \ M_C(name, _list_pair_splice_back)(*new_list, *list, it); \ + /* Splice_back has updated the iterator to the next one */ \ } else { \ M_C(name, _list_pair_next)(it); \ } \ @@ -313,7 +316,7 @@ assert ((old_size % 2) == 0); \ size_t new_size = old_size / 2; \ assert (new_size >= DICTI_INITIAL_SIZE); \ - /* Move all items to the lower part of the dictionnary */ \ + /* Move all items from the upper part to the lower part of the table */ \ /* NOTE: We don't need to recompute the hash to move them! */ \ for(size_t i = new_size; i < old_size; i++) { \ M_C(name, _list_pair_t) *list = \ @@ -324,15 +327,16 @@ M_C(name, _array_list_pair_get)(map->table, i - new_size); \ M_C(name, _list_pair_splice)(*new_list, *list); \ } \ - /* Resize the dictionary */ \ + /* Resize the table of the dictionary */ \ M_C(name, _array_list_pair_resize)(map->table, new_size); \ map->upper_limit = DICTI_UPPER_BOUND(new_size); \ map->lower_limit = DICTI_LOWER_BOUND(new_size); \ } \ \ static inline void \ - M_C(name, _set_at)(dict_t map, key_type const key \ - M_IF(isSet)(, M_DEFERRED_COMMA value_type const value)) \ + M_IF(isSet)(M_C(name, _push), M_C(name, _set_at)) \ + (dict_t map, key_type const key \ + M_IF(isSet)(, M_DEFERRED_COMMA value_type const value)) \ { \ DICTI_CONTRACT(name, map); \ \ @@ -607,8 +611,11 @@ if (b == false || c != ':') { goto exit; } \ b = M_GET_PARSE_STR value_oplist (value, str, &str); \ if (b == false) { goto exit; } \ - M_C(name, _set_at)(dict, key \ - M_IF(isSet)( , M_DEFERRED_COMMA value)); \ + M_IF(isSet)( \ + M_C(name, _push)(dict, key); \ + , \ + M_C(name, _set_at)(dict, key, value); \ + ) \ do { c = *str++; } while (isspace(c)); \ } while (c == ','); \ M_GET_CLEAR key_oplist (key); \ @@ -646,8 +653,11 @@ if (c != ':') { c = 0; break; } \ b = M_GET_IN_STR value_oplist (value, file); \ if (b == false) { c = 0; break; } \ - M_C(name, _set_at)(dict, key \ - M_IF(isSet)( , M_DEFERRED_COMMA value)); \ + M_IF(isSet)( \ + M_C(name, _push)(dict, key); \ + , \ + M_C(name, _set_at)(dict, key, value); \ + ) \ do { c = fgetc(file); } while (isspace(c)); \ } while (c == ','); \ M_GET_CLEAR key_oplist (key); \ @@ -656,6 +666,22 @@ } \ , /* no IN_STR */ ) \ \ + /* TBC: What to do if the container is a set for splice? */ \ + M_IF(isSet)( \ + static inline void \ + M_C(name, _splice)(dict_t d1, dict_t d2) \ + { \ + dict_it_t it; \ + /* NOTE: Despite using set_at, the accessing of the item in d1 \ + is not as random as other uses of the HASH table as d2 \ + uses the same order than d1 */ \ + for (M_C(name, _it)(it, d2); !M_C(name, _end_p)(it); M_C(name, _next)(it)){ \ + const struct M_C(name, _pair_s) *item = M_C(name, _cref)(it); \ + M_C(name, _push)(d1, item->key); \ + } \ + M_C(name, _clean)(d2); \ + } \ + , \ M_IF_METHOD(UPDATE, value_oplist)( \ static inline void \ M_C(name, _splice)(dict_t d1, dict_t d2) \ @@ -675,7 +701,7 @@ } \ M_C(name, _clean)(d2); \ } \ - , /* NO UPDATE */) \ + , /* NO UPDATE */) ) \ \ /* HASH method for dictionnary itself seems hard to implement: \ we have to handle the case where two dictionnaries are structuraly \ @@ -720,6 +746,40 @@ ,M_IF_METHOD(DEL, oplist)(DEL(M_GET_DEL oplist),) \ ) + +/* Define the oplist of a set */ +#define DICTI_SET_OPLIST(name, key_oplist, value_oplist) \ + (INIT(M_C(name, _init)), \ + INIT_SET(M_C(name, _init_set)), \ + SET(M_C(name, _set)), \ + CLEAR(M_C(name, _clear)), \ + INIT_MOVE(M_C(name, _init_move)), \ + MOVE(M_C(name, _move)), \ + SWAP(M_C(name, _swap)), \ + TYPE(M_C(name, _t)), \ + SUBTYPE(struct M_C(name, _pair_s)), \ + PUSH(M_C(name,_push)), \ + IT_TYPE(M_C(name, _it_t)), \ + IT_FIRST(M_C(name,_it)), \ + IT_SET(M_C(name, _it_set)), \ + IT_END_P(M_C(name,_end_p)), \ + IT_LAST_P(M_C(name,_last_p)), \ + IT_NEXT(M_C(name,_next)), \ + IT_REF(M_C(name,_ref)), \ + IT_CREF(M_C(name,_cref)) \ + ,OPLIST(PAIR_OPLIST(key_oplist, value_oplist)) \ + ,M_IF_METHOD_BOTH(GET_STR, key_oplist, value_oplist)(GET_STR(M_C(name, _get_str)),) \ + ,M_IF_METHOD_BOTH(PARSE_STR, key_oplist, value_oplist)(PARSE_STR(M_C(name, _parse_str)),) \ + ,M_IF_METHOD_BOTH(OUT_STR, key_oplist, value_oplist)(OUT_STR(M_C(name, _out_str)),) \ + ,M_IF_METHOD_BOTH(IN_STR, key_oplist, value_oplist)(IN_STR(M_C(name, _in_str)),) \ + ,M_IF_METHOD(EQUAL, value_oplist)(EQUAL(M_C(name, _equal_p)),) \ + ,KEY_OPLIST(key_oplist) \ + ,VALUE_OPLIST(value_oplist) \ + ,M_IF_METHOD(NEW, oplist)(NEW(M_GET_NEW oplist),) \ + ,M_IF_METHOD(REALLOC, oplist)(REALLOC(M_GET_REALLOC oplist),) \ + ,M_IF_METHOD(DEL, oplist)(DEL(M_GET_DEL oplist),) \ + ) + #define DICTI_LOWER_BOUND(s) ((s) <= DICTI_INITIAL_SIZE ? 0 : (s) * 1 / 4) #define DICTI_UPPER_BOUND(s) ((s) * 2 / 3) #define DICTI_INITIAL_SIZE 16 diff --git a/tests/test-mdict.c b/tests/test-mdict.c index 2b0d77a9..2a484495 100644 --- a/tests/test-mdict.c +++ b/tests/test-mdict.c @@ -131,7 +131,7 @@ static void test_set(void) M_LET(set, DICT_SET_OPLIST(dict_setstr, STRING_OPLIST)) { for(int i = 0; i < 100; i++) { string_printf(str, "%d", i); - dict_setstr_set_at(set, str); + dict_setstr_push(set, str); } assert(dict_setstr_size(set) == 100); for(int i = 0; i < 100; i++) {