Package net.openhft.collections.research

Source Code of net.openhft.collections.research.SimpleVanillaShortShortMultiMap

/*
* 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 net.openhft.koloboke.function.IntConsumer;
import net.openhft.lang.Maths;
import net.openhft.lang.io.Bytes;
import net.openhft.lang.io.DirectStore;

/**
* Supports a simple interface for int -> int[] off heap.
*/
class SimpleVanillaShortShortMultiMap {
    static final long ENTRY_SIZE = 4L;
    static final int ENTRY_SIZE_SHIFT = 2;

    /**
     * Separate method because it is too easy to forget to cast to long
     * before shifting.
     */
    static long indexToPos(int index) {
        return ((long) index) << ENTRY_SIZE_SHIFT;
    }

    static long indexToPos(long index) {
        return index << ENTRY_SIZE_SHIFT;
    }

    static final int UNSET_KEY = 0;
    static final int HASH_INSTEAD_OF_UNSET_KEY = 0xFFFF;
    static final int UNSET_VALUE = Integer.MIN_VALUE;

    static final int UNSET_ENTRY = 0xFFFF;

    final long capacity;
    final long capacityMask;
    final long capacityMask2;
    final Bytes bytes;

    public SimpleVanillaShortShortMultiMap(long minCapacity) {
        if (minCapacity < 0L || minCapacity > (1L << 16))
            throw new IllegalArgumentException();
        capacity = Maths.nextPower2(minCapacity, 16L);
        capacityMask = capacity - 1L;
        capacityMask2 = capacityMask * ENTRY_SIZE;
        bytes = new DirectStore(null, capacity * ENTRY_SIZE, false).createSlice();
        clear();
    }

    public SimpleVanillaShortShortMultiMap(Bytes bytes) {
        capacity = bytes.capacity() / ENTRY_SIZE;
        assert capacity == Maths.nextPower2(capacity, 16L);
        capacityMask = capacity - 1L;
        capacityMask2 = capacityMask * ENTRY_SIZE;
        this.bytes = bytes;
    }

    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 & capacityMask);
        while (true) {
            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) & capacityMask2;
        }
    }

    public boolean remove(int key, int value) {
        if (key == UNSET_KEY)
            key = HASH_INSTEAD_OF_UNSET_KEY;
        long pos = indexToPos(key & capacityMask);
        long removedPos = -1L;
        for (long i = 0L; i <= capacityMask; i++) {
            int entry = bytes.readInt(pos);
//            int hash2 = bytes.readInt(pos + KEY);
            int hash2 = entry >>> 16;
            if (hash2 == key) {
//                int value2 = bytes.readInt(pos + VALUE);
                int value2 = entry & 0xFFFF;
                if (value2 == value) {
                    removedPos = pos;
                    break;
                }
            } else if (hash2 == UNSET_KEY) {
                break;
            }
            pos = (pos + ENTRY_SIZE) & capacityMask2;
        }
        if (removedPos < 0L)
            return false;
        long posToShift = removedPos;
        for (long i = 0L; i <= capacityMask; i++) {
            posToShift = (posToShift + ENTRY_SIZE) & capacityMask2;
            int entryToShift = bytes.readInt(posToShift);
            int hash = entryToShift >>> 16;
            if (hash == UNSET_KEY)
                break;
            long insertPos = indexToPos(hash & capacityMask);
            // see comment in VanillaIntIntMultiMap
            boolean cond1 = insertPos <= removedPos;
            boolean cond2 = removedPos <= posToShift;
            if ((cond1 && cond2) ||
                    // chain wrapped around capacity
                    (posToShift < insertPos && (cond1 || cond2))) {
                bytes.writeInt(removedPos, entryToShift);
                removedPos = posToShift;
            }
        }
        bytes.writeInt(removedPos, UNSET_ENTRY);
        return true;
    }

    /////////////////////
    // Stateful methods

    int searchHash = -1;
    long searchPos = -1L;

    public int startSearch(int key) {
        if (key == UNSET_KEY)
            key = HASH_INSTEAD_OF_UNSET_KEY;

        searchPos = indexToPos(key & capacityMask);
        return searchHash = key;
    }

    public int nextPos() {
        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;
    }

    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 & capacityMask);
        while (true) {
            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) & capacityMask2;
        }
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("{ ");
        for (long i = 0L, pos = 0L; i < capacity; i++, pos += ENTRY_SIZE) {
            int entry = bytes.readInt(pos);
            int key = entry >>> 16;
            int value = entry & 0xFFFF;
            if (key != UNSET_KEY)
                sb.append(key).append('=').append(value).append(", ");
        }
        if (sb.length() > 2) {
            sb.setLength(sb.length() - 2);
            return sb.append(" }").toString();
        }
        return "{ }";
    }

    public void clear() {
        for (long pos = 0L; pos < bytes.capacity(); pos += ENTRY_SIZE) {
            bytes.writeInt(pos, UNSET_ENTRY);
        }
    }
}
TOP

Related Classes of net.openhft.collections.research.SimpleVanillaShortShortMultiMap

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.