Simple HashMap
I’ve implemented HashMapJS, a simple hash map like implementation.
The project is located at github.
Here is the code with the usage examples:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | /* ===================================================================== @license MIT @author Daniel Kwiecinski <daniel.kwiecinski@lambder.com> @copyright 2009 Daniel Kwiecinski. @end ===================================================================== */ var HashMap = function() { this.initialize(); } HashMap.prototype = { hashkey_prefix: "<#HashMapHashkeyPerfix>", hashcode_field: "<#HashMapHashcodeField>", hashmap_instance_id: 0, initialize: function() { this.backing_hash = {}; this.code = 0; this.hashmap_instance_id += 1; this.instance_id = this.hashmap_instance_id; }, hashcodeField: function() { return this.hashcode_field + this.instance_id; }, /* maps value to key returning previous assocciation */ put: function(key, value) { var prev; if (key && value) { var hashCode; if (typeof(key) === "number" || typeof(key) === "string") { hashCode = key; } else { hashCode = key[this.hashcodeField()]; } if (hashCode) { prev = this.backing_hash[hashCode]; } else { this.code += 1; hashCode = this.hashkey_prefix + this.code; key[this.hashcodeField()] = hashCode; } this.backing_hash[hashCode] = value; } return prev; }, /* returns value associated with given key */ get: function(key) { var value; if (key) { var hashCode; if (typeof(key) === "number" || typeof(key) === "string") { hashCode = key; } else { hashCode = key[this.hashcodeField()]; } if (hashCode) { value = this.backing_hash[hashCode]; } } return value; }, /* deletes association by given key. Returns true if the assocciation existed, false otherwise */ del: function(key) { var success = false; if (key) { var hashCode; if (typeof(key) === "number" || typeof(key) === "string") { hashCode = key; } else { hashCode = key[this.hashcodeField()]; } if (hashCode) { var prev = this.backing_hash[hashCode]; this.backing_hash[hashCode] = undefined; if (prev !== undefined) success = true; } } return success; } } /* ===================================================================== usage ===================================================================== */ // creation var my_map = new HashMap(); // insertion var a_key = {}; var a_value = {struct: "structA"}; var b_key = {}; var b_value = {struct: "structB"}; var c_key = {}; var c_value = {struct: "structC"}; my_map.put(a_key, a_value); my_map.put(b_key, b_value); var prev_b = my_map.put(b_key, c_value); // retrieval if(my_map.get(a_key) !== a_value){ throw("fail1") } if(my_map.get(b_key) !== c_value){ throw("fail2") } if(prev_b !== b_value){ throw("fail3") } // deletion var a_existed = my_map.del(a_key); var c_existed = my_map.del(c_key); var a2_existed = my_map.del(a_key); if(a_existed !== true){ throw("fail4") } if(c_existed !== false){ throw("fail5") } if(a2_existed !== false){ throw("fail6") } // primitive types keys var d_value = {struct: "structD"}; my_map.put(1, d_value); if (my_map.get(1) !== d_value) { throw("fail7") } |
The keys and values can be arbitrary javascript objects.
There is no requirements on objects used as keys or values.
The mechanism is trivial. For every key there is generated unique id (per HashMap instance).
That id is injected to the key object under high unlikely to collide field name
That id is then used to keying in the underlying baking standard javascript association object.
Notes:
1. This HashMap implementation is not thread safe.
OK I know javascript is not multithreaded but it can have concurrent activities (e.g. setTimeout)
This is enough to have race conditions.
2. The mentioned high unlikely to collide name is not a problem as log as there is no
massively concurrent activities.
Roadmap:
1. Make the HashMap implementation thread safe by applying The Wallace Variation of Lamport’s bakery algorithm.
http://www.polyglotinc.com/AJAXscratch/Mutex/mutualExclusion.html
Bon Appétit,
Daniel Kwiecinski