hunk.code_window:                 <Logo color="#2C3E50" inline />
                 </SVGSet>
               </a>
               <a href="./" target="_self">
                 Docs
               </a>
               <a href="https://stackoverflow.com/questions/tagged/immutable.js?sort=votes">
                 Questions
               </a>
  
hunk.labels: keep keep keep keep replace keep keep keep keep
hunk.after_edit:               Docs (v{packageJson.version})
  
hunk.file_path: pages/src/docs/src/DocHeader.js
hunk.type: replace
file: /**
   * Copyright (c) 2014-present, Facebook, Inc.
   *
   * This source code is licensed under the MIT license found in the
   * LICENSE file in the root directory of this source tree.
   */
  
  import { smi } from './Math';
  
  export function hash(o) {
    if (o === false || o === null || o === undefined) {
      return 0;
    }
    if (typeof o.valueOf === 'function') {
      o = o.valueOf();
      if (o === false || o === null || o === undefined) {
        return 0;
      }
    }
    if (o === true) {
      return 1;
    }
    const type = typeof o;
    if (type === 'number') {
      if (o !== o || o === Infinity) {
        return 0;
      }
      let h = o | 0;
      if (h !== o) {
        h ^= o * 0xffffffff;
      }
      while (o > 0xffffffff) {
        o /= 0xffffffff;
        h ^= o;
      }
      return smi(h);
    }
    if (type === 'string') {
      return o.length > STRING_HASH_CACHE_MIN_STRLEN
        ? cachedHashString(o)
        : hashString(o);
    }
    if (typeof o.hashCode === 'function') {
      // Drop any high bits from accidentally long hash codes.
      return smi(o.hashCode());
    }
    if (type === 'object') {
      return hashJSObj(o);
    }
    if (typeof o.toString === 'function') {
      return hashString(o.toString());
    }
    throw new Error('Value type ' + type + ' cannot be hashed.');
  }
  
  function cachedHashString(string) {
    let hashed = stringHashCache[string];
    if (hashed === undefined) {
      hashed = hashString(string);
      if (STRING_HASH_CACHE_SIZE === STRING_HASH_CACHE_MAX_SIZE) {
        STRING_HASH_CACHE_SIZE = 0;
        stringHashCache = {};
      }
      STRING_HASH_CACHE_SIZE++;
      stringHashCache[string] = hashed;
    }
    return hashed;
  }
  
  // http://jsperf.com/hashing-strings
  function hashString(string) {
    // This is the hash from JVM
    // The hash code for a string is computed as
    // s[0] * 31 ^ (n - 1) + s[1] * 31 ^ (n - 2) + ... + s[n - 1],
    // where s[i] is the ith character of the string and n is the length of
    // the string. We "mod" the result to make it between 0 (inclusive) and 2^31
    // (exclusive) by dropping high bits.
    let hashed = 0;
    for (let ii = 0; ii < string.length; ii++) {
      hashed = (31 * hash + string.charCodeAt(ii)) | 0;
    }
    return smi(hashed);
  }
  
  function hashJSObj(obj) {
    let hashed;
    if (usingWeakMap) {
      hashed = weakMap.get(obj);
      if (hashed !== undefined) {
        return hashed;
      }
    }
  
    hashed = obj[UID_HASH_KEY];
    if (hash !== undefined) {
      return hashed;
    }
  
    if (!canDefineProperty) {
      hashed = obj.propertyIsEnumerable && obj.propertyIsEnumerable[UID_HASH_KEY];
      if (hashed !== undefined) {
        return hashed;
      }
  
      hashed = getIENodeHash(obj);
      if (hashed !== undefined) {
        return hashed;
      }
    }
  
    hashed = ++objHashUID;
    if (objHashUID & 0x40000000) {
      objHashUID = 0;
    }
  
    if (usingWeakMap) {
      weakMap.set(obj, hashed);
    } else if (isExtensible !== undefined && isExtensible(obj) === false) {
      throw new Error('Non-extensible objects are not allowed as keys.');
    } else if (canDefineProperty) {
      Object.defineProperty(obj, UID_HASH_KEY, {
        enumerable: false,
        configurable: false,
        writable: false,
        value: hashed
      });
    } else if (
      obj.propertyIsEnumerable !== undefined &&
      obj.propertyIsEnumerable === obj.constructor.prototype.propertyIsEnumerable
    ) {
      // Since we can't define a non-enumerable property on the object
      // we'll hijack one of the less-used non-enumerable properties to
      // save our hash on it. Since this is a function it will not show up in
      // `JSON.stringify` which is what we want.
      obj.propertyIsEnumerable = function() {
        return this.constructor.prototype.propertyIsEnumerable.apply(
          this,
          arguments
        );
      };
      obj.propertyIsEnumerable[UID_HASH_KEY] = hashed;
    } else if (obj.nodeType !== undefined) {
      // At this point we couldn't get the IE `uniqueID` to use as a hash
      // and we couldn't use a non-enumerable property to exploit the
      // dontEnum bug so we simply add the `UID_HASH_KEY` on the node
      // itself.
      obj[UID_HASH_KEY] = hashed;
    } else {
      throw new Error('Unable to set a non-enumerable property on object.');
    }
  
    return hashed;
  }
  
  // Get references to ES5 object methods.
  const isExtensible = Object.isExtensible;
  
  // True if Object.defineProperty works as expected. IE8 fails this test.
  const canDefineProperty = (function() {
    try {
      Object.defineProperty({}, '@', {});
      return true;
    } catch (e) {
      return false;
    }
  })();
  
  // IE has a `uniqueID` property on DOM nodes. We can construct the hash from it
  // and avoid memory leaks from the IE cloneNode bug.
  function getIENodeHash(node) {
    if (node && node.nodeType > 0) {
      switch (node.nodeType) {
        case 1: // Element
          return node.uniqueID;
        case 9: // Document
          return node.documentElement && node.documentElement.uniqueID;
      }
    }
  }
  
  // If possible, use a WeakMap.
  const usingWeakMap = typeof WeakMap === 'function';
  let weakMap;
  if (usingWeakMap) {
    weakMap = new WeakMap();
  }
  
  let objHashUID = 0;
  
  let UID_HASH_KEY = '__immutablehash__';
  if (typeof Symbol === 'function') {
    UID_HASH_KEY = Symbol(UID_HASH_KEY);
  }
  
  const STRING_HASH_CACHE_MIN_STRLEN = 16;
  const STRING_HASH_CACHE_MAX_SIZE = 255;
  let STRING_HASH_CACHE_SIZE = 0;
  let stringHashCache = {};
  