/**
* A function for comparing two values and determine whether they're considered
* equal.
*
* @callback equalityCallback
* @param {Any} a -
* The first value to test.
* @param {Any} b -
* The second value to test.
* @return {Boolean} -
* Whether or not the two values are considered equivalent.
* @see Rekord.equals
* @see Rekord.equalsStrict
* @see Rekord.equalsCompare
*/
/**
* A function for comparing two values to determine if one is greater or lesser
* than the other or if they're equal.
*
* ```javascript
* comparisonCallback( a, b ) < 0 // a < b
* comparisonCallback( a, b ) > 0 // a > b
* comparisonCallback( a, b ) == 0 // a == b
* ```
*
* @callback comparisonCallback
* @param {Any} a -
* The first value to test.
* @param {Any} b -
* The second value to test.
* @return {Number} -
* 0 if the two values are considered equal, a negative value if `a` is
* considered less than `b`, and a positive value if `a` is considered
* greater than `b`.
* @see Rekord.compare
* @see Rekord.compareNumbers
*/
function equalsStrict(a, b)
{
return a === b;
}
function equalsCompare(a, b)
{
return compare( a, b ) === 0;
}
function equals(a, b)
{
if (a === b)
{
return true;
}
if (a === null || b === null)
{
return false;
}
if (a !== a && b !== b)
{
return true; // NaN === NaN
}
var at = typeof a;
var bt = typeof b;
var ar = isRegExp(a);
var br = isRegExp(b);
if (at === 'string' && br)
{
return b.test(a);
}
if (bt === 'string' && ar)
{
return a.test(b);
}
if (at !== bt)
{
return false;
}
var aa = isArray(a);
var ba = isArray(b);
if (aa !== ba)
{
return false;
}
if (aa)
{
if (a.length !== b.length)
{
return false;
}
for (var i = 0; i < a.length; i++)
{
if (!equals(a[i], b[i]))
{
return false;
}
}
return true;
}
if (isDate(a))
{
return isDate(b) && equals( a.getTime(), b.getTime() );
}
if (ar)
{
return br && a.toString() === b.toString();
}
if (at === 'object')
{
for (var ap in a)
{
if (ap.charAt(0) !== '$' && !isFunction(a[ap]))
{
if (!(ap in b) || !equals(a[ap], b[ap]))
{
return false;
}
}
}
for (var bp in b)
{
if (bp.charAt(0) !== '$' && !isFunction(b[bp]))
{
if (!(bp in a))
{
return false;
}
}
}
return true;
}
return false;
}
function compareNumbers(a, b)
{
return (a === b ? 0 : (a < b ? -1 : 1));
}
function compare(a, b, nullsFirst)
{
if (a == b) // jshint ignore:line
{
return 0;
}
var av = isValue( a );
var bv = isValue( b );
if (av !== bv)
{
return (av && !nullsFirst) || (bv && nullsFirst) ? -1 : 1;
}
if (isDate(a))
{
a = a.getTime();
}
if (isDate(b))
{
b = b.getTime();
}
if (isNumber(a) && isNumber(b))
{
return compareNumbers(a, b);
}
if (isArray(a) && isArray(b))
{
return compareNumbers(a.length, b.length);
}
if (isBoolean(a) && isBoolean(b))
{
return (a ? -1 : 1);
}
return (a + '').localeCompare(b + '');
}