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

com.koloboke.collect.impl.hash.UpdatableLHash Maven / Gradle / Ivy

Go to download

Carefully designed and efficient extension of the Java Collections Framework with primitive specializations and more, built for Java 8 (Implementation)

The newest version!
/*
 * 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 com.koloboke.collect.impl.hash;

import com.koloboke.collect.hash.HashConfig;

import static com.koloboke.collect.impl.Maths.isPowerOf2;
import static com.koloboke.collect.impl.hash.LHashCapacities.*;


public abstract class UpdatableLHash extends HashWithoutRemovedSlots implements LHash {

    static void verifyConfig(HashConfig config) {
        assert config.getGrowthFactor() == 2.0;
    }

    ////////////////////////////
    // Fields

    private HashConfigWrapper configWrapper;

    int size;

    private int maxSize;

    private int modCount = 0;


    /////////////////////////////
    // Getters

    @Override
    public final HashConfigWrapper configWrapper() {
        return configWrapper;
    }

    @Override
    public final int size() {
        return size;
    }

    @Override
    public final int modCount() {
        return modCount;
    }

    final void incrementModCount() {
        modCount++;
    }


    ////////////////////////
    // Initialization and construction operations

    final void copy(LHash hash) {
        configWrapper = hash.configWrapper();
        size = hash.size();
        int capacity = hash.capacity();
        maxSize = maxSize(capacity);
    }

    final void init(HashConfigWrapper configWrapper, int size) {
        verifyConfig(configWrapper.config());
        this.configWrapper = configWrapper;
        this.size = 0;
        internalInit(targetCapacity(size));
    }

    private void internalInit(int capacity) {
        assert isPowerOf2(capacity);
        maxSize = maxSize(capacity);
        allocateArrays(capacity);
    }

    private int maxSize(int capacity) {
        // No sense in trying to rehash after each insertion
        // if the capacity is already reached the limit.
        return !isMaxCapacity(capacity) ? configWrapper.maxSize(capacity) : capacity - 1;
    }

    /**
     * Allocates arrays of {@code capacity} length to hold states, elements, keys or values in.
     *
     * 

Subclasses should override this method, but MUST NOT call it. This method is called * in {@code UpdatableLHash} from {@link #initForRehash(int)} and * {@link #init(HashConfigWrapper, int)} methods. * * @param capacity length of arrays, comprising the hashtable */ abstract void allocateArrays(int capacity); /** * Moves elements to the new arrays of {@code newCapacity} length. * *

This method should be implemented as follows: * * 1. Copy references to the old arrays comprising the hashtable from fields to local variables * * 2. Call {@link #initForRehash(int)} * * 3. Move elements, entries, etc. from the old arrays to the new ones. * *

Subclasses should implement, but MUST NOT call this method. This method is called * in {@code UpdatableLHash} from {@link #postInsertHook()}, {@link #ensureCapacity(long)} * and {@link #shrink()} methods. */ abstract void rehash(int newCapacity); /** * This method just increments modification count (see {@link #modCount()}) * and calls {@link #internalInit(int)}. Should be called by subclasses * in {@link #rehash(int)} implementation. */ final void initForRehash(int newCapacity) { modCount++; internalInit(newCapacity); } ////////////////////////////// // Roots of chain operations /** * Empties the hash. */ @Override public void clear() { modCount++; size = 0; } ///////////////////////////// // Modification hooks and rehash logic @Override public boolean shrink() { int newCapacity = targetCapacity(size); if (newCapacity < capacity()) { rehash(newCapacity); return true; } else { return false; } } private boolean tryRehashForExpansion(int newCapacity) { if (newCapacity > capacity()) { rehash(newCapacity); return true; } else { return false; } } @Override public final boolean ensureCapacity(long minSize) { int intMinSize = (int) Math.min(minSize, (long) Integer.MAX_VALUE); if (minSize < 0L) throw new IllegalArgumentException( "Min size should be positive, " + minSize + " given."); return intMinSize > maxSize && tryRehashForExpansion(targetCapacity(intMinSize)); } final void postInsertHook() { if (++size > maxSize) { int capacity = capacity(); if (!isMaxCapacity(capacity)) { rehash(capacity << 1); } } } /** * LongLong, LongDouble, DoubleDouble and DoubleLong maps might use array of doubled size * as table to layout keys and values in parallel. They should override this method to return * {@code true}. * *

IntInt and smaller maps would better use array of larger primitives ({@code long[]} in * this particular case), because it 1) guarantees that each key and value pair lay on the same * cache line and 2) allows higher max capacity. * *

It is UpdatableLHash's concern in order to treat edge cases of capacities near to Java * array size limit correctly. * * @return if the hash is a map which use double sized array to layout keys and values * in parallel */ boolean doubleSizedArrays() { return false; } private int targetCapacity(int size) { return LHashCapacities.capacity(configWrapper, size, doubleSizedArrays()); } private boolean isMaxCapacity(int capacity) { return LHashCapacities.isMaxCapacity(capacity, doubleSizedArrays()); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy