-
Notifications
You must be signed in to change notification settings - Fork 38
Expand file tree
/
Copy pathHashMap.js
More file actions
114 lines (100 loc) · 3.25 KB
/
HashMap.js
File metadata and controls
114 lines (100 loc) · 3.25 KB
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
/* Copyright (c) 2012-2022 The ANTLR Project Contributors. All rights reserved.
* Use is of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
import standardEqualsFunction from "../utils/standardEqualsFunction.js";
import standardHashCodeFunction from "../utils/standardHashCodeFunction.js";
let DEFAULT_LOAD_FACTOR = 0.75;
let INITIAL_CAPACITY = 16
export default class HashMap {
constructor(hashFunction, equalsFunction) {
this.buckets = new Array(INITIAL_CAPACITY);
this.threshold = Math.floor(INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);
this.itemCount = 0;
this.hashFunction = hashFunction || standardHashCodeFunction;
this.equalsFunction = equalsFunction || standardEqualsFunction;
}
set(key, value) {
this._expand();
let slot = this._getSlot(key);
let bucket = this.buckets[slot];
if (!bucket) {
bucket = [[key, value]];
this.buckets[slot] = bucket;
this.itemCount++;
return value;
}
let existing = bucket.find(pair => this.equalsFunction(pair[0], key), this);
if(existing) {
let result = existing[1];
existing[1] = value;
return result;
} else {
bucket.push([key, value]);
this.itemCount++;
return value;
}
}
containsKey(key) {
let bucket = this._getBucket(key);
if(!bucket) {
return false;
}
let existing = bucket.find(pair => this.equalsFunction(pair[0], key), this);
return !!existing;
}
get(key) {
let bucket = this._getBucket(key);
if(!bucket) {
return null;
}
let existing = bucket.find(pair => this.equalsFunction(pair[0], key), this);
return existing ? existing[1] : null;
}
entries() {
return this.buckets.filter(b => b != null).flat(1);
}
getKeys() {
return this.entries().map(pair => pair[0]);
}
getValues() {
return this.entries().map(pair => pair[1]);
}
toString() {
let ss = this.entries().map(e => '{' + e[0] + ':' + e[1] + '}');
return '[' + ss.join(", ") + ']';
}
get length() {
return this.itemCount;
}
_getSlot(key) {
let hash = this.hashFunction(key);
return hash & this.buckets.length - 1;
}
_getBucket(key) {
return this.buckets[this._getSlot(key)];
}
_expand() {
if (this.itemCount <= this.threshold) {
return;
}
let old_buckets = this.buckets;
let newCapacity = this.buckets.length * 2;
this.buckets = new Array(newCapacity);
this.threshold = Math.floor(newCapacity * DEFAULT_LOAD_FACTOR);
for (let bucket of old_buckets) {
if (!bucket) {
continue;
}
for (let pair of bucket) {
let slot = this._getSlot(pair[0]);
let newBucket = this.buckets[slot];
if (!newBucket) {
newBucket = [];
this.buckets[slot] = newBucket;
}
newBucket.push(pair);
}
}
}
}