diff options
-rw-r--r-- | erts/emulator/beam/bif.tab | 4 | ||||
-rw-r--r-- | erts/emulator/beam/erl_hashmap.c | 123 |
2 files changed, 126 insertions, 1 deletions
diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab index cf606a9deb..ed85021f8a 100644 --- a/erts/emulator/beam/bif.tab +++ b/erts/emulator/beam/bif.tab @@ -621,9 +621,11 @@ bif hashmap:remove/2 bif hashmap:info/1 bif hashmap:to_list/1 bif hashmap:new/0 -# bif hashmap:keys/1 +bif hashmap:is_key/2 +bif hashmap:keys/1 bif hashmap:size/1 bif erlang:is_hashmap/1 +bif hashmap:values/1 # # Obsolete diff --git a/erts/emulator/beam/erl_hashmap.c b/erts/emulator/beam/erl_hashmap.c index 11d2309fe3..5cb768a3fe 100644 --- a/erts/emulator/beam/erl_hashmap.c +++ b/erts/emulator/beam/erl_hashmap.c @@ -68,6 +68,8 @@ static Eterm hashmap_insert(Process *p, Uint32 hx, Eterm key, Eterm value, Eterm static const Eterm *hashmap_get(Uint32 hx, Eterm key, Eterm node); static Eterm hashmap_delete(Process *p, Uint32 hx, Eterm key, Eterm node); static Eterm hashmap_to_list(Process *p, Eterm map); +static Eterm hashmap_keys(Process *p, Eterm map); +static Eterm hashmap_values(Process *p, Eterm map); static Eterm hashmap_bld_tuple_uint(Uint **hpp, Uint *szp, Uint n, Uint nums[]); /* hashmap:new/0 */ @@ -159,6 +161,38 @@ BIF_RETTYPE is_hashmap_1(BIF_ALIST_1) { BIF_RET(am_false); } +/* hashmap:is_key/2 + */ + +BIF_RETTYPE hashmap_is_key_2(BIF_ALIST_2) { + if (is_hashmap(BIF_ARG_1)) { + Uint32 hx = make_hash2(BIF_ARG_1); + + BIF_RET(hashmap_get(hx, BIF_ARG_1, BIF_ARG_2) ? am_true : am_false); + } + BIF_ERROR(BIF_P, BADARG); +} + +/* hashmap:keys/1 + */ + +BIF_RETTYPE hashmap_keys_1(BIF_ALIST_1) { + if (is_hashmap(BIF_ARG_1)) { + BIF_RET(hashmap_keys(BIF_P, BIF_ARG_1)); + } + BIF_ERROR(BIF_P, BADARG); +} + +/* hashmap:keys/1 + */ + +BIF_RETTYPE hashmap_values_1(BIF_ALIST_1) { + if (is_hashmap(BIF_ARG_1)) { + BIF_RET(hashmap_values(BIF_P, BIF_ARG_1)); + } + BIF_ERROR(BIF_P, BADARG); +} + /* impl. */ static const Eterm *hashmap_get(Uint32 hx, Eterm key, Eterm node) { @@ -750,6 +784,95 @@ static Eterm hashmap_to_list(Process *p, Eterm node) { return res; } +typedef void hashmap_doer(Eterm*, void*); + +static void hashmap_do_foreach(Eterm node, hashmap_doer* fptr, void* farg) { + Eterm *ptr, hdr; + Uint sz; + DECLARE_ESTACK(stack); + + ESTACK_PUSH(stack, node); + do { + node = ESTACK_POP(stack); + switch(primary_tag(node)) { + case TAG_PRIMARY_LIST: + ptr = list_val(node); + (*fptr)(ptr, farg); /* Do! */ + break; + case TAG_PRIMARY_BOXED: + ptr = boxed_val(node); + hdr = *ptr; + ASSERT(is_header(hdr)); + switch(hdr & _HEADER_MAP_SUBTAG_MASK) { + case HAMT_SUBTAG_HEAD_ARRAY: + ptr++; + case HAMT_SUBTAG_NODE_ARRAY: + ptr++; + sz = 16; + while(sz--) { ESTACK_PUSH(stack, ptr[sz]); } + break; + case HAMT_SUBTAG_HEAD_BITMAP: + ptr++; + case HAMT_SUBTAG_NODE_BITMAP: + sz = hashmap_bitcount(MAP_HEADER_VAL(hdr)); + ASSERT(sz < 17); + ptr++; + while(sz--) { ESTACK_PUSH(stack, ptr[sz]); } + break; + default: + erl_exit(1, "bad header\r\n"); + break; + } + } + } while(!ESTACK_ISEMPTY(stack)); + + DESTROY_ESTACK(stack); +} + +typedef struct { + Eterm* hp; + Eterm res; +}hashmap_keys_state; +static void hashmap_keys_doer(Eterm* kv, hashmap_keys_state*); + +static Eterm hashmap_keys(Process* p, Eterm node) { + hashmap_head_t* root; + hashmap_keys_state state; + + root = (hashmap_head_t*) boxed_val(node); + state.hp = HAlloc(p, root->size * 2); + state.res = NIL; + hashmap_do_foreach(node, (hashmap_doer*)hashmap_keys_doer, &state); + return state.res; +} + +static void hashmap_keys_doer(Eterm* kv, hashmap_keys_state* statep) { + statep->res = CONS(statep->hp, CAR(kv), statep->res); + statep->hp += 2; +} + +typedef struct { + Eterm* hp; + Eterm res; +}hashmap_values_state; +static void hashmap_values_doer(Eterm* kv, hashmap_values_state*); + +static Eterm hashmap_values(Process* p, Eterm node) { + hashmap_head_t* root; + hashmap_values_state state; + + root = (hashmap_head_t*) boxed_val(node); + state.hp = HAlloc(p, root->size * 2); + state.res = NIL; + hashmap_do_foreach(node, (hashmap_doer*)hashmap_values_doer, &state); + return state.res; +} + +static void hashmap_values_doer(Eterm* kv, hashmap_values_state* statep) { + statep->res = CONS(statep->hp, CDR(kv), statep->res); + statep->hp += 2; +} + /* hashmap:info/0 */ static Eterm hashmap_info(Process *p, Eterm node) { |