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
_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
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
}
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;
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
}
}
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;
}
}
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:
all:
mvn install
+src/main/mal/%.java:
+ mvn install
+
#.PHONY: stats tests $(TESTS)
.PHONY: stats
}
}
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;
}
}
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:
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
$(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))))
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;
}
;; 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))