All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.epam.deltix.qsrv.hf.blocks.InstrumentKeyToIntegerHashMap Maven / Gradle / Ivy

There is a newer version: 6.2.9
Show newest version
/*
 * Copyright 2024 EPAM Systems, Inc
 *
 * See the NOTICE file distributed with this work for additional information
 * regarding copyright ownership. 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 com.epam.deltix.qsrv.hf.blocks;

import com.epam.deltix.timebase.messages.ConstantIdentityKey;
import com.epam.deltix.util.collections.KeyEntry;
import com.epam.deltix.util.collections.generated.IntegerEnumeration;
import org.agrona.BitUtil;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

public class InstrumentKeyToIntegerHashMap
    extends InstrumentKeyHashMapBase
{
    private int []         values;

    public InstrumentKeyToIntegerHashMap() {
        super ();
    }

    public InstrumentKeyToIntegerHashMap(int cap) {
        super (validateSize(cap));
    }

    private static int validateSize(int cap) {
        if (!BitUtil.isPowerOfTwo(cap)) {
            throw new IllegalArgumentException("Size must be a power of 2");
        }
        return cap;
    }

    @Override
    protected void              allocTable (int cap) {
        super.allocTable (cap);

        values = new int [cap];
    }

    @Override
    public long                 getSizeInMemory () {
        return (
            super.getSizeInMemory () + (SIZE_OF_POINTER + ARRAY_OVERHEAD) +
            values.length * SIZE_OF_INT
        );
    }


    protected void              resizeTable (int newSize) {
        assert BitUtil.isPowerOfTwo(newSize);

        final int curLength = values.length;
        final ConstantIdentityKey[] saveKeys = keys;
        final int[] saveValues = values;
        final int[] savePrev = prev;

        allocTable (newSize);

        for (int ii = 0; ii < curLength; ii++)
            if (savePrev [ii] != NULL)
                putNewNoSpaceCheck (saveKeys [ii], saveValues [ii]);
    }

    public int               get (CharSequence symbol, int notFoundValue) {
        int         pos = find (symbol);

        return (pos == NULL ? notFoundValue : values [pos]);
    }

    /**
     * @return key object instance if key present in the map
     */
    @Nullable
    public ConstantIdentityKey getKeyObject(CharSequence symbol) {
        int pos = find(symbol);

        return (pos == NULL ? null : keys[pos]);
    }

    public int               get (ConstantIdentityKey key, int notFoundValue) {
        int         pos = find (key);

        return (pos == NULL ? notFoundValue : values [pos]);
    }

    /**
     *  Remove a value, if existed.
     *
     *  @param key          The key
     *  @param notFoundValue This will be returned if the key was not associated with a value.
     *  @return The old value associated with the key, or notFoundValue.
     */
    public int               remove (ConstantIdentityKey key, int notFoundValue) {
        int         idx = find (key);

        if (idx == NULL)
            return (notFoundValue);

        int        value = values [idx];

        free (idx);

        return (value);
    }

    private void                putNewNoSpaceCheck (ConstantIdentityKey key, int value) {
        int         hidx = hashIndex (key);
        int         idx = find (hidx, key);

        if (idx != NULL)
            throw new IllegalArgumentException (
                "Value for key " + key + " already exists = " + value
            );

        idx = allocEntry (hidx);

        values [idx] = value;
        putKey(idx, key);
    }

    /**
     *  Put new element into the map
     *
     *  @param key       The key
     *  @param value     The value
     *  @return  true if the element is new, false if the key was found.
     */
    public boolean              put (ConstantIdentityKey key, int value) {
        int         hidx = hashIndex (key);
        int         idx = find (hidx, key);

        if (idx != NULL) {
            values [idx] = value;
            return (false);
        }

        if (freeHead == NULL) {
            resizeTable (values.length * 2);
            hidx = hashIndex (key); // recompute!
        }

        idx = allocEntry (hidx);

        values [idx] = value;
        putKey (idx, key);

        return (true);
    }

    /**
     *  Replace a value and return the old one.
     *  @param key          The key
     *  @param value        The new value to put in table
     *  @param notFoundValue This will be returned if the key was not associated with a value.
     *  @return The old value associated with the key, or notFoundValue.
     */
    public int               putAndGet (
        ConstantIdentityKey   key,
        int                     value,
        int                     notFoundValue
    )
    {
        int         hidx = hashIndex (key);
        int         idx = find (hidx, key);

        if (idx != NULL) {
            int    old = values [idx];

            values [idx] = value;

            return (old);
        }

        if (freeHead == NULL) {
            resizeTable (values.length * 2);
            hidx = hashIndex (key); // recompute!
        }

        idx = allocEntry (hidx);

        values [idx] = value;
        putKey(idx, key);

        return (notFoundValue);
    }

    /**
     *  Put new value into the map only if there is no previously stored value under the same key.
     *
     *  @param key          The key
     *  @param value        The new value to put in table (but only if the key is not occupied)
     *  @return             Value that remains in the map.
     */
    public int               putAndGetIfEmpty (
        ConstantIdentityKey key,
        int                 value
    )
    {
        int         hidx = hashIndex (key);
        int         idx = find (hidx, key);

        if (idx != NULL) {
            return  values [idx];
        }

        if (freeHead == NULL) {
            resizeTable (values.length * 2);
            hidx = hashIndex (key); // recompute!
        }

        idx = allocEntry (hidx);

        values [idx] = value;
        putKey(idx, key);

        return value;
    }

    /**
     *  Put new value into the map only if there is no previously stored value under the same key.
     *
     *  @param key          The key
     *  @param value        The new value to put in table (but only if the key is not occupied)
     *  @return             True if this map has changed as the result of this call.
     */
    public boolean               putIfEmpty (
        ConstantIdentityKey key,
        int                 value
    )
    {
        int         hidx = hashIndex (key);
        int         idx = find (hidx, key);

        if (idx != NULL) {
            return false;
        }

        if (freeHead == NULL) {
            resizeTable (values.length * 2);
            hidx = hashIndex (key); // recompute!
        }

        idx = allocEntry (hidx);

        values [idx] = value;
        putKey(idx, key);

        return true;
    }


    /**
     *	Linearly searches for the specified value.
     *
     *  @param value    The value to search.
     *  @return         Whether the specified value is found.
     */
    public final boolean        containsValue (int value) {
    	int         tabSize = values.length;

    	for (int ii = 0; ii < tabSize; ii++)
    		if (isFilled (ii) && values [ii] == value)
    			return (true);

    	return (false);
    }

    public final int []   valuesToArray (int [] ret) {
        if (ret == null || ret.length < count)
            ret = new int [count];

        final int       tabSize = values.length;
        int             outIdx = 0;

        for (int ii = 0; ii < tabSize; ii++)
            if (isFilled (ii))
                ret [outIdx++] = values [ii];

        assert outIdx == count;

        return ret;
    }

    /**
     * Returns array that contains keys of this map as values with array indexes matching this map keys.
     * So map [(key1 - 1), (key2 - 2), (key3 - 0)] will be returned as [key3, key1, key2]
     *
     * Values for entries in current map must be distinct and in range 0..size-1. Otherwise Illegal state exception will be thrown.
     */
    @Nonnull
    public ConstantIdentityKey[] getInverseMapSnapshot() {
        ConstantIdentityKey[] result = new ConstantIdentityKey[count];

        for (int i = 0; i < values.length; i++) {
            ConstantIdentityKey key = keys[i];
            if (key != null) {
                int value = values[i];
                if (value < 0 || value >= count || result[value] != null) {
                    throw new IllegalStateException("Map is not invertible");
                }
                result[value] = key;
            }
        }
        return result;
    }


    protected final class ElementEnumeration
        implements IntegerEnumeration, KeyEntry
    {
    	private int             pos = -1;

    	public ElementEnumeration () {
    		move ();
    	}

    	private void            move () {
    		do {
    			pos++;
    		} while (pos < values.length && isEmpty (pos));
    	}

        @Override
    	public boolean          hasMoreElements () {
    		return (pos < values.length);
    	}

        @Override
        public void             reset() {
            pos = -1;
            move();
        }

        @Override
    	public Integer           nextElement () {
    		int   ret = values [pos];
    		move ();
    		return (ret);
    	}

        @Override
	    public int           nextIntElement () {
    		int   ret = values [pos];
    		move ();
    		return (ret);
    	}

        @Override
	    public ConstantIdentityKey                key () {
           return keys [pos];
        }
    }

    public IntegerEnumeration    elements () {
    	return (new ElementEnumeration ());
    }

    @Override
    public final boolean        equals (Object o) {
        throw new UnsupportedOperationException ();
    }

    @Override
    public int                  hashCode () {
        throw new UnsupportedOperationException ();
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy