RobotCore 1.0
WPILib port to raspberry Pi
Loading...
Searching...
No Matches
LongToObjectHashMap.java
1// Copyright (c) FIRST and other WPILib contributors.
2// Open Source Software; you can modify and/or share it under the terms of
3// the WPILib BSD license file in the root directory of this project.
4
5package org.wpilib.units.collections;
6
7import java.util.ArrayList;
8import java.util.Arrays;
9import java.util.Collection;
10import java.util.List;
11
18public class LongToObjectHashMap<V> {
19 private static final int INITIAL_SIZE = 0;
20 private static final int INITIAL_CAPACITY = 8; // NOTE: must be a power of two
21
27 private static final double LOAD_FACTOR = 75.00 / 100;
28
30 private int m_size = INITIAL_SIZE;
31
36 private int m_capacity = INITIAL_CAPACITY;
37
46 private long[] m_keys = new long[m_capacity];
47
49 private boolean[] m_uses = new boolean[m_capacity];
50
54 @SuppressWarnings("unchecked")
55 private V[] m_values = (V[]) new Object[m_capacity];
56
59
67 public V put(long key, V value) {
68 int bucket = bucket(key);
69
70 // Increment the bucket until we hit an open space (there's always going to be at least one)
71 while (m_uses[bucket]) {
72 if (m_keys[bucket] == key) {
73 // replace the existing value
74 var oldValue = m_values[bucket];
75 m_values[bucket] = value;
76 return oldValue;
77 }
78 bucket = safeIncrement(bucket);
79 }
80
81 m_uses[bucket] = true;
82 m_keys[bucket] = key;
83 m_values[bucket] = value;
84 m_size++;
85
86 if (m_size > maxSize()) {
87 grow();
88 }
89 return null;
90 }
91
98 public V get(long key) {
99 int bucket = bucket(key);
100 while (m_uses[bucket]) {
101 if (m_keys[bucket] == key) {
102 // found it
103 return m_values[bucket];
104 }
105 bucket = safeIncrement(bucket);
106 }
107 return null;
108 }
109
116 public V remove(long key) {
117 int bucket = bucket(key);
118 while (m_uses[bucket]) {
119 if (m_keys[bucket] == key) {
120 // found it
121 // TODO: Shrink the map when below a certain load factor
122 // Current use cases don't remove elements from the map, so there's not much use
123 // for shrinking at the moment.
124 m_size--;
125 m_keys[bucket] = 0L;
126 m_uses[bucket] = false;
127
128 var oldValue = m_values[bucket];
129 m_values[bucket] = null;
130 return oldValue;
131 }
132 bucket = safeIncrement(bucket);
133 }
134
135 return null;
136 }
137
144 public boolean containsKey(long key) {
145 int bucket = bucket(key);
146 while (m_uses[bucket]) {
147 if (m_keys[bucket] == key) {
148 return true;
149 }
150 bucket = safeIncrement(bucket);
151 }
152 return false;
153 }
154
156 public void clear() {
157 if (m_size == 0) {
158 // Nothing to do
159 return;
160 }
161 m_size = 0;
162
163 Arrays.fill(m_uses, false);
164 Arrays.fill(m_keys, 0L);
165 Arrays.fill(m_values, null);
166 }
167
173 public int size() {
174 return m_size;
175 }
176
177 // package-private for tests
178 int capacity() {
179 return m_capacity;
180 }
181
187 public boolean isEmpty() {
188 return m_size == 0;
189 }
190
199 // copy the sparse key array into a compact array
200 final long[] keys = new long[m_size];
201 int i = 0;
202 for (int bucket = 0; bucket < m_capacity; bucket++) {
203 if (m_uses[bucket]) {
204 keys[i] = m_keys[bucket];
205 i++;
206 }
207 }
208
209 return new ReadOnlyPrimitiveLongSet(keys);
210 }
211
218 public Collection<V> values() {
219 Collection<V> values = new ArrayList<>();
220 for (int bucket = 0; bucket < m_capacity; bucket++) {
221 if (m_uses[bucket]) {
222 values.add(m_values[bucket]);
223 }
224 }
225 return List.copyOf(values); // return a readonly copy
226 }
227
233 @FunctionalInterface
234 public interface IteratorFunction<V> {
241 void accept(long key, V value);
242 }
243
249 public void forEach(IteratorFunction<? super V> function) {
250 for (int bucket = 0; bucket < m_capacity; bucket++) {
251 if (m_uses[bucket]) {
252 function.accept(m_keys[bucket], m_values[bucket]);
253 }
254 }
255 }
256
257 private void grow() {
258 final int currentSize = m_size;
259 final int oldCapacity = m_capacity;
260 if (oldCapacity * LOAD_FACTOR >= currentSize) {
261 // We're below the maximum allowed size for the current capacity
262 // Nothing to do
263 return;
264 }
265
266 final int newCapacity = oldCapacity * 2;
267 final int newMask = newCapacity - 1;
268
269 final boolean[] oldUses = m_uses;
270 final long[] oldKeys = m_keys;
271 final V[] oldValues = m_values;
272
273 final boolean[] newUses = new boolean[newCapacity];
274 final long[] newKeys = new long[newCapacity];
275 @SuppressWarnings("unchecked")
276 final V[] newValues = (V[]) new Object[newCapacity];
277
278 for (int oldBucket = 0; oldBucket < oldCapacity; oldBucket++) {
279 if (!oldUses[oldBucket]) {
280 // Bucket is empty, skip
281 continue;
282 }
283 final long key = oldKeys[oldBucket];
284 final V value = oldValues[oldBucket];
285
286 int newBucket = (int) (hash(key) & newMask);
287 while (newUses[newBucket]) {
288 newBucket = (newBucket + 1) & newMask;
289 }
290
291 newUses[newBucket] = true;
292 newKeys[newBucket] = key;
293 newValues[newBucket] = value;
294 }
295
296 m_capacity = newCapacity;
297 m_uses = newUses;
298 m_keys = newKeys;
299 m_values = newValues;
300 }
301
302 private int maxSize() {
303 return (int) (m_capacity * LOAD_FACTOR);
304 }
305
313 private long hash(long key) {
314 return 31 + (key ^ (key >>> 15) ^ (key >>> 31) ^ (key << 31));
315 }
316
321 private int mask() {
322 return m_capacity - 1;
323 }
324
332 private int bucket(long key) {
333 var hash = hash(key);
334 return (int) (hash & mask());
335 }
336
343 private int safeIncrement(int bucket) {
344 return (bucket + 1) & mask();
345 }
346}
void forEach(IteratorFunction<? super V > function)