The type-defining-script for CsoGateway.Collections.Hashing is located in file CsoGateway.Collections.Hashing.js

Copy 
// File: CsoGateway.Collections.Hashing.js
// Version: 0.7.1.0
// Author: Pascal Dufresne
// Date: 2008-08-05
// Last update: 2009-05-25
// http://csogateway.codeplex.com
// http://csogateway.metaobjects.ca
// Copyright (C) 2010 Pascal Dufresne


/*
 * Register CsoGateway.Collections namespace. Import CsoGateway.System namespace.
 */
Type.registerNamespace("CsoGateway.Collections");
ImportNamespace(CsoGateway.System);
Copy 
/*
 * CsoGateway.Collections.Hashing is a static class. It contains static utility methods that calculates hash codes. Methods
 * in this class are not in the prototype. They can be called without creating an object with the new operator.
 *
 * Methods                          Description
 * ----------                       -----------------------------------------------------------
 * Hash(Object)                     Return a non-negative Number which is a hash code for the given
 *                                  object. The strategy used to calculated the hash code
 *                                  varies according the the actual Type of the object.
 *
 * HashFromString(String)           Uses and adaptation of Bob Jenkins 'One-at-a-Time' Hash function
 *                                  to compute a hash for the given String.
 */



/*
 * Creates a new CsoGateway.Collections.Hashing. All methods of the Hashing class are static so this
 * constructor should never be called. Exists only for structural integrity of the Hashing class.
 */

CsoGateway.Collections.Hashing = function Hashing()
{
    throw new Error('CsoGateway.Collections.Hashing is a static class. Its constructor should not be called.');
}

/* 
 * Return a non-negative Number which is a hash code for the given object.
 *
 * For most types, the stategy used is to convert the object into a string and using the
 * HashFromString(String) function.
 *
 * -Calculation of hashes by method Hash(Object):
 *
 * -Hashes for objects of type String, Number, Boolean, Function will always return the same
 *  value because these objects are immutable or because their hash is created from a property that cannot
 *  change.    
 *
 * -Hashes for objects of type Date are calculated based on the current value of the object. If the value
 *    changes, the hash will be different even if it is the same object.
 *
 * -Hashes for objects of type Array are calculated, the first time, to be
 *        Hash(a) ^ Hash(z)
 *    where a is the first element of the Array and z is the last. So 2 distinct arrays with the same first
 *    and last elements will return the same hash code. Once the hash is calculated for an Array, the value
 *    is stored in the object itself and future call to the Hash function for this object will return this
 *    stored value. So changing the content of the Array will not change the value returned by the Hash
 *    function.
 *
 * -There is no good way to compute a hash for an arbitrary object of type Object since the name of the
 *    custom properties of the object are not known. Hashes for objects of type Object are calculated, the
 *    first time, to be the bitwise XOR of the results of the calls to this same Hash function for the first
 *    3 properties in the object as returned by the statement for..in on this object.
 *    Once the hash is calculated for an object of type Object, the value is stored in the object itself
 *    and future call to the Hash function on this object will return this stored value.
 *    So adding/removing or changing the value of the properties of the object will not change its hash.
 *
 * -Objects that are not of type String, Number, Boolean, Function, Date, Array or Object
 *    can still be passed to this method if they implement the ICsoHashProvider interface. In this case,
 *    hashes will be calculated to be the bitwise XOR of the results of the Hash function called on each
 *    of the objects returned by the ICsoHashProvider.getCsoHashSource() method.
 *    
 *  If the object is not of type String, Number, Boolean, Function, Date, Array, Object
 *    and does not implement ICsoHashProvider, the hash will be calculated as if the object was of type
 *    Object.
 *
 */


CsoGateway.Collections.Hashing.Hash = function(obj)
{
    AssertArgumentNotNullOrUndefined(obj, 'obj in CsoGateway.Collections.Hashing.Hash');

    with(CsoGateway.Collections.Hashing)
    {
        var hashCode = null;
        var varCount;

        if(obj._csoHashCode != undefined)
        {
            hashCode = obj._csoHashCode;
        }
        else
        {
            switch(Object.getType(obj))
            {
                case String:
                    hashCode = HashFromString(obj)
                    break;
                case Number:
                    hashCode = HashFromString('Number:' + obj.toString());
                    break;
                case Object:
                    hashCode = HashFromString('Object:' + obj.toString());
                    varCount = 0;
                    for(var v in obj)
                    {
                        hashCode ^= Hash(obj[v]);
                        if(++varCount == 3)
                            break;    
                    }
                    obj._csoHashCode = hashCode; //Complex hash. Store for better performance
                    break;
                case Boolean:
                    hashCode = HashFromString((obj ? 'true' : 'false'));
                    break;
                case Array:
                    hashCode = ((obj.length > 0)?(this.Hash(obj[0]) ^ this.Hash(obj[obj.length-1])):HashFromString('Array'));
                    obj._csoHashCode = hashCode; //Complex hash. Store for better performance
                    break;
                case Date:
                    hashCode = this.HashFromString(obj.valueOf().toString());
                    break;
                case Function:
                    hashCode = this.HashFromString('Function:' + obj.name);
                    break;

                default:
                    if(CsoGateway.System.CsoGenerated.isInstanceOfType(obj) &&
                        CsoGateway.Collections.ICsoHashProvider.isImplementedBy(obj))
                    {
                        sources = obj.getCsoHashSource();
                        hashCode = 0;
                        for(var s in sources)
                        {
                            hashCode ^= Hash(sources[s]);
                        }
                        obj._csoHashCode = hashCode;
                    }
                    else
                    {
                        hashCode = HashFromString(obj.toString());
                        varCount = 0;
                        for(var v in obj)
                        {
                            hashCode ^= Hash(obj[v]);
                            if(++varCount == 3)
                                break;    
                        }
                        obj._csoHashCode = hashCode; //Complex hash. Store for better performance
                    }
            }
        }

        return hashCode;
    }
}


/*
 * Uses an adaptation of the Bob Jenkins 'One-at-a-Time' Hash function to calculate a hash for a string.
 * 
 * http://www.burtleburtle.net/bob/hash/doobs.html
 *
 */

CsoGateway.Collections.Hashing.HashFromString = function(stringSource)
{
    AssertArgumentType(stringSource, String, 'stringSource in CsoGateway.Collections.Hashing.HashFromString');

    var hashed = 0;

    for (var i = 0; i < stringSource.length; i++)
    {
        hashed += stringSource.charCodeAt(i);
        hashed += (hashed << 20);
        hashed ^= (hashed >> 12);
    }

    hashed += (hashed << 6);
    hashed ^= (hashed >> 22);
    hashed += (hashed << 30);

    return Math.abs(hashed);
}

CsoGateway.Collections.Hashing.registerClass('CsoGateway.Collections.Hashing', CsoNative, Sys.IDisposable);

/*
 * End of CsoGateway.Collections.Hashing definition
 */