var hash = require('string-hash');

module.exports = function HashSet() {
    var length = 0,
        self = this,
        map = Object.create(null);

    // defines the length property as read-only
    Object.defineProperty(this, 'length', {
        get: function() {
            return length;
        }
    });

    // defines the values property as read-only
    Object.defineProperty(this, 'values', {
        get: function() {
            var subkeys;
            var values = [];
            var keys = Object.keys(map);
            keys.forEach(function(key) {
                subkeys = Object.keys(map[key]);
                subkeys.forEach(function(subkey) {
                    var arr = map[key][subkey];
                    for (var i = 0; i < arr.length; ++i) {
                        values.push(arr[i]);
                    }
                });
            });

            return values;
        }
    });

    [].forEach.call(arguments, function(v) {
        add(v);
    });

    // exporting public methods
    this.contains = contains;
    this.equals = equals;
    this.add = add;
    this.remove = remove;
    this.isSubSetOf = isSubSetOf;
    this.isSuperSetOf = isSuperSetOf;
    this.unionWith = unionWith;
    this.intersectWith = intersectWith;

    // helper functions
    function contains(val) {
        var type = toString.call(val);
        if (map[type] === undefined)
            return false;

        var key = hash('' + val);
        return map[type][key] !== undefined;
    };

    function add(val) {
        var type = toString.call(val);
        if (map[type] === undefined) {
            map[type] = Object.create(null);
        }

        var key = hash('' + val);
        if (map[type][key] === undefined) {
            map[type][key] = [val];
            length++;
        } else {
            var i = 0;
            var arr = map[type][key];
            for (; i < arr.length; ++i) {
                if (arr[i] === val) return;
            }

            arr.push(val);
            length++;
        }
    };

    function remove(val) {
        var type = toString.call(val);
        if (map[type] === undefined)
            return;

        var key = hash('' + val);
        if (map[type][key] !== undefined) {
            var arr = map[type][key];
            for (var i = 0; i < arr.length; ++i) {
                if (arr[i] === val) {
                    arr[i] = undefined;
                    length--;
                }
            }
        }
    };

    function isSubSetOf(hashset) {
        if (length < 1)
            return true;

        if (hashset.length < 1)
            return false;

        var values = self.values;
        for (var i in values) {
            if (!hashset.contains(values[i]))
                return false;
        }

        return true;
    }

    function isSuperSetOf(hashset) {
        if (hashset.length === 0)
            return true;

        if (this.length < hashset.length)
            return false;

        var values = hashset.values;
        for (var i in values) {
            if (!self.contains(values[i]))
                return false;
        }

        return true;
    }

    function unionWith(hashset) {
        var values = hashset.values;
        values.forEach(function(v) {
            self.add(v);
        });
    }

    function equals(hashset) {
        if (self.length !== hashset.length) return false;

        var values = hashset.values;
        for (var i in values) {
            if (!self.contains(values[i]))
                return false;
        }

        return true;
    };

    function intersectWith(hashset) {
        if (length === 0) return;

        var value;
        var values = self.values;
        for (var i = 0; i < values.length; ++i) {
            value = values[i];
            if (!hashset.contains(value))
                self.remove(value);
        }
    }
}
@@ -91,29 +91,8 @@
  0,%0A
-        self = this,%0A
     
@@ -291,619 +291,8 @@
 );%0A%0A
-    // defines the values property as read-only%0A    Object.defineProperty(this, 'values', %7B%0A        get: function() %7B%0A            var subkeys;%0A            var values = %5B%5D;%0A            var keys = Object.keys(map);%0A            keys.forEach(function(key) %7B%0A                subkeys = Object.keys(map%5Bkey%5D);%0A                subkeys.forEach(function(subkey) %7B%0A                    var arr = map%5Bkey%5D%5Bsubkey%5D;%0A                    for (var i = 0; i %3C arr.length; ++i) %7B%0A                        values.push(arr%5Bi%5D);%0A                    %7D%0A                %7D);%0A            %7D);%0A%0A            return values;%0A        %7D%0A    %7D);%0A%0A
     
@@ -491,16 +491,44 @@
 remove;%0A
+    this.toArray = toArray;%0A
     this
@@ -900,25 +900,24 @@
 fined;%0A    %7D
-;
 %0A%0A    functi
@@ -1435,33 +1435,32 @@
 %0A        %7D%0A    %7D
-;
 %0A%0A    function r
@@ -1887,25 +1887,479 @@
      %7D%0A    %7D
-;
+%0A%0A    function toArray() %7B%0A        var subkeys;%0A        var values = %5B%5D;%0A        var keys = Object.keys(map);%0A%0A        keys.forEach(function(key) %7B%0A            subkeys = Object.keys(map%5Bkey%5D);%0A            subkeys.forEach(function(subkey) %7B%0A                var arr = map%5Bkey%5D%5Bsubkey%5D;%0A                for (var i = 0; i %3C arr.length; ++i) %7B%0A                    values.push(arr%5Bi%5D);%0A                %7D%0A            %7D);%0A        %7D);%0A%0A        return values;%0A    %7D
 %0A%0A    functi
@@ -2509,35 +2509,33 @@
 ar values = 
-self.values
+toArray()
 ;%0A        fo
@@ -2858,38 +2858,41 @@
 alues = hashset.
-values
+toArray()
 ;%0A        for (v
@@ -2918,37 +2918,32 @@
            if (!
-self.
 contains(values%5B
@@ -3071,38 +3071,41 @@
 alues = hashset.
-values
+toArray()
 ;%0A        values
@@ -3139,21 +3139,16 @@
         
-self.
 add(v);%0A
@@ -3209,21 +3209,16 @@
     if (
-self.
 length !
@@ -3280,22 +3280,25 @@
 hashset.
-values
+toArray()
 ;%0A      
@@ -3340,21 +3340,16 @@
    if (!
-self.
 contains
@@ -3428,17 +3428,16 @@
 e;%0A    %7D
-;
 %0A%0A    fu
@@ -3547,19 +3547,17 @@
 s = 
-self.values
+toArray()
 ;%0A  
@@ -3697,13 +3697,8 @@
     
-self.
 remo

replace values property with toArray() method