From a0b63ee4771c43b1e9a9bc39bf53b17967411371 Mon Sep 17 00:00:00 2001 From: Joel Martin Date: Mon, 16 Nov 2015 23:28:58 -0600 Subject: [PATCH] hash-map equality: bash, c, coffee, cs, es6, ... - hash-map equality support for bash, c, coffee, cs, es6, java, js, julia, make, php. - also, add another test to catch another hash-map in-equality: same keys, different values --- bash/types.sh | 16 +++++++++++++++- c/types.c | 21 +++++++++++++++++++-- coffee/types.coffee | 4 +--- cs/types.cs | 13 +++++++++++++ es6/types.js | 9 +++------ java/Makefile | 3 +++ java/src/main/java/mal/types.java | 14 ++++++++++++++ js/types.js | 9 +++------ julia/types.jl | 10 ++++++++++ make/types.mk | 16 +++++++++++++--- php/types.php | 10 ++++++++++ tests/step9_try.mal | 2 ++ 12 files changed, 106 insertions(+), 21 deletions(-) diff --git a/bash/types.sh b/bash/types.sh index 02108a73..f171b17c 100644 --- a/bash/types.sh +++ b/bash/types.sh @@ -81,7 +81,7 @@ _equal? () { case "${ot1}" in string|symbol|keyword|number) [[ "${ANON["${1}"]}" == "${ANON["${2}"]}" ]] ;; - list|vector|hash_map) + list|vector) _count "${1}"; local sz1="${r}" _count "${2}"; local sz2="${r}" [[ "${sz1}" == "${sz2}" ]] || return 1 @@ -91,6 +91,20 @@ _equal? () { _equal? "${a1[${i}]}" "${a2[${i}]}" || return 1 done ;; + hash_map) + local hm1="${ANON["${1}"]}" + eval local ks1="\${!${hm1}[@]}" + local hm2="${ANON["${2}"]}" + eval local ks2="\${!${hm2}[@]}" + [[ "${#ks1}" == "${#ks2}" ]] || return 1 + for k in ${ks1}; do + eval v1="\${${hm1}[\"${k}\"]}" + eval v2="\${${hm2}[\"${k}\"]}" + [ "${v1}" ] || return 1 + [ "${v2}" ] || return 1 + _equal? "${v1}" "${v2}" || return 1 + done + ;; *) [[ "${1}" == "${2}" ]] ;; esac diff --git a/c/types.c b/c/types.c index 1602d54e..d99c6cf6 100644 --- a/c/types.c +++ b/c/types.c @@ -268,6 +268,9 @@ MalVal *_apply(MalVal *f, MalVal *args) { int _equal_Q(MalVal *a, MalVal *b) { + GHashTableIter iter; + gpointer key, value; + if (a == NULL || b == NULL) { return FALSE; } // If types are the same or both are sequential then they might be equal @@ -305,8 +308,22 @@ int _equal_Q(MalVal *a, MalVal *b) { } return TRUE; case MAL_HASH_MAP: - _error("_equal_Q does not support hash-maps yet"); - return FALSE; + if (g_hash_table_size(a->val.hash_table) != + g_hash_table_size(b->val.hash_table)) { + return FALSE; + } + g_hash_table_iter_init (&iter, a->val.hash_table); + while (g_hash_table_iter_next (&iter, &key, &value)) { + if (!g_hash_table_contains(b->val.hash_table, key)) { + return FALSE; + } + MalVal *aval = (MalVal *) g_hash_table_lookup(a->val.hash_table, key); + MalVal *bval = (MalVal *) g_hash_table_lookup(b->val.hash_table, key); + if (!_equal_Q(aval, bval)) { + return FALSE; + } + } + return TRUE; case MAL_FUNCTION_C: case MAL_FUNCTION_MAL: return a->val.f0 == b->val.f0; diff --git a/coffee/types.coffee b/coffee/types.coffee index b31c9b9a..20a9cff2 100644 --- a/coffee/types.coffee +++ b/coffee/types.coffee @@ -38,9 +38,7 @@ E._equal_Q = _equal_Q = (a,b) -> bkeys = (key for key of b) return false if akeys.length != bkeys.length for akey,i in akeys - bkey = bkeys[i] - return false if akey != bkey - return false if !_equal_Q(a[akey], b[bkey]) + return false if !_equal_Q(a[akey], b[akey]) true else a == b diff --git a/cs/types.cs b/cs/types.cs index 0ed335f2..21088fd0 100644 --- a/cs/types.cs +++ b/cs/types.cs @@ -58,6 +58,19 @@ namespace Mal { } } return true; + } else if (a is MalHashMap) { + var akeys = ((MalHashMap)a).getValue().Keys; + var bkeys = ((MalHashMap)b).getValue().Keys; + if (akeys.Count != bkeys.Count) { + return false; + } + foreach (var k in akeys) { + if (!_equal_Q(((MalHashMap)a).getValue()[k], + ((MalHashMap)b).getValue()[k])) { + return false; + } + } + return true; } else { return a == b; } diff --git a/es6/types.js b/es6/types.js index 9f5f0ef1..fb579b3c 100644 --- a/es6/types.js +++ b/es6/types.js @@ -34,12 +34,9 @@ export function _equal_Q (a, b) { } return true case 'hash-map': - let akeys = Object.keys(a).sort(), - bkeys = Object.keys(b).sort() - if (akeys.length !== bkeys.length) { return false } - for (let i=0; i hm = (HashMap)a.value; + MalHashMap mhm = ((MalHashMap)a); + HashMap hm = (HashMap)mhm.value; + for (String k : hm.keySet()) { + if (! _equal_Q(((MalVal)((MalHashMap)a).value.get(k)), + ((MalVal)((MalHashMap)b).value.get(k)))) { + return false; + } + } + return true; } else { return a == b; } diff --git a/js/types.js b/js/types.js index 68c3743c..7897f89e 100644 --- a/js/types.js +++ b/js/types.js @@ -43,12 +43,9 @@ function _equal_Q (a, b) { } return true; case 'hash-map': - var akeys = Object.keys(a).sort(), - bkeys = Object.keys(b).sort(); - if (akeys.length !== bkeys.length) { return false; } - for (var i=0; icount() !== $b->count()) { return false; } + $hm1 = $a->getArrayCopy(); + $hm2 = $b->getArrayCopy(); + foreach (array_keys($hm1) as $k) { + if ($hm1[$k] !== $hm2[$k]) { + return false; + } + } + return true; } else { return $a === $b; } diff --git a/tests/step9_try.mal b/tests/step9_try.mal index 1a2c5ed8..4c1d64f1 100644 --- a/tests/step9_try.mal +++ b/tests/step9_try.mal @@ -268,6 +268,8 @@ ;; Testing equality of hash-maps (= {:a 11 :b 22} (hash-map :b 22 :a 11)) ;=>true +(= {:a 11 :b 22} (hash-map :b 23 :a 11)) +;=>false (= {:a 11 :b 22} (hash-map :a 11)) ;=>false (= {:a 11 :b 22} (list :a 11 :b 22)) -- 2.20.1