mirror of
https://github.com/kanaka/mal.git
synced 2024-09-11 13:55:55 +03:00
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
This commit is contained in:
parent
a076db29a0
commit
a0b63ee477
@ -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
|
||||
|
21
c/types.c
21
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;
|
||||
|
@ -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
|
||||
|
||||
|
13
cs/types.cs
13
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;
|
||||
}
|
||||
|
@ -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<akeys.length; i++) {
|
||||
if (akeys[i] !== bkeys[i]) { return false }
|
||||
if (! _equal_Q(a.get(akeys[i]), b.get(bkeys[i]))) { return false }
|
||||
if (a.size !== b.size) { return false }
|
||||
for (let k of a.keys()) {
|
||||
if (! _equal_Q(a.get(k), b.get(k))) { return false }
|
||||
}
|
||||
return true
|
||||
default:
|
||||
|
@ -11,6 +11,9 @@ SOURCES = $(SOURCES_BASE) $(SOURCES_LISP)
|
||||
all:
|
||||
mvn install
|
||||
|
||||
src/main/mal/%.java:
|
||||
mvn install
|
||||
|
||||
#.PHONY: stats tests $(TESTS)
|
||||
.PHONY: stats
|
||||
|
||||
|
@ -64,6 +64,20 @@ public class types {
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else if (a instanceof MalHashMap) {
|
||||
if (((MalHashMap)a).value.size() != ((MalHashMap)b).value.size()) {
|
||||
return false;
|
||||
}
|
||||
//HashMap<String,MalVal> hm = (HashMap<String,MalVal>)a.value;
|
||||
MalHashMap mhm = ((MalHashMap)a);
|
||||
HashMap<String,MalVal> hm = (HashMap<String,MalVal>)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;
|
||||
}
|
||||
|
@ -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; i<akeys.length; i++) {
|
||||
if (akeys[i] !== bkeys[i]) { return false; }
|
||||
if (! equal_Q(a[akeys[i]], b[bkeys[i]])) { return false; }
|
||||
if (Object.keys(a).length !== Object.keys(b).length) { return false; }
|
||||
for (var k in a) {
|
||||
if (! _equal_Q(a[k], b[k])) { return false; }
|
||||
}
|
||||
return true;
|
||||
default:
|
||||
|
@ -41,6 +41,16 @@ function equal_Q(a, b)
|
||||
tuple(a...) == tuple(b...)
|
||||
elseif isa(a,AbstractString)
|
||||
a == b
|
||||
elseif isa(a,Dict)
|
||||
if length(a) !== length(b)
|
||||
return false
|
||||
end
|
||||
for (k,v) in a
|
||||
if !equal_Q(v,b[k])
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
else
|
||||
a === b
|
||||
end
|
||||
|
@ -111,16 +111,26 @@ _clone_obj = $(strip \
|
||||
$(eval $(new_obj)_value := $(strip $($(1)_value)))))\
|
||||
$(new_obj))))
|
||||
|
||||
_hash_equal? = $(strip \
|
||||
$(if $(and $(call _EQ,$(foreach v,$(call __get_obj_values,$(1)),$(word 4,$(subst _, ,$(v)))),$(foreach v,$(call __get_obj_values,$(2)),$(word 4,$(subst _, ,$(v))))),\
|
||||
$(call _EQ,$(call _count,$(1)),$(words $(call gmsl_pairmap,_equal?,$(foreach v,$(call __get_obj_values,$(1)),$($(v))),\
|
||||
$(foreach v,$(call __get_obj_values,$(2)),$($(v))))))),\
|
||||
$(__true),))
|
||||
|
||||
_equal? = $(strip \
|
||||
$(foreach ot1,$(call _obj_type,$(1)),$(foreach ot2,$(call _obj_type,$(2)),\
|
||||
$(if $(or $(call _EQ,$(ot1),$(ot2)),\
|
||||
$(and $(call _sequential?,$(1)),$(call _sequential?,$(2)))),\
|
||||
$(if $(or $(call _string?,$(1)),$(call _symbol?,$(1)),$(call _keyword?,$(1)),$(call _number?,$(1))),\
|
||||
$(call _EQ,$($(1)_value),$($(2)_value)),\
|
||||
$(if $(or $(call _vector?,$(1)),$(call _list?,$(1)),$(call _hash_map?,$(1))),\
|
||||
$(if $(call _hash_map?,$(1)),\
|
||||
$(call _hash_equal?,$(1),$(2)),\
|
||||
$(if $(or $(call _vector?,$(1)),$(call _list?,$(1))),\
|
||||
$(if $(and $(call _EQ,$(call _count,$(1)),$(call _count,$(2))),\
|
||||
$(call _EQ,$(call _count,$(1)),$(words $(call gmsl_pairmap,_equal?,$(call __get_obj_values,$(1)),$(call __get_obj_values,$(2)))))),$(__true),),\
|
||||
$(call _EQ,$(1),$(2))))))))
|
||||
$(call _EQ,$(call _count,$(1)),$(words $(call gmsl_pairmap,_equal?,$(call __get_obj_values,$(1)),\
|
||||
$(call __get_obj_values,$(2)))))),\
|
||||
$(__true),),\
|
||||
$(call _EQ,$(1),$(2)))))))))
|
||||
|
||||
_undefined? = $(or $(call _EQ,undefined,$(origin $(1))),$(filter $(__undefined),$($(1))))
|
||||
|
||||
|
@ -27,6 +27,16 @@ function _equal_Q($a, $b) {
|
||||
if (!_equal_Q($a[$i], $b[$i])) { return false; }
|
||||
}
|
||||
return true;
|
||||
} elseif (_hash_map_Q($a)) {
|
||||
if ($a->count() !== $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;
|
||||
}
|
||||
|
@ -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))
|
||||
|
Loading…
Reference in New Issue
Block a user