/*
* Copyright 2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.openhft.collections.research;
import com.koloboke.function.IntConsumer;
import net.openhft.lang.io.Bytes;
public class Tiered2VanillaShortShortMultiMap extends SimpleVanillaShortShortMultiMap {
private final long halfCapacity;
private final long halfCapacityMask;
private final long halfCapacityMask2;
public Tiered2VanillaShortShortMultiMap(long minCapacity) {
super(minCapacity);
halfCapacity = capacity / 2L;
halfCapacityMask = halfCapacity - 1L;
halfCapacityMask2 = halfCapacityMask * ENTRY_SIZE;
}
public Tiered2VanillaShortShortMultiMap(Bytes bytes) {
super(bytes);
halfCapacity = capacity / 2L;
halfCapacityMask = halfCapacity - 1L;
halfCapacityMask2 = halfCapacityMask * ENTRY_SIZE;
}
@Override
public void put(int key, int value) {
if (key == UNSET_KEY)
key = HASH_INSTEAD_OF_UNSET_KEY;
else if ((key & ~0xFFFF) != 0)
throw new IllegalArgumentException("Key out of range, was " + key);
if ((value & ~0xFFFF) != 0)
throw new IllegalArgumentException("Value out of range, was " + value);
long pos = indexToPos(key & halfCapacityMask);
// probe 1
int entry = bytes.readInt(pos);
int hash2 = entry >>> 16;
if (hash2 == UNSET_KEY) {
bytes.writeInt(pos, ((key << 16) | value));
return;
}
if (hash2 == key) {
int value2 = entry & 0xFFFF;
if (value2 == value)
return;
}
pos = (pos + ENTRY_SIZE) & halfCapacityMask2;
// probe 2
entry = bytes.readInt(pos);
hash2 = entry >>> 16;
if (hash2 == UNSET_KEY) {
bytes.writeInt(pos, ((key << 16) | value));
return;
}
if (hash2 == key) {
int value2 = entry & 0xFFFF;
if (value2 == value)
return;
}
pos = halfCapacity * ENTRY_SIZE + ((pos + ENTRY_SIZE) & halfCapacityMask2);
while (true) {
entry = bytes.readInt(pos);
hash2 = entry >>> 16;
if (hash2 == UNSET_KEY) {
bytes.writeInt(pos, ((key << 16) | value));
return;
}
if (hash2 == key) {
int value2 = entry & 0xFFFF;
if (value2 == value)
return;
}
pos = (pos + ENTRY_SIZE) & capacityMask2;
}
}
private int probe;
@Override
public int startSearch(int key) {
if (key == UNSET_KEY)
key = HASH_INSTEAD_OF_UNSET_KEY;
probe = 0;
searchPos = indexToPos(key & halfCapacityMask);
return searchHash = key;
}
public int firstPos() {
probe = 1;
int entry = bytes.readInt(searchPos);
int hash2 = entry >>> 16;
if (hash2 == UNSET_KEY) {
return UNSET_VALUE;
}
searchPos = (searchPos + ENTRY_SIZE) & halfCapacityMask2;
if (hash2 == searchHash) {
return entry & 0xFFFF;
}
return secondPos();
}
public int secondPos() {
probe = -1;
int entry = bytes.readInt(searchPos);
int hash2 = entry >>> 16;
if (hash2 == UNSET_KEY) {
return UNSET_VALUE;
}
searchPos = halfCapacity * ENTRY_SIZE + ((searchPos + ENTRY_SIZE) & halfCapacityMask2);
if (hash2 == searchHash) {
return entry & 0xFFFF;
}
return ordinaryNextPos();
}
public int ordinaryNextPos() {
for (long i = 0L; i < capacity; i++) {
int entry = bytes.readInt(searchPos);
int hash2 = entry >>> 16;
if (hash2 == UNSET_KEY) {
return UNSET_VALUE;
}
searchPos = (searchPos + ENTRY_SIZE) & capacityMask2;
if (hash2 == searchHash) {
return entry & 0xFFFF;
}
}
return UNSET_VALUE;
}
@Override
public int nextPos() {
if (probe == 0) {
return firstPos();
} else if (probe > 0) {
return secondPos();
} else {
return ordinaryNextPos();
}
}
@Override
public void forEachValue(int key, IntConsumer action) {
if (key == UNSET_KEY)
key = HASH_INSTEAD_OF_UNSET_KEY;
else if ((key & ~0xFFFF) != 0)
throw new IllegalArgumentException("Key out of range, was " + key);
long pos = indexToPos(key & halfCapacityMask);
// probe 1
int entry = bytes.readInt(pos);
int hash2 = entry >>> 16;
if (hash2 == UNSET_KEY) {
return;
}
if (hash2 == key) {
int value2 = entry & 0xFFFF;
action.accept(value2);
}
pos = (pos + ENTRY_SIZE) & halfCapacityMask2;
// probe 2
entry = bytes.readInt(pos);
hash2 = entry >>> 16;
if (hash2 == UNSET_KEY) {
return;
}
if (hash2 == key) {
int value2 = entry & 0xFFFF;
action.accept(value2);
}
pos = halfCapacity * ENTRY_SIZE + ((pos + ENTRY_SIZE) & halfCapacityMask2);
while (true) {
entry = bytes.readInt(pos);
hash2 = entry >>> 16;
if (hash2 == UNSET_KEY) {
return;
}
if (hash2 == key) {
int value2 = entry & 0xFFFF;
action.accept(value2);
}
pos = (pos + ENTRY_SIZE) & capacityMask2;
}
}
}