text: "use strict";
  var atob = require("../util").atob;
  
  /**
   * @alias caching.BloomFilter
   */
  class BloomFilter {
    constructor(rawBF) {
      this.bytes = atob(rawBF.b);
      this.bits = rawBF.m;
      this.hashes = rawBF.h;
      this.creation = new Date().getTime();
    }
  
    contains(element) {
      for (let hash of BloomFilter._getHashes(element, this.bits, this.hashes)) {
        if (!this._isSet(hash)) {
          return false;
        }
      }
      return true;
    }
  
    _isSet(index) {
      var pos = Math.floor(index / 8);
      var bit = 1 << (index % 8);
      //Extract byte as int or NaN if out of range
      var byte = this.bytes.charCodeAt(pos);
      //Bit-wise AND should be non-zero (NaN always yields false)
      return (byte & bit) != 0;
    }
  
    static _getHashes(element, bits, hashes) {
      var hashValues = new Array(this.hashes);
      var hash1 = BloomFilter._murmur3(0, element);
      var hash2 = BloomFilter._murmur3(hash1, element);
      for (let i = 0; i < hashes; i++) {
        hashValues[i] = (hash1 + i * hash2) % bits;
      }
      return hashValues;
    }
  
    static _murmur3(seed, key) {
      var remainder, bytes, h1, h1b, c1, c2, k1, i;
      remainder = key.length & 3;
      bytes = key.length - remainder;
      h1 = seed;
      c1 = 0xcc9e2d51;
      c2 = 0x1b873593;
      i = 0;
  
      while (i < bytes) {
        k1 =
            ((key.charCodeAt(i) & 0xff)) |
            ((key.charCodeAt(++i) & 0xff) << 8) |
            ((key.charCodeAt(++i) & 0xff) << 16) |
            ((key.charCodeAt(++i) & 0xff) << 24);
        ++i;
  
        k1 = ((((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16))) & 0xffffffff;
        k1 = (k1 << 15) | (k1 >>> 17);
        k1 = ((((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16))) & 0xffffffff;
  
        h1 ^= k1;
        h1 = (h1 << 13) | (h1 >>> 19);
        h1b = ((((h1 & 0xffff) * 5) + ((((h1 >>> 16) * 5) & 0xffff) << 16))) & 0xffffffff;
        h1 = (((h1b & 0xffff) + 0x6b64) + ((((h1b >>> 16) + 0xe654) & 0xffff) << 16));
      }
  
      k1 = 0;
  
      switch (remainder) {
        case 3:
          k1 ^= (key.charCodeAt(i + 2) & 0xff) << 16;
        case 2:
          k1 ^= (key.charCodeAt(i + 1) & 0xff) << 8;
        case 1:
          k1 ^= (key.charCodeAt(i) & 0xff);
  
          k1 = (((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16)) & 0xffffffff;
          k1 = (k1 << 15) | (k1 >>> 17);
          k1 = (((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16)) & 0xffffffff;
          h1 ^= k1;
      }
  
      h1 ^= key.length;
  
      h1 ^= h1 >>> 16;
      h1 = (((h1 & 0xffff) * 0x85ebca6b) + ((((h1 >>> 16) * 0x85ebca6b) & 0xffff) << 16)) & 0xffffffff;
      h1 ^= h1 >>> 13;
      h1 = ((((h1 & 0xffff) * 0xc2b2ae35) + ((((h1 >>> 16) * 0xc2b2ae35) & 0xffff) << 16))) & 0xffffffff;
      h1 ^= h1 >>> 16;
  
      return h1 >>> 0;
    }
  
  }
  
  module.exports = BloomFilter;