aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/beam/erl_map.c
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/beam/erl_map.c')
-rw-r--r--erts/emulator/beam/erl_map.c41
1 files changed, 37 insertions, 4 deletions
diff --git a/erts/emulator/beam/erl_map.c b/erts/emulator/beam/erl_map.c
index cca287c753..98023bbb47 100644
--- a/erts/emulator/beam/erl_map.c
+++ b/erts/emulator/beam/erl_map.c
@@ -568,14 +568,14 @@ static Eterm hashmap_from_unsorted_array(ErtsHeapFactory* factory,
while(ix < jx) {
lx = ix;
- while(ix < jx && EQ(CAR(list_val(hxns[ix].val)), CAR(list_val(hxns[lx].val)))) {
+ while(++ix < jx && EQ(CAR(list_val(hxns[ix].val)),
+ CAR(list_val(hxns[lx].val)))) {
if (reject_dupkeys)
return THE_NON_VALUE;
if (hxns[ix].i > hxns[lx].i) {
lx = ix;
}
- ix++;
}
hxns[cx].hx = hxns[lx].hx;
hxns[cx].val = hxns[lx].val;
@@ -679,7 +679,35 @@ static Eterm hashmap_from_chunked_array(ErtsHeapFactory *factory, hxnode_t *hxns
DECLARE_ESTACK(stack);
Eterm res = NIL, *hp = NULL, *nhp;
- ASSERT(n > 1);
+
+ /* if we get here with only one element then
+ * we have eight levels of collisions
+ */
+
+ if (n == 1) {
+ res = hxns[0].val;
+ v = hxns[0].hx;
+ for (d = 7; d > 0; d--) {
+ slot = maskval(v,d);
+ hp = erts_produce_heap(factory, HAMT_NODE_BITMAP_SZ(1), HALLOC_EXTRA);
+ hp[0] = MAP_HEADER_HAMT_NODE_BITMAP(1 << slot);
+ hp[1] = res;
+ res = make_hashmap(hp);
+ }
+
+ slot = maskval(v,0);
+ hp = erts_produce_heap(factory, (is_root ? 3 : 2), 0);
+
+ if (is_root) {
+ hp[0] = MAP_HEADER_HAMT_HEAD_BITMAP(1 << slot);
+ hp[1] = size;
+ hp[2] = res;
+ } else {
+ hp[0] = MAP_HEADER_HAMT_NODE_BITMAP(1 << slot);
+ hp[1] = res;
+ }
+ return make_hashmap(hp);
+ }
/* push initial nodes on the stack,
* this is the starting depth */
@@ -860,7 +888,12 @@ static Eterm hashmap_from_chunked_array(ErtsHeapFactory *factory, hxnode_t *hxns
#undef HALLOC_EXTRA
static int hxnodecmpkey(hxnode_t *a, hxnode_t *b) {
- return CMP_TERM(CAR(list_val(a->val)), CAR(list_val(b->val)));
+ Sint c = CMP_TERM(CAR(list_val(a->val)), CAR(list_val(b->val)));
+#if ERTS_SIZEOF_ETERM <= SIZEOF_INT
+ return c;
+#else
+ return c > 0 ? 1 : (c < 0 ? -1 : 0);
+#endif
}
static int hxnodecmp(hxnode_t *a, hxnode_t *b) {