HashEntries.java

/*
 *      Copyright (C) 2014 Robert Stupp, Koeln, Germany, robert-stupp.de
 *
 *   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 org.caffinitas.ohc.linked;

/**
 * Encapsulates access to hash entries.
 */
final class HashEntries
{
    static void init(long hash, int keyLen, int valueLen, long hashEntryAdr, int sentinel, long expireAt)
    {
        Uns.putLong(hashEntryAdr, Util.ENTRY_OFF_EXPIRE_AT, expireAt);
        Uns.putLong(hashEntryAdr, Util.ENTRY_OFF_HASH, hash);
        setNext(hashEntryAdr, 0L);
        Uns.putInt(hashEntryAdr, Util.ENTRY_OFF_KEY_LENGTH, keyLen);
        Uns.putInt(hashEntryAdr, Util.ENTRY_OFF_VALUE_LENGTH, valueLen);
        Uns.putInt(hashEntryAdr, Util.ENTRY_OFF_REFCOUNT, 1);
        Uns.putInt(hashEntryAdr, Util.ENTRY_OFF_GENERATION, Util.GEN_EDEN);
        Uns.putInt(hashEntryAdr, Util.ENTRY_OFF_SENTINEL, sentinel);
    }

    static boolean compare(long hashEntryAdr, long offset, long otherHashEntryAdr, long otherOffset, long len)
    {
        if (hashEntryAdr == 0L)
            return false;

        if (hashEntryAdr == otherHashEntryAdr)
        {
            assert offset == otherOffset;
            return true;
        }

        int p = 0;
        for (; p <= len - 8; p += 8, offset += 8, otherOffset += 8)
            if (Uns.getLong(hashEntryAdr, offset) != Uns.getLong(otherHashEntryAdr, otherOffset))
                return false;
        for (; p <= len - 4; p += 4, offset += 4, otherOffset += 4)
            if (Uns.getInt(hashEntryAdr, offset) != Uns.getInt(otherHashEntryAdr, otherOffset))
                return false;
        for (; p <= len - 2; p += 2, offset += 2, otherOffset += 2)
            if (Uns.getShort(hashEntryAdr, offset) != Uns.getShort(otherHashEntryAdr, otherOffset))
                return false;
        for (; p < len; p++, offset++, otherOffset++)
            if (Uns.getByte(hashEntryAdr, offset) != Uns.getByte(otherHashEntryAdr, otherOffset))
                return false;

        return true;
    }

    static long getLRUNext(long hashEntryAdr)
    {
        return Uns.getLong(hashEntryAdr, Util.ENTRY_OFF_LRU_NEXT);
    }

    static void setLRUNext(long hashEntryAdr, long replacement)
    {
        Uns.putLong(hashEntryAdr, Util.ENTRY_OFF_LRU_NEXT, replacement);
    }

    static long getAndSetLRUNext(long hashEntryAdr, long replacement)
    {
        return Uns.getAndPutLong(hashEntryAdr, Util.ENTRY_OFF_LRU_NEXT, replacement);
    }

    static long getLRUPrev(long hashEntryAdr)
    {
        return Uns.getLong(hashEntryAdr, Util.ENTRY_OFF_LRU_PREV);
    }

    static void setLRUPrev(long hashEntryAdr, long replacement)
    {
        Uns.putLong(hashEntryAdr, Util.ENTRY_OFF_LRU_PREV, replacement);
    }

    static long getAndSetLRUPrev(long hashEntryAdr, long replacement)
    {
        return Uns.getAndPutLong(hashEntryAdr, Util.ENTRY_OFF_LRU_PREV, replacement);
    }

    static long getHash(long hashEntryAdr)
    {
        return Uns.getLong(hashEntryAdr, Util.ENTRY_OFF_HASH);
    }

    static long getNext(long hashEntryAdr)
    {
        return hashEntryAdr != 0L ? Uns.getLong(hashEntryAdr, Util.ENTRY_OFF_NEXT) : 0L;
    }

    static int getSentinel(long hashEntryAdr)
    {
        return hashEntryAdr != 0L ? Uns.getInt(hashEntryAdr, Util.ENTRY_OFF_SENTINEL) : 0;
    }

    static void setSentinel(long hashEntryAdr, int sentinelState)
    {
        if (hashEntryAdr != 0L)
            Uns.putInt(hashEntryAdr, Util.ENTRY_OFF_SENTINEL, sentinelState);
    }

    static void setNext(long hashEntryAdr, long nextAdr)
    {
        if (hashEntryAdr == nextAdr)
            throw new IllegalArgumentException();
        if (hashEntryAdr != 0L)
            Uns.putLong(hashEntryAdr, Util.ENTRY_OFF_NEXT, nextAdr);
    }

    static int getKeyLen(long hashEntryAdr)
    {
        return Uns.getInt(hashEntryAdr, Util.ENTRY_OFF_KEY_LENGTH);
    }

    static int getValueLen(long hashEntryAdr)
    {
        return Uns.getInt(hashEntryAdr, Util.ENTRY_OFF_VALUE_LENGTH);
    }

    static long getExpireAt(long hashEntryAdr)
    {
        return Uns.getLong(hashEntryAdr, Util.ENTRY_OFF_EXPIRE_AT);
    }

    static void setExpireAt(long hashEntryAdr, long expireAt)
    {
        Uns.putLong(hashEntryAdr, Util.ENTRY_OFF_EXPIRE_AT, expireAt);
    }

    static int getGeneration(long hashEntryAdr)
    {
        return Uns.getInt(hashEntryAdr, Util.ENTRY_OFF_GENERATION);
    }

    static void setGeneration(long hashEntryAdr, int generation)
    {
        Uns.putInt(hashEntryAdr, Util.ENTRY_OFF_GENERATION, generation);
    }

    static long getAllocLen(long hashEntryAdr)
    {
        return Util.allocLen(getKeyLen(hashEntryAdr), getValueLen(hashEntryAdr));
    }

    static void reference(long hashEntryAdr)
    {
        Uns.increment(hashEntryAdr, Util.ENTRY_OFF_REFCOUNT);
    }

    static boolean dereference(long hashEntryAdr)
    {
        if (hashEntryAdr != 0L && Uns.decrement(hashEntryAdr, Util.ENTRY_OFF_REFCOUNT))
        {
            Uns.free(hashEntryAdr);
            return true;
        }
        return false;
    }
}