162 lines
4.4 KiB
JavaScript
162 lines
4.4 KiB
JavaScript
goog.provide("com.cognitect.transit.eq");
|
|
goog.require("com.cognitect.transit.util");
|
|
goog.scope(function() {
|
|
var eq = com.cognitect.transit.eq, util = com.cognitect.transit.util;
|
|
eq.hashCodeProperty = "transit$hashCode$";
|
|
eq.hashCodeCounter = 1;
|
|
eq.equals = function(x, y) {
|
|
if (x == null) {
|
|
return y == null;
|
|
} else if (x === y) {
|
|
return true;
|
|
} else if (typeof x === "object") {
|
|
if (util.isArray(x)) {
|
|
if (util.isArray(y)) {
|
|
if (x.length === y.length) {
|
|
for (var i = 0; i < x.length; i++) {
|
|
if (!eq.equals(x[i], y[i])) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
} else {
|
|
return false;
|
|
}
|
|
} else if (x.com$cognitect$transit$equals) {
|
|
return x.com$cognitect$transit$equals(y);
|
|
} else if (y != null && typeof y === "object") {
|
|
if (y.com$cognitect$transit$equals) {
|
|
return y.com$cognitect$transit$equals(x);
|
|
} else {
|
|
var xklen = 0, yklen = util.objectKeys(y).length;
|
|
for (var p in x) {
|
|
if (!x.hasOwnProperty(p)) {
|
|
continue;
|
|
}
|
|
xklen++;
|
|
if (!y.hasOwnProperty(p)) {
|
|
return false;
|
|
} else {
|
|
if (!eq.equals(x[p], y[p])) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return xklen === yklen;
|
|
}
|
|
} else {
|
|
return false;
|
|
}
|
|
} else {
|
|
return false;
|
|
}
|
|
};
|
|
eq.hashCombine = function(seed, hash) {
|
|
return seed ^ hash + 2654435769 + (seed << 6) + (seed >> 2);
|
|
};
|
|
eq.stringCodeCache = {};
|
|
eq.stringCodeCacheSize = 0;
|
|
eq.STR_CACHE_MAX = 256;
|
|
eq.hashString = function(str) {
|
|
var cached = eq.stringCodeCache[str];
|
|
if (cached != null) {
|
|
return cached;
|
|
}
|
|
var code = 0;
|
|
for (var i = 0; i < str.length; ++i) {
|
|
code = 31 * code + str.charCodeAt(i);
|
|
code %= 4294967296;
|
|
}
|
|
eq.stringCodeCacheSize++;
|
|
if (eq.stringCodeCacheSize >= eq.STR_CACHE_MAX) {
|
|
eq.stringCodeCache = {};
|
|
eq.stringCodeCacheSize = 1;
|
|
}
|
|
eq.stringCodeCache[str] = code;
|
|
return code;
|
|
};
|
|
eq.hashMapLike = function(m) {
|
|
var code = 0;
|
|
if (m.forEach != null) {
|
|
m.forEach(function(val, key, m) {
|
|
code = (code + (eq.hashCode(key) ^ eq.hashCode(val))) % 4503599627370496;
|
|
});
|
|
} else {
|
|
var keys = util.objectKeys(m);
|
|
for (var i = 0; i < keys.length; i++) {
|
|
var key = keys[i];
|
|
var val = m[key];
|
|
code = (code + (eq.hashCode(key) ^ eq.hashCode(val))) % 4503599627370496;
|
|
}
|
|
}
|
|
return code;
|
|
};
|
|
eq.hashArrayLike = function(arr) {
|
|
var code = 0;
|
|
if (util.isArray(arr)) {
|
|
for (var i = 0; i < arr.length; i++) {
|
|
code = eq.hashCombine(code, eq.hashCode(arr[i]));
|
|
}
|
|
} else if (arr.forEach) {
|
|
arr.forEach(function(x, i) {
|
|
code = eq.hashCombine(code, eq.hashCode(x));
|
|
});
|
|
}
|
|
return code;
|
|
};
|
|
eq.hashCode = function(x) {
|
|
if (x == null) {
|
|
return 0;
|
|
} else {
|
|
switch(typeof x) {
|
|
case "number":
|
|
return x;
|
|
break;
|
|
case "boolean":
|
|
return x === true ? 1 : 0;
|
|
break;
|
|
case "string":
|
|
return eq.hashString(x);
|
|
break;
|
|
case "function":
|
|
var code = x[eq.hashCodeProperty];
|
|
if (code) {
|
|
return code;
|
|
} else {
|
|
code = eq.hashCodeCounter;
|
|
if (typeof Object.defineProperty != "undefined") {
|
|
Object.defineProperty(x, eq.hashCodeProperty, {value:code, enumerable:false});
|
|
} else {
|
|
x[eq.hashCodeProperty] = code;
|
|
}
|
|
eq.hashCodeCounter++;
|
|
return code;
|
|
}
|
|
break;
|
|
default:
|
|
if (x instanceof Date) {
|
|
return x.valueOf();
|
|
} else if (util.isArray(x)) {
|
|
return eq.hashArrayLike(x);
|
|
}
|
|
if (x.com$cognitect$transit$hashCode) {
|
|
return x.com$cognitect$transit$hashCode();
|
|
} else {
|
|
return eq.hashMapLike(x);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
};
|
|
eq.extendToEQ = function(obj, opts) {
|
|
obj.com$cognitect$transit$hashCode = opts["hashCode"];
|
|
obj.com$cognitect$transit$equals = opts["equals"];
|
|
return obj;
|
|
};
|
|
});
|
|
|
|
//# sourceMappingURL=com.cognitect.transit.eq.js.map
|