Updated deepEqual to make it be more accurate

This commit is contained in:
NeeEoo
2024-04-25 12:33:45 +02:00
parent 50e87c504d
commit b7c12943fa
+74 -76
View File
@@ -1,102 +1,100 @@
import hscript.Expr.Error;
import hscript.Printer;
import haxe.Constraints.IMap;
import haxe.EnumTools.EnumValueTools;
using StringTools;
class Util {
// TODO: check this for bugs
static function deepEqual(a:Dynamic, b:Dynamic):Bool {
if (a == b) {
return true;
}
static inline function isNull(a:Dynamic):Bool {
return Type.typeof(a) == TNull;
}
if (a == null || b == null) {
static inline function isFunction(a:Dynamic):Bool {
return Type.typeof(a) == TFunction;
}
// TODO: check this for bugs
// Code from https://github.com/elnabo/equals/blob/master/src/equals/Equal.hx, (MIT License), but updated to work with haxe 4
public static function deepEqual<T> (a:T, b:T) : Bool {
if (a == b) { return true; } // if physical equality
if (isNull(a) || isNull(b)) {
return false;
}
if ((a is String) && (b is String)) {
return a == b;
}
if ((a is Array) && (b is Array)) {
var aArray:Array<Dynamic> = cast a;
var bArray:Array<Dynamic> = cast b;
if (aArray.length != bArray.length) {
return false;
}
for (i in 0...aArray.length) {
if (!deepEqual(aArray[i], bArray[i])) {
switch (Type.typeof(a)) {
case TNull, TInt, TBool, TUnknown:
return a == b;
case TFloat:
return Math.isNaN(cast a) && Math.isNaN(cast b); // only valid true result remaining
case TFunction:
return Reflect.compareMethods(a, b); // only physical equality can be tested for function
case TEnum(_):
if (EnumValueTools.getIndex(cast a) != EnumValueTools.getIndex(cast b)) {
return false;
}
}
var a_args = EnumValueTools.getParameters(cast a);
var b_args = EnumValueTools.getParameters(cast b);
return deepEqual(a_args, b_args);
case TClass(_):
if (Std.isOfType(a, String) && Std.isOfType(b, String)) {
return a == b;
}
if (Std.isOfType(a, Array) && Std.isOfType(b, Array)) {
var a = cast(a, Array<Dynamic>);
var b = cast(b, Array<Dynamic>);
if (a.length != b.length) { return false; }
for (i in 0...a.length) {
if (!deepEqual(a[i], b[i])) {
return false;
}
}
return true;
}
return true;
if (Std.isOfType(a, IMap) && Std.isOfType(b, IMap)) {
var a = cast(a, Map<Dynamic, Dynamic>);
var b = cast(b, Map<Dynamic, Dynamic>);
var a_keys = [ for (key in a.keys()) key ];
var b_keys = [ for (key in b.keys()) key ];
a_keys.sort(Reflect.compare);
b_keys.sort(Reflect.compare);
if (!deepEqual(a_keys, b_keys)) { return false; }
for (key in a_keys) {
if (!deepEqual(a.get(key), b.get(key))) {
return false;
}
}
return true;
}
if (Std.isOfType(a, Date) && Std.isOfType(b, Date)) {
return cast(a, Date).getTime() == cast(b, Date).getTime();
}
if (Std.isOfType(a, haxe.io.Bytes) && Std.isOfType(b, haxe.io.Bytes)) {
return deepEqual(cast(a, haxe.io.Bytes).getData(), cast(b, haxe.io.Bytes).getData());
}
case TObject:
}
if(Std.isOfType(a, Enum) && Std.isOfType(b, Enum)) {
if(Type.enumEq(a, b))
return true;
}
// Check Map Equality
if (Std.isOfType(a, IMap) && Std.isOfType(b, IMap)) {
var aMap:IMap<Dynamic, Dynamic> = cast a;
var bMap:IMap<Dynamic, Dynamic> = cast b;
var aFields = [for(v in aMap.keys()) v];
var bFields = [for(v in bMap.keys()) v];
if (aFields.length != bFields.length) {
return false;
}
// Sort fields to ensure consistent comparison
aFields.sort(Reflect.compare);
bFields.sort(Reflect.compare);
for (key in aMap.keys()) {
if (!bMap.exists(key) || !deepEqual(aMap.get(key), bMap.get(key))) {
for (field in Reflect.fields(a)) {
var pa = Reflect.field(a, field);
var pb = Reflect.field(b, field);
if (isFunction(pa)) {
// ignore function as only physical equality can be tested, unless null
if (isNull(pa) != isNull(pb)) {
return false;
}
continue;
}
return true;
}
if (Reflect.isObject(a) && Reflect.isObject(b)) {
var aFields = Reflect.fields(a);
var bFields = Reflect.fields(b);
if (aFields.length != bFields.length) {
if (!deepEqual(pa, pb)) {
return false;
}
// Sort fields to ensure consistent comparison
aFields.sort(Reflect.compare);
bFields.sort(Reflect.compare);
for (i in 0...aFields.length) {
var field = aFields[i];
if (field != bFields[i] || !deepEqual(Reflect.field(a, field), Reflect.field(b, field))) {
return false;
}
}
return true;
}
if(!Type.enumEq(Type.typeof(a), Type.typeof(b))) {
if(Type.typeof(a) == TInt && Type.typeof(b) == TFloat) {
return cast(a, Int) == cast(b, Float);
}
if(Type.typeof(a) == TFloat && Type.typeof(b) == TInt) {
return cast(a, Float) == cast(b, Int);
}
}
return false;
return true;
}