From 395ba917ab547d536fb8a181fb4215fdb055972a Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=A9mie=20Astor?= Date: Sun, 31 Oct 2021 21:16:52 +0100 Subject: [PATCH] :white_check_mark: Add dict tests --- src/emit/emit.c | 8 ++++++-- src/lib/dict.c | 12 +++++++----- tests/dict/dict.gw | 7 +++++++ tests/dict/dict_lit.gw | 2 ++ tests/dict/dict_lit_nomatch.gw | 2 ++ tests/dict/dict_noleak.gw | 5 +++++ tests/dict/dict_remove.gw | 10 ++++++++++ 7 files changed, 39 insertions(+), 7 deletions(-) create mode 100644 tests/dict/dict.gw create mode 100644 tests/dict/dict_lit.gw create mode 100644 tests/dict/dict_lit_nomatch.gw create mode 100644 tests/dict/dict_noleak.gw create mode 100644 tests/dict/dict_remove.gw diff --git a/src/emit/emit.c b/src/emit/emit.c index 594bdc63..e9c61bd0 100644 --- a/src/emit/emit.c +++ b/src/emit/emit.c @@ -673,16 +673,20 @@ ANN static m_bool emit_prim_dict(const Emitter emit, Exp *data) { const Type val = e->next->type; const Type t = dict_type(emit->gwion, key, val, e->pos); const Instr init = emit_add_instr(emit, dict_ctor_alt); + const Exp next = e->next; + e->next = NULL; struct Exp_ func = { .exp_type = ae_exp_primary, .d = { .prim = { .prim_type = ae_prim_id, .d = { .var = insert_symbol("hash") }} }}; + struct Exp_ call = { .exp_type = ae_exp_call, .d = { .exp_call = { .func = &func, .args = e}}}; + CHECK_BB(traverse_exp(emit->env, &call)); + e->next = next; m_uint count = 0; - CHECK_BB(traverse_exp(emit->env, &func)); do { const Exp next = e->next; const Exp nnext = next->next; next->next = NULL; e->next = NULL; CHECK_BB(emit_exp(emit, e)); - e->next = nnext; + e->next = next; CHECK_BB(emit_exp(emit, next)); next->next = nnext; if(key->size == SZ_INT) { diff --git a/src/lib/dict.c b/src/lib/dict.c index 6a08440a..ba43527e 100644 --- a/src/lib/dict.c +++ b/src/lib/dict.c @@ -66,7 +66,7 @@ static SFUN(mfun_float_h) { } static SFUN(mfun_string_h) { - *(m_int*)RETURN = hash(STRING(MEM(0))); + *(m_int*)RETURN = hash(STRING(*(M_Object*)MEM(0))); } ANN static void clear_oo(const HMap *a, const VM_Shred shred, const HMapInfo *info NUSED, const m_uint idx) { @@ -238,11 +238,11 @@ static INSTR(hmap_iter) { size_t bucket = *(m_uint*)(shred->reg - SZ_INT) % hmap->capacity; const HState *state = (HState*)(hmap->state + sizeof(HState) * bucket); if (state->set) { - const m_bit *data = hmap->data + hinfo->sz * bucket; m_int *const tombstone = (m_int*)(shred->reg - SZ_INT*2); if (state->deleted && *tombstone == -1) { *tombstone = bucket++; } + const m_bit *data = hmap->data + hinfo->sz * bucket; *(m_uint*)(shred->reg - SZ_INT) = bucket; memcpy(REG(0), data, hmap->key_size); shred->reg += hmap->key_size; @@ -341,7 +341,8 @@ static INSTR(hmap_val) { const HMapInfo *hinfo = (HMapInfo*)o->type_ref->nspc->class_data; const m_uint bucket = *(m_uint*)REG(0); const m_bit *new_data = hmap->data + hinfo->sz * bucket; - + HState *const new_state = (HState*)(hmap->state + sizeof(HState) * bucket); + if(new_state->deleted) exit(3); const m_int tombstone = *(m_int*)(shred->reg - SZ_INT); if (tombstone != -1) { m_bit *const old_data = hmap->data + (hmap->key_size + hmap->val_size) * tombstone; @@ -350,7 +351,7 @@ static INSTR(hmap_val) { memcpy(old_state, new_state, sizeof(HState)); memcpy(old_data, new_data, hinfo->sz); new_state->deleted = true; - } + } shred->reg -= SZ_INT*2 - hmap->val_size; memcpy(REG(-hmap->val_size), new_data + hmap->key_size, hmap->val_size); @@ -367,10 +368,11 @@ static INSTR(hmap_remove_clear) { static INSTR(hmap_remove) { const M_Object o = *(M_Object*)(shred->reg - SZ_INT*2); - const HMap *hmap = (HMap*)o->data; + HMap *const hmap = (HMap*)o->data; const HMapInfo *hinfo = (HMapInfo*)o->type_ref->nspc->class_data; const m_uint bucket = *(m_uint*)REG(0); m_bit *data = hmap->data + hinfo->sz * bucket; + hmap->count--; HState *const state = (HState *)(hmap->state + bucket * sizeof(HState)); state->deleted = true; shred->reg -= SZ_INT*3 - hmap->val_size; diff --git a/tests/dict/dict.gw b/tests/dict/dict.gw new file mode 100644 index 00000000..fbdb3b35 --- /dev/null +++ b/tests/dict/dict.gw @@ -0,0 +1,7 @@ +#! [contains] 0 +const Dict:[string, int] d; +0 => d["foo"]; +1 => d["bar"]; +2 => d["baz"]; + +<<< d["foo"] >>>; diff --git a/tests/dict/dict_lit.gw b/tests/dict/dict_lit.gw new file mode 100644 index 00000000..6ccc838c --- /dev/null +++ b/tests/dict/dict_lit.gw @@ -0,0 +1,2 @@ +#! [contains] 0 +<<< { "foo" : 0, "bar" : 1, "baz" : 2 }["foo"] >>>; diff --git a/tests/dict/dict_lit_nomatch.gw b/tests/dict/dict_lit_nomatch.gw new file mode 100644 index 00000000..40bad61e --- /dev/null +++ b/tests/dict/dict_lit_nomatch.gw @@ -0,0 +1,2 @@ +#! [contains] 0 +<<< { "foo" : 0, "bar" : 1, "baz" : 2.2 }["foo"] >>>; diff --git a/tests/dict/dict_noleak.gw b/tests/dict/dict_noleak.gw new file mode 100644 index 00000000..b3fedb69 --- /dev/null +++ b/tests/dict/dict_noleak.gw @@ -0,0 +1,5 @@ +#! ensure no leaks +const Dict:[string, Event] d; +new Object => d["foo"]; +new Object => d["bar"]; +new Object => d["baz"]; diff --git a/tests/dict/dict_remove.gw b/tests/dict/dict_remove.gw new file mode 100644 index 00000000..ddecbcda --- /dev/null +++ b/tests/dict/dict_remove.gw @@ -0,0 +1,10 @@ +#! [contains] InvalidMapAccess +const Dict:[string, int] d; +0 => d["foo"]; +1 => d["bar"]; +2 => d["baz"]; + +#! could be "foo" ~~ d +<<< d.remove("foo") >>>; + +<<< d["foo"] >>>; -- 2.43.0