Skip to content

Commit

Permalink
hash-map equality: bash, c, coffee, cs, es6, ...
Browse files Browse the repository at this point in the history
- 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
  • Loading branch information
kanaka committed Nov 17, 2015
1 parent a076db2 commit a0b63ee
Show file tree
Hide file tree
Showing 12 changed files with 106 additions and 21 deletions.
16 changes: 15 additions & 1 deletion bash/types.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
21 changes: 19 additions & 2 deletions c/types.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down
4 changes: 1 addition & 3 deletions coffee/types.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
13 changes: 13 additions & 0 deletions cs/types.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,19 @@ public static bool _equal_Q(MalVal a, MalVal 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;
}
Expand Down
9 changes: 3 additions & 6 deletions es6/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
3 changes: 3 additions & 0 deletions java/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ SOURCES = $(SOURCES_BASE) $(SOURCES_LISP)
all:
mvn install

src/main/mal/%.java:
mvn install

#.PHONY: stats tests $(TESTS)
.PHONY: stats

Expand Down
14 changes: 14 additions & 0 deletions java/src/main/java/mal/types.java
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,20 @@ public static Boolean _equal_Q(MalVal a, MalVal b) {
}
}
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;
}
Expand Down
9 changes: 3 additions & 6 deletions js/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
10 changes: 10 additions & 0 deletions julia/types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
16 changes: 13 additions & 3 deletions make/types.mk
Original file line number Diff line number Diff line change
Expand Up @@ -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))))

Expand Down
10 changes: 10 additions & 0 deletions php/types.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
2 changes: 2 additions & 0 deletions tests/step9_try.mal
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down

0 comments on commit a0b63ee

Please sign in to comment.