Libraryless. Click here for Pure Java version (5423L/31K).
1 | /* |
2 | * #! |
3 | * 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 | // modified by Stefan Reich |
22 | |
23 | // a compact unordered set of longs. unsynchronized |
24 | |
25 | sclass CompactLongSet extends java.util.AbstractSet<Long> { |
26 | protected final static int INITIAL_SIZE = 3; |
27 | public final static double LOAD_FACTOR = 0.75; |
28 | |
29 | protected final static long deletedObject = Long.MIN_VALUE; |
30 | |
31 | bool containsZero, containsDeletedObject; // special handling for sentinels |
32 | protected int elements; |
33 | protected int freecells; |
34 | protected long[] objects; |
35 | |
36 | ifndef NoModCount |
37 | protected int modCount; |
38 | endifndef |
39 | |
40 | *() { this(0); } |
41 | |
42 | // This applies the load factor so the set should be able to hold |
43 | // expectedElements without growing (haven't tested if this works exactly). |
44 | *(int expectedElements) { |
45 | int size = max(INITIAL_SIZE, iceil(expectedElements/LOAD_FACTOR)); |
46 | // NOTE: If array size is 0, we get a |
47 | // "java.lang.ArithmeticException: / by zero" in add(Object). |
48 | objects = new long[size]; |
49 | freecells = objects.length; |
50 | } |
51 | |
52 | *(Collection<long> c) { |
53 | this(c.size()); |
54 | addAll(c); |
55 | } |
56 | |
57 | @Override |
58 | public RenamedLongIterator iterator() { |
59 | return new CompactHashIterator; |
60 | } |
61 | |
62 | @Override |
63 | public int size() { |
64 | return elements; |
65 | } |
66 | |
67 | @Override |
68 | public boolean isEmpty() { |
69 | return elements == 0; |
70 | } |
71 | |
72 | @Override |
73 | public bool contains(O o) { |
74 | ret contains((long) o); |
75 | } |
76 | |
77 | public bool contains(long o) { |
78 | if (o == 0) ret containsZero; |
79 | if (o == deletedObject) ret containsDeletedObject; |
80 | |
81 | int hash = hash(o); |
82 | int index = (hash & 0x7FFFFFFF) % objects.length; |
83 | int offset = 1; |
84 | |
85 | // search for the object (continue while !null and !this object) |
86 | while (objects[index] != 0) { |
87 | if (objects[index] == o) true; |
88 | index = ((index + offset) & 0x7FFFFFFF) % objects.length; |
89 | offset = offset*2 + 1; |
90 | |
91 | if (offset == -1) |
92 | offset = 2; |
93 | } |
94 | |
95 | false; |
96 | } |
97 | |
98 | @Override |
99 | public boolean add(Long o) { |
100 | ret add((long) o); |
101 | } |
102 | |
103 | public boolean add(long o) { |
104 | if (o == 0) { |
105 | if (containsZero) false; |
106 | set containsZero; elements++; true; |
107 | } |
108 | if (o == deletedObject) { |
109 | if (containsDeletedObject) false; |
110 | set containsDeletedObject; elements++; true; |
111 | } |
112 | int hash = hash(o); |
113 | int index = (hash & 0x7FFFFFFF) % objects.length; |
114 | int offset = 1; |
115 | int deletedix = -1; |
116 | |
117 | // search for the object (continue while !null and !this object) |
118 | while (objects[index] != 0 && objects[index] != o) { |
119 | |
120 | // if there's a deleted object here we can put this object here, |
121 | // provided it's not in here somewhere else already |
122 | if (objects[index] == deletedObject) |
123 | deletedix = index; |
124 | |
125 | index = ((index + offset) & 0x7FFFFFFF) % objects.length; |
126 | offset = offset*2 + 1; |
127 | |
128 | if (offset == -1) |
129 | offset = 2; |
130 | } |
131 | |
132 | if (objects[index] == 0) { // wasn't present already |
133 | if (deletedix != -1) // reusing a deleted cell |
134 | index = deletedix; |
135 | else |
136 | freecells--; |
137 | |
138 | ifndef NoModCount |
139 | modCount++; |
140 | endifndef |
141 | elements++; |
142 | |
143 | objects[index] = o; |
144 | |
145 | // do we need to rehash? |
146 | if (1 - (freecells / (double) objects.length) > LOAD_FACTOR) |
147 | rehash(); |
148 | return true; |
149 | } else // was there already |
150 | return false; |
151 | } |
152 | |
153 | @Override |
154 | public boolean remove(Object o) { |
155 | ret remove((long) o); |
156 | } |
157 | |
158 | public boolean remove(long o) { |
159 | if (o == 0) { |
160 | if (!containsZero) false; |
161 | containsZero = false; --elements; |
162 | true; |
163 | } |
164 | |
165 | if (o == deletedObject) { |
166 | if (!containsDeletedObject) false; |
167 | containsDeletedObject = false; --elements; |
168 | true; |
169 | } |
170 | |
171 | int hash = hash(o); |
172 | int index = (hash & 0x7FFFFFFF) % objects.length; |
173 | int offset = 1; |
174 | |
175 | // search for the object (continue while !null and !this object) |
176 | while (objects[index] != 0 && objects[index] != o) { |
177 | index = ((index + offset) & 0x7FFFFFFF) % objects.length; |
178 | offset = offset*2 + 1; |
179 | |
180 | if (offset == -1) |
181 | offset = 2; |
182 | } |
183 | |
184 | // we found the right position, now do the removal |
185 | if (objects[index] != 0) { |
186 | // we found the object |
187 | |
188 | // same problem here as with add |
189 | objects[index] = deletedObject; |
190 | ifndef NoModCount |
191 | modCount++; |
192 | endifndef |
193 | elements--; |
194 | return true; |
195 | } else |
196 | // we did not find the object |
197 | return false; |
198 | } |
199 | |
200 | @Override |
201 | public void clear() { |
202 | elements = 0; |
203 | for (int ix = 0; ix < objects.length; ix++) |
204 | objects[ix] = 0; |
205 | containsZero = containsDeletedObject = false; |
206 | freecells = objects.length; |
207 | ifndef NoModCount |
208 | modCount++; |
209 | endifndef |
210 | } |
211 | |
212 | protected void rehash() { |
213 | int garbagecells = objects.length - (elements + freecells); |
214 | if (garbagecells / (double) objects.length > 0.05) |
215 | // rehash with same size |
216 | rehash(objects.length); |
217 | else |
218 | // rehash with increased capacity |
219 | rehash(objects.length*2 + 1); |
220 | } |
221 | |
222 | protected void rehash(int newCapacity) { |
223 | int oldCapacity = objects.length; |
224 | @SuppressWarnings("unchecked") |
225 | long[] newObjects = new[newCapacity]; |
226 | |
227 | for ix to oldCapacity: { |
228 | long o = objects[ix]; |
229 | if (o == 0 || o == deletedObject) |
230 | continue; |
231 | |
232 | int hash = hash(o); |
233 | int index = (hash & 0x7FFFFFFF) % newCapacity; |
234 | int offset = 1; |
235 | |
236 | // search for the object |
237 | while(newObjects[index] != 0) { // no need to test for duplicates |
238 | index = ((index + offset) & 0x7FFFFFFF) % newCapacity; |
239 | offset = offset*2 + 1; |
240 | |
241 | if (offset == -1) |
242 | offset = 2; |
243 | } |
244 | |
245 | newObjects[index] = o; |
246 | } |
247 | |
248 | objects = newObjects; |
249 | freecells = objects.length - elements; |
250 | } |
251 | |
252 | private class CompactHashIterator extends RenamedLongIterator { |
253 | private int index; |
254 | private int lastReturned = -1; |
255 | bool sendZero, sendDeletedObject; |
256 | |
257 | ifndef NoModCount |
258 | private int expectedModCount; |
259 | endifndef |
260 | |
261 | @SuppressWarnings("empty-statement") |
262 | public CompactHashIterator() { |
263 | // find first non-empty slot |
264 | for (index = 0; index < objects.length && |
265 | (objects[index] == 0 || |
266 | objects[index] == deletedObject); index++) |
267 | ; |
268 | ifndef NoModCount |
269 | expectedModCount = modCount; |
270 | endifndef |
271 | |
272 | sendZero = containsZero; |
273 | sendDeletedObject = containsDeletedObject; |
274 | } |
275 | |
276 | @Override |
277 | public bool hasNext() { |
278 | ret index < objects.length || sendZero || sendDeletedObject; |
279 | } |
280 | |
281 | @Override |
282 | public long nextLong() { |
283 | /*if (modCount != expectedModCount) |
284 | throw new ConcurrentModificationException();*/ |
285 | int length = objects.length; |
286 | |
287 | if (index >= length) { |
288 | if (sendZero) { sendZero = false; ret 0L; } |
289 | if (sendDeletedObject) { sendDeletedObject = false; ret deletedObject; } |
290 | throw new NoSuchElementException; |
291 | } |
292 | |
293 | lastReturned = index; |
294 | for (index += 1; index < length && |
295 | (objects[index] == 0 || |
296 | objects[index] == deletedObject); index++) |
297 | ; |
298 | |
299 | ret objects[lastReturned]; |
300 | } |
301 | |
302 | @Override |
303 | public void remove() { |
304 | ifndef NoModCount |
305 | if (modCount != expectedModCount) |
306 | throw new ConcurrentModificationException(); |
307 | endifndef |
308 | if (lastReturned == -1 || lastReturned == -2) |
309 | throw new IllegalStateException(); |
310 | // delete object |
311 | if (objects[lastReturned] != 0 && objects[lastReturned] != deletedObject) { |
312 | objects[lastReturned] = deletedObject; |
313 | elements--; |
314 | ifndef NoModCount |
315 | modCount++; |
316 | expectedModCount = modCount; // this is expected; we made the change |
317 | endifndef |
318 | } |
319 | } |
320 | } |
321 | |
322 | int capacity() { ret objects.length; } |
323 | |
324 | // returns true if there was a shrink |
325 | bool shrinkToFactor(double factor) { |
326 | if (factor > LOAD_FACTOR) |
327 | fail("Shrink factor must be equal to or smaller than load factor: " + factor + " / " + LOAD_FACTOR); |
328 | int newCapacity = max(INITIAL_SIZE, iround(size()/factor); |
329 | if (newCapacity >= capacity()) false; |
330 | rehash(newCapacity); |
331 | true; |
332 | } |
333 | |
334 | int hash(long l) { ret main hashCode(l); } |
335 | } |
Began life as a copy of #1028522
download show line numbers debug dex old transpilations
Travelled to 4 computer(s): bhatertpkbcr, ekrmjmnbrukm, mowyntqkapby, mqqgnosmbjvj
No comments. add comment
Snippet ID: | #1033825 |
Snippet name: | CompactLongSet [OK] |
Eternal ID of this version: | #1033825/25 |
Text MD5: | b8a1c9cefa4102d0177fabcd515a21eb |
Transpilation MD5: | bb77863d25cccc540f738b3b81c7b914 |
Author: | stefan |
Category: | javax / collections |
Type: | JavaX fragment (include) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2022-03-22 21:31:38 |
Source code size: | 9219 bytes / 335 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 185 / 429 |
Version history: | 24 change(s) |
Referenced in: | [show references] |