-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathHashMap.as
174 lines (135 loc) · 3.87 KB
/
HashMap.as
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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
// angelscript dictionaries in sven lag like shit when they have a lot of keys,
// even when not accessing them. They just generate lag without being used somehow.
// So, this is a temporary replacement.
uint64 hash_FNV1a(string key)
{
uint64 hash = 14695981039346656037;
for (uint c = 0; c < key.Length(); c++) {
hash = (hash * 1099511628211) ^ key[c];
}
return hash;
}
class HashMapEntryMapStat {
string key;
MapStat value;
HashMapEntryMapStat() {}
HashMapEntryMapStat(string key, MapStat value) {
this.key = key;
this.value = value;
}
}
// round up to the nearest power of 2
uint32 ceil_pot(uint32 v)
{
// http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
v -= 1;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v += 1;
return v;
}
class HashMapMapStat
{
array<array<HashMapEntryMapStat>> buckets;
HashMapMapStat() {
buckets.resize(1024);
}
HashMapMapStat(int size) {
buckets.resize(size);
}
MapStat@ get(string key) {
return get(key, hash_FNV1a(key));
}
MapStat@ get(string key, uint64 hashedKey) {
int idx = hashedKey % buckets.size();
for (uint i = 0; i < buckets[idx].size(); i++) {
if (buckets[idx][i].key == key) {
return @buckets[idx][i].value;
}
}
MapStat newStat;
put(key, newStat);
return @newStat;
}
array<string> getKeys() {
array<string> allKeys;
for (uint i = 0; i < buckets.size(); i++) {
for (uint k = 0; k < buckets[i].size(); k++) {
allKeys.insertLast(buckets[i][k].key);
}
}
return allKeys;
}
array<HashMapEntryMapStat@> getItems() {
array<HashMapEntryMapStat@> items;
for (uint i = 0; i < buckets.size(); i++) {
for (uint k = 0; k < buckets[i].size(); k++) {
items.insertLast(@buckets[i][k]);
}
}
return items;
}
void put(string key, MapStat value) {
int idx = hash_FNV1a(key) % buckets.size();
for (uint i = 0; i < buckets[idx].size(); i++) {
if (buckets[idx][i].key == key) {
buckets[idx][i].value = value;
return;
}
}
buckets[idx].insertLast(HashMapEntryMapStat(key, value));
}
bool exists(string key) {
int idx = hash_FNV1a(key) % buckets.size();
for (uint i = 0; i < buckets[idx].size(); i++) {
if (buckets[idx][i].key == key) {
return true;
}
}
return false;
}
void clear(int newSize) {
buckets.resize(0);
buckets.resize(newSize);
}
int countItems() {
int total = 0;
for (uint i = 0; i < buckets.size(); i++) {
total += buckets[i].size();
}
return total;
}
// resize to the smallest amount of buckets with low average depth
void resize() {
int targetBucketSize = Math.max(uint(1), ceil_pot(countItems() / 2));
HashMapMapStat newMap(targetBucketSize);
for (uint i = 0; i < buckets.size(); i++) {
for (uint k = 0; k < buckets[i].size(); k++) {
newMap.put(buckets[i][k].key, buckets[i][k].value);
}
}
this.buckets = newMap.buckets;
}
void stats() {
int total_collisions = 0;
float avg_bucket_depth = 0;
int total_filled_buckets = 0;
uint max_bucket_depth = 0;
for (uint i = 0; i < buckets.size(); i++) {
if (buckets[i].size() > 0) {
total_collisions += buckets[i].size()-1;
total_filled_buckets += 1;
avg_bucket_depth += buckets[i].size();
max_bucket_depth = Math.max(max_bucket_depth, buckets[i].size());
}
}
float bucket_filled_percent = float(total_filled_buckets) / buckets.size();
println("Total collisions: " + total_collisions);
println("Buckets filled: " + total_filled_buckets + " / " + buckets.size() + " (" + int(bucket_filled_percent*100) + "%%)");
println("Average bucket depth: " + (avg_bucket_depth / float(total_filled_buckets)));
println("Max bucket depth: " + max_bucket_depth);
}
}