Libraryless. Click here for Pure Java version (3053L/19K).
1 | /* |
2 | * #! |
3 | * loosely based on code from the Ontopia Engine |
4 | * #- |
5 | * Copyright (C) 2001 - 2013 The Ontopia Project |
6 | * #- |
7 | * Licensed under the Apache License, Version 2.0 (the "License"); |
8 | * you may not use this file except in compliance with the License. |
9 | * You may obtain a copy of the License at |
10 | * |
11 | * http://www.apache.org/licenses/LICENSE-2.0 |
12 | * |
13 | * Unless required by applicable law or agreed to in writing, software |
14 | * distributed under the License is distributed on an "AS IS" BASIS, |
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16 | * See the License for the specific language governing permissions and |
17 | * limitations under the License. |
18 | * !# |
19 | */ |
20 | |
21 | // Note: Long.MIN_VALUE and Long.MIN_VALUE+1 are not allowed as keys |
22 | sclass LongIntHashMap_IntMemory extends AbstractMap<Long, Int> { |
23 | final static int INITIAL_SIZE = 3; |
24 | final static double LOAD_FACTOR = 0.6; |
25 | |
26 | /** |
27 | * When a key is deleted this object is put into the hashtable in |
28 | * its place, so that other entries with the same key (collisions) |
29 | * further down the hashtable are not lost after we delete an object |
30 | * in the collision chain. |
31 | */ |
32 | final static long noKey = Long.MIN_VALUE; // null in original code |
33 | final static long deletedKey = Long.MIN_VALUE+1; |
34 | |
35 | IIntMemory mem; |
36 | |
37 | // memory layout: |
38 | // tableSize at 0 |
39 | // elements at 1 |
40 | // freecells at 2 |
41 | // table starts at 3 (long key, int value, ...) |
42 | |
43 | int tableSize; |
44 | int elements; |
45 | int freecells; |
46 | int modCount; |
47 | |
48 | // load existing map |
49 | *(IIntMemory *mem) { |
50 | tableSize = mem.get(0); |
51 | elements = mem.get(1); |
52 | freecells = mem.get(2); |
53 | } |
54 | |
55 | // make new map |
56 | *(IIntMemory *mem, int capacity) { |
57 | int tsize = iceil_safe(capacity/LOAD_FACTOR); |
58 | mem.ensureSize(toInt(3+tsize*3L)); |
59 | setTableSize(tsize); |
60 | setElements(0); |
61 | setFreecells(tsize); |
62 | for i to tableSize: |
63 | setKey(i, noKey); |
64 | } |
65 | |
66 | void setTableSize(int tableSize) { |
67 | mem.set(0, this.tableSize = tableSize); |
68 | } |
69 | |
70 | void setElements(int elements) { |
71 | mem.set(1, this.elements = elements); |
72 | } |
73 | |
74 | void setFreecells(int freecells) { |
75 | mem.set(2, this.freecells = freecells); |
76 | } |
77 | |
78 | // ===== MAP IMPLEMENTATION ============================================= |
79 | |
80 | public synchronized int size() { ret elements; } |
81 | public synchronized boolean isEmpty() { ret elements == 0; } |
82 | |
83 | public synchronized void clear() { |
84 | setElements(0); |
85 | for ix to tableSize: { |
86 | setKey(ix, noKey); |
87 | setValue(ix, 0); // just for beauty |
88 | } |
89 | setFreecells(tableSize); |
90 | modCount++; |
91 | } |
92 | |
93 | int ptr(int i) { ret 3+i*3; } |
94 | |
95 | void setKey(int i, long key) { |
96 | mem.setLong(ptr(i), key); |
97 | } |
98 | |
99 | void setValue(int i, int val) { |
100 | mem.set(ptr(i)+2, val); |
101 | } |
102 | |
103 | long getKey(int i) { |
104 | ret mem.getLong(ptr(i)); |
105 | } |
106 | |
107 | int getValue(int i) { |
108 | ret mem.get(ptr(i)+2); |
109 | } |
110 | |
111 | public synchronized bool containsKey(Object k) { |
112 | return getKey(findKeyIndex((Long) k)) != noKey; |
113 | } |
114 | |
115 | public synchronized Set<Entry<Long, Int>> entrySet() { |
116 | throw new UnsupportedOperationException(); |
117 | } |
118 | |
119 | public synchronized Int remove(Object k) { |
120 | int index = findKeyIndex((Long) k); |
121 | |
122 | // we found the right position, now do the removal |
123 | if (getKey(index) != noKey) { |
124 | // we found the object |
125 | |
126 | // same problem here as with put |
127 | int v = getValue(index); |
128 | setKey(index, deletedKey); |
129 | setValue(index, 0); |
130 | modCount++; |
131 | setElements(elements-1); |
132 | ret v; |
133 | } |
134 | |
135 | // we did not find the key |
136 | null; |
137 | } |
138 | |
139 | public synchronized Int put(Long k, Int v) { |
140 | int hash = k.hashCode(); |
141 | int index = (hash & 0x7FFFFFFF) % tableSize; |
142 | int offset = 1; |
143 | int deletedix = -1; |
144 | |
145 | // search for the key (continue while !null and !this key) |
146 | while (getKey(index) != noKey && getKey(index) != k) { |
147 | |
148 | // if there's a deleted mapping here we can put this mapping here, |
149 | // provided it's not in here somewhere else already |
150 | if (getKey(index) == deletedKey) |
151 | deletedix = index; |
152 | |
153 | index = ((index + offset) & 0x7FFFFFFF) % tableSize; |
154 | offset = offset*2 + 1; |
155 | |
156 | if (offset == -1) |
157 | offset = 2; |
158 | } |
159 | |
160 | if (getKey(index) == noKey) { // wasn't present already |
161 | if (deletedix != -1) // reusing a deleted cell |
162 | index = deletedix; |
163 | else |
164 | setFreecells(freecells-1); |
165 | |
166 | modCount++; |
167 | setElements(elements+1); |
168 | |
169 | setKey(index, k); |
170 | setValue(index, v); |
171 | |
172 | // rehash with increased capacity |
173 | if (1 - (freecells / (double) tableSize) > LOAD_FACTOR) |
174 | rehash(tableSize*2 + 1); |
175 | null; |
176 | } else { // was there already |
177 | modCount++; |
178 | int oldv = getValue(index); |
179 | setValue(index, v); |
180 | ret oldv; |
181 | } |
182 | } |
183 | |
184 | /** |
185 | * INTERNAL: Rehashes the hashmap to a bigger size. |
186 | */ |
187 | void rehash(int newCapacity) { |
188 | fail("rehash not implemented"); |
189 | } |
190 | |
191 | public synchronized Int get(Object k) { |
192 | int i = findKeyIndex((Long) k); |
193 | ret getKey(i) == noKey ? null : getValue(i); |
194 | } |
195 | |
196 | public synchronized Collection<Int> values() { |
197 | return new ValueCollection(); |
198 | } |
199 | |
200 | /** |
201 | * Returns a virtual read-only set of all the keys in the map. |
202 | */ |
203 | public synchronized Set<Long> keySet() { |
204 | return new KeySet(); |
205 | } |
206 | |
207 | // --- Internal utilities |
208 | |
209 | final int findKeyIndex(long k) { |
210 | int hash = Long.hashCode(k); |
211 | int index = (hash & 0x7FFFFFFF) % tableSize; |
212 | int offset = 1; |
213 | |
214 | // search for the key (continue while !null and !this key) |
215 | while (getKey(index) != noKey && getKey(index) != k) { |
216 | index = ((index + offset) & 0x7FFFFFFF) % tableSize; |
217 | offset = offset*2 + 1; |
218 | |
219 | if (offset == -1) |
220 | offset = 2; |
221 | } |
222 | ret index; |
223 | } |
224 | |
225 | class KeySet extends AbstractSet<Long> { |
226 | public synchronized int size() { |
227 | return elements; |
228 | } |
229 | |
230 | public synchronized boolean contains(Object k) { |
231 | return containsKey(k); |
232 | } |
233 | |
234 | public synchronized Iterator<Long> iterator() { |
235 | return new KeyIterator(); |
236 | } |
237 | } |
238 | |
239 | class KeyIterator implements Iterator<Long> { |
240 | private int ix; |
241 | |
242 | private KeyIterator() { |
243 | // walk up to first value, so that hasNext() and next() return |
244 | // correct results |
245 | for (; ix < tableSize; ix++) |
246 | if (getKey(ix) != noKey && getKey(ix) != deletedKey) |
247 | break; |
248 | } |
249 | |
250 | public synchronized boolean hasNext() { |
251 | return ix < tableSize; |
252 | } |
253 | |
254 | public synchronized void remove() { |
255 | throw new UnsupportedOperationException("Collection is read-only"); |
256 | } |
257 | |
258 | public synchronized Long next() { |
259 | if (ix >= tableSize) |
260 | throw new NoSuchElementException(); |
261 | long key = getKey(ix++); |
262 | |
263 | // walk up to next value |
264 | for (; ix < tableSize; ix++) |
265 | if (getKey(ix) != noKey && getKey(ix) != deletedKey) |
266 | break; |
267 | |
268 | // ix now either points to next key, or outside array (if no next) |
269 | ret key; |
270 | } |
271 | } |
272 | |
273 | // --- Value collection |
274 | |
275 | class ValueCollection extends AbstractCollection<Int> { |
276 | public synchronized int size() { |
277 | return elements; |
278 | } |
279 | |
280 | public synchronized Iterator<Int> iterator() { |
281 | return new ValueIterator(); |
282 | } |
283 | |
284 | public synchronized boolean contains(Object v) { |
285 | return containsValue(v); |
286 | } |
287 | } |
288 | |
289 | class ValueIterator implements Iterator<Int> { |
290 | private int ix; |
291 | |
292 | private ValueIterator() { |
293 | // walk up to first value, so that hasNext() and next() return |
294 | // correct results |
295 | for (; ix < tableSize; ix++) |
296 | if (getKey(ix) != noKey && getKey(ix) != deletedKey) |
297 | break; |
298 | } |
299 | |
300 | public synchronized boolean hasNext() { |
301 | return ix < tableSize; |
302 | } |
303 | |
304 | public synchronized void remove() { |
305 | throw new UnsupportedOperationException("Collection is read-only"); |
306 | } |
307 | |
308 | public synchronized Int next() { |
309 | if (ix >= tableSize) |
310 | throw new NoSuchElementException(); |
311 | int value = getValue(ix++); |
312 | |
313 | // walk up to next value |
314 | for (; ix < tableSize; ix++) |
315 | if (getKey(ix) != noKey && getKey(ix) != deletedKey) |
316 | break; |
317 | |
318 | // ix now either points to next value, or outside array (if no next) |
319 | return value; |
320 | } |
321 | } |
322 | } |
Began life as a copy of #1029374
download show line numbers debug dex old transpilations
Travelled to 7 computer(s): bhatertpkbcr, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, tvejysmllsmz, vouqrxazstgt, xrpafgyirdlv
No comments. add comment
Snippet ID: | #1029376 |
Snippet name: | LongIntHashMap_IntMemory [dev.] - long to int HashMap that works on disk |
Eternal ID of this version: | #1029376/13 |
Text MD5: | ccda07b372ce1503204ed6e42d75e761 |
Transpilation MD5: | f5bd477c5067be2553a229707b260b14 |
Author: | stefan |
Category: | javax / collections |
Type: | JavaX fragment (include) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2020-08-03 21:45:05 |
Source code size: | 8493 bytes / 322 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 328 / 638 |
Version history: | 12 change(s) |
Referenced in: | [show references] |