public ConcurrentLongPairSet(int expectedItems, int concurrencyLevel) { checkArgument(expectedItems > 0); checkArgument(concurrencyLevel > 0); checkArgument(expectedItems >= concurrencyLevel); int numSections = concurrencyLevel; int perSectionExpectedItems = expectedItems / numSections; int perSectionCapacity = (int) (perSectionExpectedItems / SetFillFactor); this.sections = new Section[numSections]; for (int i = 0; i < numSections; i++) { sections[i] = new Section(perSectionCapacity); } }
/** * @return a new list of keys with max provided numberOfItems (makes a copy) */ public Set<LongPair> items(int numberOfItems) { Set<LongPair> items = new HashSet<>(); for (Section s : sections) { s.forEach((item1, item2) -> { if (items.size() < numberOfItems) { items.add(new LongPair(item1, item2)); } }); if (items.size() >= numberOfItems) { return items; } } return items; }
private void rehash() { // Expand the hashmap int newCapacity = capacity * 2; long[] newTable = new long[2 * newCapacity]; Arrays.fill(newTable, EmptyItem); // Re-hash table for (int i = 0; i < table.length; i += 2) { long storedItem1 = table[i]; long storedItem2 = table[i + 1]; if (storedItem1 != EmptyItem && storedItem1 != DeletedItem) { insertKeyValueNoLock(newTable, newCapacity, storedItem1, storedItem2); } } capacity = newCapacity; table = newTable; usedBuckets = size; resizeThreshold = (int) (capacity * SetFillFactor); }
boolean contains(long item1, long item2, int hash) { long stamp = tryOptimisticRead(); boolean acquiredLock = false; int bucket = signSafeMod(hash, capacity); long storedItem2 = table[bucket + 1]; if (!acquiredLock && validate(stamp)) { stamp = readLock(); acquiredLock = true; unlockRead(stamp);
boolean add(long item1, long item2, long hash) { long stamp = writeLock(); int bucket = signSafeMod(hash, capacity); if (usedBuckets > resizeThreshold) { try { rehash(); } finally { unlockWrite(stamp); unlockWrite(stamp);
public void forEach(LongPairConsumer processor) { long stamp = tryOptimisticRead(); if (!validate(stamp)) { stamp = readLock(); acquiredReadLock = true; table = this.table; long storedItem2 = table[bucket + 1]; if (!acquiredReadLock && !validate(stamp)) { stamp = readLock(); acquiredReadLock = true; unlockRead(stamp);
private boolean remove(long item1, long item2, int hash) { long stamp = writeLock(); int bucket = signSafeMod(hash, capacity); try { while (true) { long storedItem1 = table[bucket]; long storedItem2 = table[bucket + 1]; if (item1 == storedItem1 && item2 == storedItem2) { --size; cleanBucket(bucket); return true; } else if (storedItem1 == EmptyItem) { return false; } bucket = (bucket + 2) & (table.length - 1); } } finally { unlockWrite(stamp); } }
private int removeIf(LongPairPredicate filter) { Objects.requireNonNull(filter); int removedItems = 0; // Go through all the buckets for this section for (int bucket = 0; bucket < table.length; bucket += 2) { long storedItem1 = table[bucket]; long storedItem2 = table[bucket + 1]; if (storedItem1 != DeletedItem && storedItem1 != EmptyItem) { if (filter.test(storedItem1, storedItem2)) { long h = hash(storedItem1, storedItem2); if (remove(storedItem1, storedItem2, (int) h)) { removedItems++; } } } } return removedItems; }
public boolean add(long item1, long item2) { checkBiggerEqualZero(item1); long h = hash(item1, item2); return getSection(h).add(item1, item2, (int) h); }
public boolean contains(long item1, long item2) { checkBiggerEqualZero(item1); long h = hash(item1, item2); return getSection(h).contains(item1, item2, (int) h); }
public void forEach(LongPairConsumer processor) { for (Section s : sections) { s.forEach(processor); } }
public void clear() { for (Section s : sections) { s.clear(); } }