/*
 * Copyright (c) 2018 amy, All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  1. Redistributions of source code must retain the above copyright notice, this
 *     list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright notice,
 *     this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *  3. Neither the name of the copyright holder nor the names of its contributors
 *     may be used to endorse or promote products derived from this software without
 *     specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 *  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 *  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 *  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 *  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 *  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 *  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
// We disable the formatter on this class so that it doesn't get hecked up.
// Autoformatter has no idea how to handle this class correctly.
// @formatter:off


package com.mewna.catnip.cache.view;

import com.koloboke.collect.*;
import com.koloboke.collect.hash.HashConfig;
import com.koloboke.collect.impl.*;
import com.koloboke.collect.impl.hash.Hash;
import com.koloboke.collect.impl.hash.HashConfigWrapper;
import com.koloboke.collect.impl.hash.LHash;
import com.koloboke.collect.impl.hash.LHashCapacities;
import com.koloboke.collect.map.LongObjMap;
import com.koloboke.collect.set.LongSet;
import com.koloboke.collect.set.ObjSet;
import com.koloboke.collect.set.hash.HashLongSet;
import com.koloboke.collect.set.hash.HashObjSet;
import com.koloboke.function.LongObjConsumer;
import com.koloboke.function.LongObjPredicate;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.lang.reflect.Array;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.Consumer;
import java.util.function.LongConsumer;
import java.util.function.LongPredicate;
import java.util.function.Predicate;

@SuppressWarnings(value = { "all" , "unsafe" , "deprecation" , "overloads" , "rawtypes" })
final class KolobokeLongEntityMap<T>  implements LongEntityMap<T> {
    KolobokeLongEntityMap(int expectedSize) {
        this.init(DEFAULT_CONFIG_WRAPPER, expectedSize);
    }
    
    static void verifyConfig(HashConfig config) {
        if ((config.getGrowthFactor()) != 2.0) {
            throw new IllegalArgumentException(((((((config + " passed, HashConfig for a hashtable\n") + "implementation with linear probing must have growthFactor of 2.0.\n") + "A Koloboke Compile-generated hashtable implementation could have\n") + "a different growth factor, if the implemented type is annotated with\n") + "@com.koloboke.compile.hash.algo.openaddressing.QuadraticProbing or\n") + "@com.koloboke.compile.hash.algo.openaddressing.DoubleHashing"));
        }
    }
    
    @Nonnull
    public final HashConfig hashConfig() {
        return configWrapper().config();
    }
    
    long freeValue;
    
    public long sizeAsLong() {
        return ((long) (size()));
    }
    
    T[] values;
    
    long[] set;
    
    public final boolean noRemoved() {
        return true;
    }
    
    public final boolean isEmpty() {
        return (size()) == 0;
    }
    
    public final boolean containsKey(Object key) {
        return contains(key);
    }
    
    public final int freeSlots() {
        return (capacity()) - (size());
    }
    
    private HashConfigWrapper configWrapper;
    
    @Nonnull
    public long[] keys() {
        return set;
    }
    
    int size;
    
    public final int removedSlots() {
        return 0;
    }
    
    private int maxSize;
    
    public int capacity() {
        return set.length;
    }
    
    @Nonnull
    public HashLongSet keySet() {
        return new KolobokeLongEntityMap.KeyView();
    }
    
    public final double currentLoad() {
        return ((double) (size())) / ((double) (capacity()));
    }
    
    final void init(HashConfigWrapper configWrapper, int size, long freeValue) {
        KolobokeLongEntityMap.this.freeValue = freeValue;
        init(configWrapper, size);
    }
    
    public void forEach(Consumer<? super Long> action) {
        if (action == null)
            throw new NullPointerException();
        
        if (KolobokeLongEntityMap.this.isEmpty())
            return ;
        
        long free = freeValue;
        long[] keys = set;
        for (int i = (keys.length) - 1; i >= 0; i--) {
            long key;
            if ((key = keys[i]) != free) {
                action.accept(key);
            }
        }
    }
    
    boolean nullableValueEquals(@Nullable
                                        T a, @Nullable
                                        T b) {
        return (a == b) || ((a != null) && (valueEquals(a, b)));
    }
    
    public final HashConfigWrapper configWrapper() {
        return configWrapper;
    }
    
    class KeyView extends AbstractLongKeyView implements HashLongSet , InternalLongCollectionOps , KolobokeLongEntityMap.Support.SeparateKVLongLHash { // lgtm[java/inconsistent-equals-and-hashcode]
        @Nonnull
        @Override
        public HashConfig hashConfig() {
            return KolobokeLongEntityMap.this.hashConfig();
        }
        
        @Override
        public HashConfigWrapper configWrapper() {
            return KolobokeLongEntityMap.this.configWrapper();
        }
        
        @Override
        public int size() {
            return KolobokeLongEntityMap.this.size();
        }
        
        @Override
        public double currentLoad() {
            return KolobokeLongEntityMap.this.currentLoad();
        }
        
        @Override
        public long freeValue() {
            return KolobokeLongEntityMap.this.freeValue();
        }
        
        @Override
        public boolean supportRemoved() {
            return KolobokeLongEntityMap.this.supportRemoved();
        }
        
        @Override
        public long removedValue() {
            return KolobokeLongEntityMap.this.removedValue();
        }
        
        @Nonnull
        @Override
        public long[] keys() {
            return KolobokeLongEntityMap.this.keys();
        }
        
        @Override
        public int capacity() {
            return KolobokeLongEntityMap.this.capacity();
        }
        
        @Override
        public int freeSlots() {
            return KolobokeLongEntityMap.this.freeSlots();
        }
        
        @Override
        public boolean noRemoved() {
            return KolobokeLongEntityMap.this.noRemoved();
        }
        
        @Override
        public int removedSlots() {
            return KolobokeLongEntityMap.this.removedSlots();
        }
        
        @Override
        public int modCount() {
            return 0;
        }
        
        @Override
        public final boolean contains(Object o) {
            return KolobokeLongEntityMap.this.contains(o);
        }
        
        @Override
        public boolean contains(long key) {
            return KolobokeLongEntityMap.this.contains(key);
        }
        
        @Override
        public void forEach(Consumer<? super Long> action) {
            KolobokeLongEntityMap.this.forEach(action);
        }
        
        @Override
        public void forEach(LongConsumer action) {
            KolobokeLongEntityMap.this.forEach(action);
        }
        
        @Override
        public boolean forEachWhile(LongPredicate predicate) {
            return KolobokeLongEntityMap.this.forEachWhile(predicate);
        }
        
        @Override
        public boolean allContainingIn(LongCollection c) {
            return KolobokeLongEntityMap.this.allContainingIn(c);
        }
        
        @Override
        public boolean reverseAddAllTo(LongCollection c) {
            return KolobokeLongEntityMap.this.reverseAddAllTo(c);
        }
        
        @Override
        public boolean reverseRemoveAllFrom(LongSet s) {
            return KolobokeLongEntityMap.this.reverseRemoveAllFrom(s);
        }
        
        @Override
        @Nonnull
        public LongIterator iterator() {
            return KolobokeLongEntityMap.this.iterator();
        }
        
        @Override
        @Nonnull
        public LongCursor cursor() {
            return setCursor();
        }
        
        @Override
        @Nonnull
        public Object[] toArray() {
            return KolobokeLongEntityMap.this.toArray();
        }
        
        @Override
        @Nonnull
        public <T2>  T2[] toArray(@Nonnull
                                          T2[] a) {
            return KolobokeLongEntityMap.this.toArray(a);
        }
        
        @Override
        public long[] toLongArray() {
            return KolobokeLongEntityMap.this.toLongArray();
        }
        
        @Override
        public long[] toArray(long[] a) {
            return KolobokeLongEntityMap.this.toArray(a);
        }
        
        @Override
        public int hashCode() {
            return setHashCode();
        }
        
        @Override
        public String toString() {
            return setToString();
        }
        
        @Override
        public boolean shrink() {
            return KolobokeLongEntityMap.this.shrink();
        }
        
        @Override
        public final boolean remove(Object o) {
            return justRemove(((Long) (o)));
        }
        
        @Override
        public boolean removeLong(long v) {
            return justRemove(v);
        }
        
        @Override
        public boolean removeIf(Predicate<? super Long> filter) {
            return KolobokeLongEntityMap.this.removeIf(filter);
        }
        
        @Override
        public boolean removeIf(LongPredicate filter) {
            return KolobokeLongEntityMap.this.removeIf(filter);
        }
        
        @Override
        public boolean removeAll(@Nonnull
                                         Collection<?> c) {
            if (c instanceof LongCollection) {
                if (c instanceof InternalLongCollectionOps) {
                    InternalLongCollectionOps c2 = ((InternalLongCollectionOps) (c));
                    if ((c2.size()) < (KolobokeLongEntityMap.KeyView.this.size())) {
                        return c2.reverseRemoveAllFrom(KolobokeLongEntityMap.KeyView.this);
                    }
                }
                return KolobokeLongEntityMap.this.removeAll(KolobokeLongEntityMap.KeyView.this, ((LongCollection) (c)));
            }
            return KolobokeLongEntityMap.this.removeAll(KolobokeLongEntityMap.KeyView.this, c);
        }
        
        @Override
        public boolean retainAll(@Nonnull
                                         Collection<?> c) {
            return KolobokeLongEntityMap.this.retainAll(KolobokeLongEntityMap.KeyView.this, c);
        }
        
        @Override
        public void clear() {
            KolobokeLongEntityMap.this.clear();
        }
    }
    
    boolean valueEquals(@Nonnull
                                T a, @Nullable
                                T b) {
        return a.equals(b);
    }
    
    public long freeValue() {
        return freeValue;
    }
    
    @Override
    public final int size() {
        return size;
    }
    
    int nullableValueHashCode(@Nullable
                                      T value) {
        return value != null ? valueHashCode(value) : 0;
    }
    
    public boolean supportRemoved() {
        return false;
    }
    
    int valueHashCode(@Nonnull
                              T value) {
        return value.hashCode();
    }
    
    public void forEach(LongConsumer action) {
        if (action == null)
            throw new NullPointerException();
        
        if (KolobokeLongEntityMap.this.isEmpty())
            return ;
        
        long free = freeValue;
        long[] keys = set;
        for (int i = (keys.length) - 1; i >= 0; i--) {
            long key;
            if ((key = keys[i]) != free) {
                action.accept(key);
            }
        }
    }
    
    public long removedValue() {
        throw new UnsupportedOperationException();
    }
    
    int valueIndex(@Nullable
                           Object value) {
        if (value == null)
            return nullValueIndex();
        
        if (KolobokeLongEntityMap.this.isEmpty())
            return -1;
        
        T val = ((T) (value));
        int index = -1;
        long free = freeValue;
        long[] keys = set;
        T[] vals = values;
        for (int i = (keys.length) - 1; i >= 0; i--) {
            if ((keys[i]) != free) {
                if (valueEquals(val, vals[i])) {
                    index = i;
                    break;
                }
            }
        }
        return index;
    }
    
    @Nonnull
    public Equivalence<T> valueEquivalence() {
        return Equivalence.defaultEquality();
    }
    
    public boolean contains(Object key) {
        return contains(((Long) (key)).longValue());
    }
    
    public boolean containsEntry(long key, Object value) {
        int index = index(key);
        if (index >= 0) {
            return nullableValueEquals(values[index], ((T) (value)));
        } else {
            return false;
        }
    }
    
    public boolean contains(long key) {
        return (index(key)) >= 0;
    }
    
    final void init(HashConfigWrapper configWrapper, int size) {
        KolobokeLongEntityMap.verifyConfig(configWrapper.config());
        KolobokeLongEntityMap.this.configWrapper = configWrapper;
        KolobokeLongEntityMap.this.size = 0;
        internalInit(targetCapacity(size));
    }
    
    public boolean forEachWhile(LongPredicate predicate) {
        if (predicate == null)
            throw new NullPointerException();
        
        if (KolobokeLongEntityMap.this.isEmpty())
            return true;
        
        boolean terminated = false;
        long free = freeValue;
        long[] keys = set;
        for (int i = (keys.length) - 1; i >= 0; i--) {
            long key;
            if ((key = keys[i]) != free) {
                if (!(predicate.test(key))) {
                    terminated = true;
                    break;
                }
            }
        }
        return !terminated;
    }
    
    int index(long key) {
        long free;
        if (key != (free = freeValue)) {
            long[] keys = set;
            int capacityMask;
            int index;
            long cur;
            if ((cur = keys[(index = (LHash.SeparateKVLongKeyMixing.mix(key)) & (capacityMask = (keys.length) - 1))]) == key) {
                return index;
            } else {
                if (cur == free) {
                    return -1;
                } else {
                    while (true) {
                        if ((cur = keys[(index = (index - 1) & capacityMask)]) == key) {
                            return index;
                        } else if (cur == free) {
                            return -1;
                        }
                    }
                }
            }
        } else {
            return -1;
        }
    }
    
    private void internalInit(int capacity) {
        assert Maths.isPowerOf2(capacity);
        maxSize = maxSize(capacity);
        allocateArrays(capacity);
    }
    
    @Override
    public T get(Object key) {
        int index = index(((Long) (key)));
        if (index >= 0) {
            return values[index];
        } else {
            return null;
        }
    }
    
    private int nullValueIndex() {
        if (KolobokeLongEntityMap.this.isEmpty())
            return -1;
        
        int index = -1;
        long free = freeValue;
        long[] keys = set;
        T[] vals = values;
        for (int i = (keys.length) - 1; i >= 0; i--) {
            if ((keys[i]) != free) {
                if ((vals[i]) == null) {
                    index = i;
                    break;
                }
            }
        }
        return index;
    }
    
    private int maxSize(int capacity) {
        return !(isMaxCapacity(capacity)) ? configWrapper.maxSize(capacity) : capacity - 1;
    }
    
    public boolean allContainingIn(LongCollection c) {
        if (KolobokeLongEntityMap.this.isEmpty())
            return true;
        
        boolean containsAll = true;
        long free = freeValue;
        long[] keys = set;
        for (int i = (keys.length) - 1; i >= 0; i--) {
            long key;
            if ((key = keys[i]) != free) {
                if (!(c.contains(key))) {
                    containsAll = false;
                    break;
                }
            }
        }
        return containsAll;
    }
    
    @Override
    public T get(long key) {
        int index = index(key);
        if (index >= 0) {
            return values[index];
        } else {
            return null;
        }
    }
    
    @Override
    public boolean containsValue(Object value) {
        return (valueIndex(value)) >= 0;
    }
    
    private long findNewFreeOrRemoved() {
        long free = KolobokeLongEntityMap.this.freeValue;
        Random random = ThreadLocalRandom.current();
        long newFree;
        {
            do {
                newFree = ((long) (random.nextLong()));
            } while ((newFree == free) || ((index(newFree)) >= 0) );
        }
        return newFree;
    }
    
    boolean removeValue(@Nullable
                                Object value) {
        int index = valueIndex(value);
        if (index >= 0) {
            removeAt(index);
            return true;
        } else {
            return false;
        }
    }
    
    public boolean reverseAddAllTo(LongCollection c) {
        if (KolobokeLongEntityMap.this.isEmpty())
            return false;
        
        boolean changed = false;
        long free = freeValue;
        long[] keys = set;
        for (int i = (keys.length) - 1; i >= 0; i--) {
            long key;
            if ((key = keys[i]) != free) {
                changed |= c.add(key);
            }
        }
        return changed;
    }
    
    int insert(long key, T value) {
        long free;
        if (key == (free = freeValue)) {
            free = changeFree();
        }
        long[] keys = set;
        int capacityMask;
        int index;
        long cur;
        keyAbsent : if ((cur = keys[(index = (LHash.SeparateKVLongKeyMixing.mix(key)) & (capacityMask = (keys.length) - 1))]) != free) {
            if (cur == key) {
                return index;
            } else {
                while (true) {
                    if ((cur = keys[(index = (index - 1) & capacityMask)]) == free) {
                        break keyAbsent;
                    } else if (cur == key) {
                        return index;
                    }
                }
            }
        }
        keys[index] = key;
        values[index] = value;
        postInsertHook();
        return -1;
    }
    
    long changeFree() {
        long newFree = findNewFreeOrRemoved();
        LongArrays.replaceAll(set, freeValue, newFree);
        KolobokeLongEntityMap.this.freeValue = newFree;
        return newFree;
    }
    
    final void initForRehash(int newCapacity) {
        internalInit(newCapacity);
    }
    
    public boolean reverseRemoveAllFrom(LongSet s) {
        if ((KolobokeLongEntityMap.this.isEmpty()) || (s.isEmpty()))
            return false;
        
        boolean changed = false;
        long free = freeValue;
        long[] keys = set;
        for (int i = (keys.length) - 1; i >= 0; i--) {
            long key;
            if ((key = keys[i]) != free) {
                changed |= s.removeLong(key);
            }
        }
        return changed;
    }
    
    private void _MutableSeparateKVLongLHashSO_allocateArrays(int capacity) {
        set = new long[capacity];
        if ((freeValue) != 0)
            Arrays.fill(set, freeValue);
        
    }
    
    private void _MutableLHash_clear() {
        size = 0;
    }
    
    private void _MutableSeparateKVLongLHashSO_clear() {
        _MutableLHash_clear();
        Arrays.fill(set, freeValue);
    }
    
    public boolean shrink() {
        int newCapacity = targetCapacity(size);
        if (newCapacity < (capacity())) {
            rehash(newCapacity);
            return true;
        } else {
            return false;
        }
    }
    
    @SuppressWarnings(value = "unchecked")
    void allocateArrays(int capacity) {
        _MutableSeparateKVLongLHashSO_allocateArrays(capacity);
        values = ((T[]) (new Object[capacity]));
    }
    
    private void _MutableLHashSeparateKVLongObjMapSO_clear() {
        _MutableSeparateKVLongLHashSO_clear();
        Arrays.fill(values, null);
    }
    
    @Nonnull
    public Object[] toArray() {
        int size = size();
        Object[] result = new Object[size];
        if (size == 0)
            return result;
        
        int resultIndex = 0;
        long free = freeValue;
        long[] keys = set;
        for (int i = (keys.length) - 1; i >= 0; i--) {
            long key;
            if ((key = keys[i]) != free) {
                result[(resultIndex++)] = key;
            }
        }
        return result;
    }
    
    private boolean tryRehashForExpansion(int newCapacity) {
        if (newCapacity > (capacity())) {
            rehash(newCapacity);
            return true;
        } else {
            return false;
        }
    }
    
    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)));
    }
    
    @SuppressWarnings(value = "unchecked")
    @Nonnull
    public <T2>  T2[] toArray(@Nonnull
                                      T2[] a) {
        int size = size();
        if ((a.length) < size) {
            Class<?> elementType = a.getClass().getComponentType();
            a = ((T2[]) (Array.newInstance(elementType, size)));
        }
        if (size == 0) {
            if ((a.length) > 0)
                a[0] = null;
            
            return a;
        }
        int resultIndex = 0;
        long free = freeValue;
        long[] keys = set;
        for (int i = (keys.length) - 1; i >= 0; i--) {
            long key;
            if ((key = keys[i]) != free) {
                a[(resultIndex++)] = ((T2) (Long.valueOf(key)));
            }
        }
        if ((a.length) > resultIndex)
            a[resultIndex] = null;
        
        return a;
    }
    
    final void postRemoveHook() {
        (size)--;
    }
    
    final void postInsertHook() {
        if ((++(size)) > (maxSize)) {
            int capacity = capacity();
            if (!(isMaxCapacity(capacity))) {
                rehash((capacity << 1));
            }
        }
    }
    
    private static boolean identical(Object a, Object b) {
        return a == b;
    }
    
    @Nonnull
    public long[] toLongArray() {
        int size = size();
        long[] result = new long[size];
        if (size == 0)
            return result;
        
        int resultIndex = 0;
        long free = freeValue;
        long[] keys = set;
        for (int i = (keys.length) - 1; i >= 0; i--) {
            long key;
            if ((key = keys[i]) != free) {
                result[(resultIndex++)] = key;
            }
        }
        return result;
    }
    
    @SuppressWarnings(value = "unchecked")
    public boolean containsAllEntries(Map<?, ?> m) {
        if (KolobokeLongEntityMap.identical(KolobokeLongEntityMap.this, m))
            throw new IllegalArgumentException();
        
        if (m instanceof LongObjMap) {
            LongObjMap m2 = ((LongObjMap) (m));
            if (m2.valueEquivalence().equals(KolobokeLongEntityMap.this.valueEquivalence())) {
                if ((KolobokeLongEntityMap.this.size()) < (m2.size()))
                    return false;
                
                if ((InternalLongObjMapOps.class.isAssignableFrom(getClass())) && (m2 instanceof InternalLongObjMapOps)) {
                    return ((InternalLongObjMapOps) (m2)).allEntriesContainingIn(((InternalLongObjMapOps<?>) (InternalLongObjMapOps.class.cast(KolobokeLongEntityMap.this))));
                }
            }
            return m2.forEachWhile(new LongObjPredicate() {
                @Override
                public boolean test(long a, Object b) {
                    return containsEntry(a, b);
                }
            });
        }
        for (Map.Entry<?, ?> e : m.entrySet()) {
            if (!(containsEntry(((Long) (e.getKey())), e.getValue())))
                return false;
            
        }
        return true;
    }
    
    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());
    }
    
    @Nonnull
    public long[] toArray(long[] a) {
        int size = size();
        if ((a.length) < size)
            a = new long[size];
        
        if (size == 0) {
            if ((a.length) > 0)
                a[0] = 0L;
            
            return a;
        }
        int resultIndex = 0;
        long free = freeValue;
        long[] keys = set;
        for (int i = (keys.length) - 1; i >= 0; i--) {
            long key;
            if ((key = keys[i]) != free) {
                a[(resultIndex++)] = key;
            }
        }
        if ((a.length) > resultIndex)
            a[resultIndex] = 0L;
        
        return a;
    }
    
    public int setHashCode() {
        int hashCode = 0;
        long free = freeValue;
        long[] keys = set;
        for (int i = (keys.length) - 1; i >= 0; i--) {
            long key;
            if ((key = keys[i]) != free) {
                hashCode += ((int) (key ^ (key >>> 32)));
            }
        }
        return hashCode;
    }
    
    public String setToString() {
        if (KolobokeLongEntityMap.this.isEmpty())
            return "[]";
        
        StringBuilder sb = new StringBuilder();
        int elementCount = 0;
        long free = freeValue;
        long[] keys = set;
        for (int i = (keys.length) - 1; i >= 0; i--) {
            long key;
            if ((key = keys[i]) != free) {
                sb.append(' ').append(key).append(',');
                if ((++elementCount) == 8) {
                    int expectedLength = (sb.length()) * ((size()) / 8);
                    sb.ensureCapacity((expectedLength + (expectedLength / 2)));
                }
            }
        }
        sb.setCharAt(0, '[');
        sb.setCharAt(((sb.length()) - 1), ']');
        return sb.toString();
    }
    
    @Override
    @Nonnull
    public HashObjSet<Map.Entry<Long, T>> entrySet() {
        return new EntryView();
    }
    
    @Override
    @Nonnull
    public ObjCollection<T> values() {
        return new ValueView();
    }
    
    @Override
    public boolean equals(Object o) {
        if ((KolobokeLongEntityMap.this) == o) {
            return true;
        }
        if (!(o instanceof Map)) {
            return false;
        }
        Map<?, ?> that = ((Map<?, ?>) (o));
        if ((that.size()) != (KolobokeLongEntityMap.this.size())) {
            return false;
        }
        try {
            return KolobokeLongEntityMap.this.containsAllEntries(that);
        } catch (ClassCastException e) {
            return false;
        } catch (NullPointerException e) {
            return false;
        }
    }
    
    @Override
    public int hashCode() {
        int hashCode = 0;
        long free = freeValue;
        long[] keys = set;
        T[] vals = values;
        for (int i = (keys.length) - 1; i >= 0; i--) {
            long key;
            if ((key = keys[i]) != free) {
                hashCode += ((int) ((key ^ (key >>> 32)))) ^ (nullableValueHashCode(vals[i]));
            }
        }
        return hashCode;
    }
    
    void rehash(int newCapacity) {
        long free = freeValue;
        long[] keys = set;
        T[] vals = values;
        initForRehash(newCapacity);
        long[] newKeys = set;
        int capacityMask = (newKeys.length) - 1;
        T[] newVals = values;
        for (int i = (keys.length) - 1; i >= 0; i--) {
            long key;
            if ((key = keys[i]) != free) {
                int index;
                if ((newKeys[(index = (LHash.SeparateKVLongKeyMixing.mix(key)) & capacityMask)]) != free) {
                    while (true) {
                        if ((newKeys[(index = (index - 1) & capacityMask)]) == free) {
                            break;
                        }
                    }
                }
                newKeys[index] = key;
                newVals[index] = vals[i];
            }
        }
    }
    
    @Override
    public T put(Long key, T value) {
        int index = insert(key, value);
        if (index < 0) {
            return null;
        } else {
            T[] vals = values;
            T prevValue = vals[index];
            vals[index] = value;
            return prevValue;
        }
    }
    
    @Override
    public T put(long key, T value) {
        int index = insert(key, value);
        if (index < 0) {
            return null;
        } else {
            T[] vals = values;
            T prevValue = vals[index];
            vals[index] = value;
            return prevValue;
        }
    }
    
    public void justPut(long key, T value) {
        int index = insert(key, value);
        if (index < 0) {
            return ;
        } else {
            values[index] = value;
            return ;
        }
    }
    
    class NoRemovedIterator implements LongIterator {
        long[] keys;
        
        final long free;
        
        final int capacityMask;
        
        int index = -1;
        
        int nextIndex;
        
        long next;
        
        NoRemovedIterator() {
            long[] keys = KolobokeLongEntityMap.NoRemovedIterator.this.keys = set;
            capacityMask = (keys.length) - 1;
            long free = this.free = freeValue;
            int nextI = keys.length;
            while ((--nextI) >= 0) {
                long key;
                if ((key = keys[nextI]) != free) {
                    next = key;
                    break;
                }
            }
            nextIndex = nextI;
        }
        
        @Override
        public long nextLong() {
            int nextI;
            if ((nextI = nextIndex) >= 0) {
                index = nextI;
                long[] keys = KolobokeLongEntityMap.NoRemovedIterator.this.keys;
                long free = KolobokeLongEntityMap.NoRemovedIterator.this.free;
                long prev = next;
                while ((--nextI) >= 0) {
                    long key;
                    if ((key = keys[nextI]) != free) {
                        next = key;
                        break;
                    }
                }
                nextIndex = nextI;
                return prev;
            } else {
                throw new NoSuchElementException();
            }
        }
        
        @Override
        public void forEachRemaining(Consumer<? super Long> action) {
            if (action == null)
                throw new NullPointerException();
            
            long[] keys = KolobokeLongEntityMap.NoRemovedIterator.this.keys;
            long free = KolobokeLongEntityMap.NoRemovedIterator.this.free;
            int nextI = nextIndex;
            for (int i = nextI; i >= 0; i--) {
                long key;
                if ((key = keys[i]) != free) {
                    action.accept(key);
                }
            }
            if (nextI != (nextIndex)) {
                throw new ConcurrentModificationException();
            }
            index = nextIndex = -1;
        }
        
        @Override
        public void forEachRemaining(LongConsumer action) {
            if (action == null)
                throw new NullPointerException();
            
            long[] keys = KolobokeLongEntityMap.NoRemovedIterator.this.keys;
            long free = KolobokeLongEntityMap.NoRemovedIterator.this.free;
            int nextI = nextIndex;
            for (int i = nextI; i >= 0; i--) {
                long key;
                if ((key = keys[i]) != free) {
                    action.accept(key);
                }
            }
            if (nextI != (nextIndex)) {
                throw new ConcurrentModificationException();
            }
            index = nextIndex = -1;
        }
        
        @Override
        public boolean hasNext() {
            return (nextIndex) >= 0;
        }
        
        @Override
        public Long next() {
            return nextLong();
        }
        
        @Override
        public void remove() {
            int index;
            if ((index = KolobokeLongEntityMap.NoRemovedIterator.this.index) >= 0) {
                KolobokeLongEntityMap.NoRemovedIterator.this.index = -1;
                long[] keys = KolobokeLongEntityMap.NoRemovedIterator.this.keys;
                if (keys == (set)) {
                    int capacityMask = KolobokeLongEntityMap.NoRemovedIterator.this.capacityMask;
                    int indexToRemove = index;
                    int indexToShift = indexToRemove;
                    int shiftDistance = 1;
                    while (true) {
                        indexToShift = (indexToShift - 1) & capacityMask;
                        long keyToShift;
                        if ((keyToShift = keys[indexToShift]) == (free)) {
                            break;
                        }
                        if ((((LHash.SeparateKVLongKeyMixing.mix(keyToShift)) - indexToShift) & capacityMask) >= shiftDistance) {
                            if ((KolobokeLongEntityMap.NoRemovedIterator.this.keys) == keys) {
                                if (indexToShift > indexToRemove) {
                                    int slotsToCopy;
                                    if ((slotsToCopy = (nextIndex) + 1) > 0) {
                                        KolobokeLongEntityMap.NoRemovedIterator.this.keys = Arrays.copyOf(keys, slotsToCopy);
                                        if (indexToRemove < slotsToCopy) {
                                            KolobokeLongEntityMap.NoRemovedIterator.this.keys[indexToRemove] = free;
                                        }
                                    }
                                } else if (indexToRemove == index) {
                                    KolobokeLongEntityMap.NoRemovedIterator.this.nextIndex = index;
                                    if (indexToShift < (index - 1)) {
                                        KolobokeLongEntityMap.NoRemovedIterator.this.next = keyToShift;
                                    }
                                }
                            }
                            keys[indexToRemove] = keyToShift;
                            indexToRemove = indexToShift;
                            shiftDistance = 1;
                        } else {
                            shiftDistance++;
                            if (indexToShift == (1 + index)) {
                                throw new ConcurrentModificationException();
                            }
                        }
                    }
                    keys[indexToRemove] = free;
                    postRemoveHook();
                } else {
                    justRemove(keys[index]);
                }
            } else {
                throw new IllegalStateException();
            }
        }
    }
    
    @Override
    public void putAll(@Nonnull
                               Map<? extends Long, ? extends T> m) {
        if (KolobokeLongEntityMap.identical(KolobokeLongEntityMap.this, m))
            throw new IllegalArgumentException();
        
        long maxPossibleSize = (sizeAsLong()) + (Containers.sizeAsLong(m));
        ensureCapacity(maxPossibleSize);
        if (m instanceof LongObjMap) {
            if ((InternalLongObjMapOps.class.isAssignableFrom(getClass())) && (m instanceof InternalLongObjMapOps)) {
                ((InternalLongObjMapOps) (m)).reversePutAllTo(((InternalLongObjMapOps<? super T>) (InternalLongObjMapOps.class.cast(KolobokeLongEntityMap.this))));
            } else {
                ((LongObjMap) (m)).forEach(new LongObjConsumer<T>() {
                    @Override
                    public void accept(long key, T value) {
                        justPut(key, value);
                    }
                });
            }
        } else {
            for (Map.Entry<? extends Long, ? extends T> e : m.entrySet()) {
                justPut(e.getKey(), e.getValue());
            }
        }
    }
    
    class NoRemovedCursor implements LongCursor {
        long[] keys;
        
        final long free;
        
        final int capacityMask;
        
        int index;
        
        long curKey;
        
        NoRemovedCursor() {
            long[] keys = KolobokeLongEntityMap.NoRemovedCursor.this.keys = set;
            capacityMask = (keys.length) - 1;
            index = keys.length;
            long free = this.free = freeValue;
            curKey = free;
        }
        
        @Override
        public void forEachForward(LongConsumer action) {
            if (action == null)
                throw new NullPointerException();
            
            long[] keys = KolobokeLongEntityMap.NoRemovedCursor.this.keys;
            long free = KolobokeLongEntityMap.NoRemovedCursor.this.free;
            int index = KolobokeLongEntityMap.NoRemovedCursor.this.index;
            for (int i = index - 1; i >= 0; i--) {
                long key;
                if ((key = keys[i]) != free) {
                    action.accept(key);
                }
            }
            if (index != (KolobokeLongEntityMap.NoRemovedCursor.this.index)) {
                throw new ConcurrentModificationException();
            }
            KolobokeLongEntityMap.NoRemovedCursor.this.index = -1;
            curKey = free;
        }
        
        @Override
        public long elem() {
            long curKey;
            if ((curKey = KolobokeLongEntityMap.NoRemovedCursor.this.curKey) != (free)) {
                return curKey;
            } else {
                throw new IllegalStateException();
            }
        }
        
        @Override
        public boolean moveNext() {
            long[] keys = KolobokeLongEntityMap.NoRemovedCursor.this.keys;
            long free = KolobokeLongEntityMap.NoRemovedCursor.this.free;
            for (int i = (index) - 1; i >= 0; i--) {
                long key;
                if ((key = keys[i]) != free) {
                    index = i;
                    curKey = key;
                    return true;
                }
            }
            curKey = free;
            index = -1;
            return false;
        }
        
        @Override
        public void remove() {
            long curKey;
            long free;
            if ((curKey = KolobokeLongEntityMap.NoRemovedCursor.this.curKey) != (free = KolobokeLongEntityMap.NoRemovedCursor.this.free)) {
                KolobokeLongEntityMap.NoRemovedCursor.this.curKey = free;
                int index = KolobokeLongEntityMap.NoRemovedCursor.this.index;
                long[] keys = KolobokeLongEntityMap.NoRemovedCursor.this.keys;
                if (keys == (set)) {
                    int capacityMask = KolobokeLongEntityMap.NoRemovedCursor.this.capacityMask;
                    int indexToRemove = index;
                    int indexToShift = indexToRemove;
                    int shiftDistance = 1;
                    while (true) {
                        indexToShift = (indexToShift - 1) & capacityMask;
                        long keyToShift;
                        if ((keyToShift = keys[indexToShift]) == free) {
                            break;
                        }
                        if ((((LHash.SeparateKVLongKeyMixing.mix(keyToShift)) - indexToShift) & capacityMask) >= shiftDistance) {
                            if ((KolobokeLongEntityMap.NoRemovedCursor.this.keys) == keys) {
                                if (indexToShift > indexToRemove) {
                                    int slotsToCopy;
                                    if ((slotsToCopy = index) > 0) {
                                        KolobokeLongEntityMap.NoRemovedCursor.this.keys = Arrays.copyOf(keys, slotsToCopy);
                                        if (indexToRemove < slotsToCopy) {
                                            KolobokeLongEntityMap.NoRemovedCursor.this.keys[indexToRemove] = free;
                                        }
                                    }
                                } else if (indexToRemove == index) {
                                    KolobokeLongEntityMap.NoRemovedCursor.this.index = ++index;
                                }
                            }
                            keys[indexToRemove] = keyToShift;
                            indexToRemove = indexToShift;
                            shiftDistance = 1;
                        } else {
                            shiftDistance++;
                            if (indexToShift == (1 + index)) {
                                throw new ConcurrentModificationException();
                            }
                        }
                    }
                    keys[indexToRemove] = free;
                    postRemoveHook();
                } else {
                    justRemove(curKey);
                }
            } else {
                throw new IllegalStateException();
            }
        }
    }
    
    @Override
    public void clear() {
        doClear();
    }
    
    private void doClear() {
        _MutableLHashSeparateKVLongObjMapSO_clear();
    }
    
    void removeAt(int index) {
        long free = freeValue;
        long[] keys = set;
        T[] vals = values;
        int capacityMask = (keys.length) - 1;
        int indexToRemove = index;
        int indexToShift = indexToRemove;
        int shiftDistance = 1;
        while (true) {
            indexToShift = (indexToShift - 1) & capacityMask;
            long keyToShift;
            if ((keyToShift = keys[indexToShift]) == free) {
                break;
            }
            if ((((LHash.SeparateKVLongKeyMixing.mix(keyToShift)) - indexToShift) & capacityMask) >= shiftDistance) {
                keys[indexToRemove] = keyToShift;
                vals[indexToRemove] = vals[indexToShift];
                indexToRemove = indexToShift;
                shiftDistance = 1;
            } else {
                shiftDistance++;
                if (indexToShift == (1 + index)) {
                    throw new ConcurrentModificationException();
                }
            }
        }
        keys[indexToRemove] = free;
        vals[indexToRemove] = null;
        postRemoveHook();
    }
    
    @Override
    public T remove(Object key) {
        long k = ((Long) (key));
        long free;
        if (k != (free = freeValue)) {
            long[] keys = set;
            int capacityMask = (keys.length) - 1;
            int index;
            long cur;
            keyPresent : if ((cur = keys[(index = (LHash.SeparateKVLongKeyMixing.mix(k)) & capacityMask)]) != k) {
                if (cur == free) {
                    return null;
                } else {
                    while (true) {
                        if ((cur = keys[(index = (index - 1) & capacityMask)]) == k) {
                            break keyPresent;
                        } else if (cur == free) {
                            return null;
                        }
                    }
                }
            }
            T[] vals = values;
            T val = vals[index];
            int indexToRemove = index;
            int indexToShift = indexToRemove;
            int shiftDistance = 1;
            while (true) {
                indexToShift = (indexToShift - 1) & capacityMask;
                long keyToShift;
                if ((keyToShift = keys[indexToShift]) == free) {
                    break;
                }
                if ((((LHash.SeparateKVLongKeyMixing.mix(keyToShift)) - indexToShift) & capacityMask) >= shiftDistance) {
                    keys[indexToRemove] = keyToShift;
                    vals[indexToRemove] = vals[indexToShift];
                    indexToRemove = indexToShift;
                    shiftDistance = 1;
                } else {
                    shiftDistance++;
                    if (indexToShift == (1 + index)) {
                        throw new ConcurrentModificationException();
                    }
                }
            }
            keys[indexToRemove] = free;
            vals[indexToRemove] = null;
            postRemoveHook();
            return val;
        } else {
            return null;
        }
    }
    
    public boolean justRemove(long key) {
        long free;
        if (key != (free = freeValue)) {
            long[] keys = set;
            int capacityMask = (keys.length) - 1;
            int index;
            long cur;
            keyPresent : if ((cur = keys[(index = (LHash.SeparateKVLongKeyMixing.mix(key)) & capacityMask)]) != key) {
                if (cur == free) {
                    return false;
                } else {
                    while (true) {
                        if ((cur = keys[(index = (index - 1) & capacityMask)]) == key) {
                            break keyPresent;
                        } else if (cur == free) {
                            return false;
                        }
                    }
                }
            }
            T[] vals = values;
            int indexToRemove = index;
            int indexToShift = indexToRemove;
            int shiftDistance = 1;
            while (true) {
                indexToShift = (indexToShift - 1) & capacityMask;
                long keyToShift;
                if ((keyToShift = keys[indexToShift]) == free) {
                    break;
                }
                if ((((LHash.SeparateKVLongKeyMixing.mix(keyToShift)) - indexToShift) & capacityMask) >= shiftDistance) {
                    keys[indexToRemove] = keyToShift;
                    vals[indexToRemove] = vals[indexToShift];
                    indexToRemove = indexToShift;
                    shiftDistance = 1;
                } else {
                    shiftDistance++;
                    if (indexToShift == (1 + index)) {
                        throw new ConcurrentModificationException();
                    }
                }
            }
            keys[indexToRemove] = free;
            vals[indexToRemove] = null;
            postRemoveHook();
            return true;
        } else {
            return false;
        }
    }
    
    @Override
    public T remove(long key) {
        long free;
        if (key != (free = freeValue)) {
            long[] keys = set;
            int capacityMask = (keys.length) - 1;
            int index;
            long cur;
            keyPresent : if ((cur = keys[(index = (LHash.SeparateKVLongKeyMixing.mix(key)) & capacityMask)]) != key) {
                if (cur == free) {
                    return null;
                } else {
                    while (true) {
                        if ((cur = keys[(index = (index - 1) & capacityMask)]) == key) {
                            break keyPresent;
                        } else if (cur == free) {
                            return null;
                        }
                    }
                }
            }
            T[] vals = values;
            T val = vals[index];
            int indexToRemove = index;
            int indexToShift = indexToRemove;
            int shiftDistance = 1;
            while (true) {
                indexToShift = (indexToShift - 1) & capacityMask;
                long keyToShift;
                if ((keyToShift = keys[indexToShift]) == free) {
                    break;
                }
                if ((((LHash.SeparateKVLongKeyMixing.mix(keyToShift)) - indexToShift) & capacityMask) >= shiftDistance) {
                    keys[indexToRemove] = keyToShift;
                    vals[indexToRemove] = vals[indexToShift];
                    indexToRemove = indexToShift;
                    shiftDistance = 1;
                } else {
                    shiftDistance++;
                    if (indexToShift == (1 + index)) {
                        throw new ConcurrentModificationException();
                    }
                }
            }
            keys[indexToRemove] = free;
            vals[indexToRemove] = null;
            postRemoveHook();
            return val;
        } else {
            return null;
        }
    }
    
    public boolean remove(long key, Object value) {
        long free;
        if (key != (free = freeValue)) {
            long[] keys = set;
            int capacityMask = (keys.length) - 1;
            int index;
            long cur;
            keyPresent : if ((cur = keys[(index = (LHash.SeparateKVLongKeyMixing.mix(key)) & capacityMask)]) != key) {
                if (cur == free) {
                    return false;
                } else {
                    while (true) {
                        if ((cur = keys[(index = (index - 1) & capacityMask)]) == key) {
                            break keyPresent;
                        } else if (cur == free) {
                            return false;
                        }
                    }
                }
            }
            T[] vals = values;
            if (nullableValueEquals(vals[index], ((T) (value)))) {
                int indexToRemove = index;
                int indexToShift = indexToRemove;
                int shiftDistance = 1;
                while (true) {
                    indexToShift = (indexToShift - 1) & capacityMask;
                    long keyToShift;
                    if ((keyToShift = keys[indexToShift]) == free) {
                        break;
                    }
                    if ((((LHash.SeparateKVLongKeyMixing.mix(keyToShift)) - indexToShift) & capacityMask) >= shiftDistance) {
                        keys[indexToRemove] = keyToShift;
                        vals[indexToRemove] = vals[indexToShift];
                        indexToRemove = indexToShift;
                        shiftDistance = 1;
                    } else {
                        shiftDistance++;
                        if (indexToShift == (1 + index)) {
                            throw new ConcurrentModificationException();
                        }
                    }
                }
                keys[indexToRemove] = free;
                vals[indexToRemove] = null;
                postRemoveHook();
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }
    
    public boolean removeIf(Predicate<? super Long> filter) {
        if (filter == null)
            throw new NullPointerException();
        
        if (KolobokeLongEntityMap.this.isEmpty())
            return false;
        
        boolean changed = false;
        long free = freeValue;
        long[] keys = set;
        int capacityMask = (keys.length) - 1;
        int firstDelayedRemoved = -1;
        long delayedRemoved = 0L;
        T[] vals = values;
        for (int i = (keys.length) - 1; i >= 0; i--) {
            long key;
            if ((key = keys[i]) != free) {
                if (filter.test(key)) {
                    closeDeletion : if (firstDelayedRemoved < 0) {
                        int indexToRemove = i;
                        int indexToShift = indexToRemove;
                        int shiftDistance = 1;
                        while (true) {
                            indexToShift = (indexToShift - 1) & capacityMask;
                            long keyToShift;
                            if ((keyToShift = keys[indexToShift]) == free) {
                                break;
                            }
                            if ((((LHash.SeparateKVLongKeyMixing.mix(keyToShift)) - indexToShift) & capacityMask) >= shiftDistance) {
                                if (indexToShift > indexToRemove) {
                                    firstDelayedRemoved = i;
                                    delayedRemoved = key;
                                    keys[indexToRemove] = key;
                                    break closeDeletion;
                                }
                                if (indexToRemove == i) {
                                    i++;
                                }
                                keys[indexToRemove] = keyToShift;
                                vals[indexToRemove] = vals[indexToShift];
                                indexToRemove = indexToShift;
                                shiftDistance = 1;
                            } else {
                                shiftDistance++;
                                if (indexToShift == (1 + i)) {
                                    throw new ConcurrentModificationException();
                                }
                            }
                        }
                        keys[indexToRemove] = free;
                        vals[indexToRemove] = null;
                        postRemoveHook();
                    } else {
                        keys[i] = delayedRemoved;
                    }
                    changed = true;
                }
            }
        }
        if (firstDelayedRemoved >= 0) {
            closeDelayedRemoved(firstDelayedRemoved, delayedRemoved);
        }
        return changed;
    }
    
    public boolean removeIf(LongPredicate filter) {
        if (filter == null)
            throw new NullPointerException();
        
        if (KolobokeLongEntityMap.this.isEmpty())
            return false;
        
        boolean changed = false;
        long free = freeValue;
        long[] keys = set;
        int capacityMask = (keys.length) - 1;
        int firstDelayedRemoved = -1;
        long delayedRemoved = 0L;
        T[] vals = values;
        for (int i = (keys.length) - 1; i >= 0; i--) {
            long key;
            if ((key = keys[i]) != free) {
                if (filter.test(key)) {
                    closeDeletion : if (firstDelayedRemoved < 0) {
                        int indexToRemove = i;
                        int indexToShift = indexToRemove;
                        int shiftDistance = 1;
                        while (true) {
                            indexToShift = (indexToShift - 1) & capacityMask;
                            long keyToShift;
                            if ((keyToShift = keys[indexToShift]) == free) {
                                break;
                            }
                            if ((((LHash.SeparateKVLongKeyMixing.mix(keyToShift)) - indexToShift) & capacityMask) >= shiftDistance) {
                                if (indexToShift > indexToRemove) {
                                    firstDelayedRemoved = i;
                                    delayedRemoved = key;
                                    keys[indexToRemove] = key;
                                    break closeDeletion;
                                }
                                if (indexToRemove == i) {
                                    i++;
                                }
                                keys[indexToRemove] = keyToShift;
                                vals[indexToRemove] = vals[indexToShift];
                                indexToRemove = indexToShift;
                                shiftDistance = 1;
                            } else {
                                shiftDistance++;
                                if (indexToShift == (1 + i)) {
                                    throw new ConcurrentModificationException();
                                }
                            }
                        }
                        keys[indexToRemove] = free;
                        vals[indexToRemove] = null;
                        postRemoveHook();
                    } else {
                        keys[i] = delayedRemoved;
                    }
                    changed = true;
                }
            }
        }
        if (firstDelayedRemoved >= 0) {
            closeDelayedRemoved(firstDelayedRemoved, delayedRemoved);
        }
        return changed;
    }
    
    public boolean removeAll(@Nonnull
                                     HashLongSet thisC, @Nonnull
                                     Collection<?> c) {
        if (thisC == ((Object) (c)))
            throw new IllegalArgumentException();
        
        if ((KolobokeLongEntityMap.this.isEmpty()) || (c.isEmpty()))
            return false;
        
        boolean changed = false;
        long free = freeValue;
        long[] keys = set;
        int capacityMask = (keys.length) - 1;
        int firstDelayedRemoved = -1;
        long delayedRemoved = 0L;
        T[] vals = values;
        for (int i = (keys.length) - 1; i >= 0; i--) {
            long key;
            if ((key = keys[i]) != free) {
                if (c.contains(key)) {
                    closeDeletion : if (firstDelayedRemoved < 0) {
                        int indexToRemove = i;
                        int indexToShift = indexToRemove;
                        int shiftDistance = 1;
                        while (true) {
                            indexToShift = (indexToShift - 1) & capacityMask;
                            long keyToShift;
                            if ((keyToShift = keys[indexToShift]) == free) {
                                break;
                            }
                            if ((((LHash.SeparateKVLongKeyMixing.mix(keyToShift)) - indexToShift) & capacityMask) >= shiftDistance) {
                                if (indexToShift > indexToRemove) {
                                    firstDelayedRemoved = i;
                                    delayedRemoved = key;
                                    keys[indexToRemove] = key;
                                    break closeDeletion;
                                }
                                if (indexToRemove == i) {
                                    i++;
                                }
                                keys[indexToRemove] = keyToShift;
                                vals[indexToRemove] = vals[indexToShift];
                                indexToRemove = indexToShift;
                                shiftDistance = 1;
                            } else {
                                shiftDistance++;
                                if (indexToShift == (1 + i)) {
                                    throw new ConcurrentModificationException();
                                }
                            }
                        }
                        keys[indexToRemove] = free;
                        vals[indexToRemove] = null;
                        postRemoveHook();
                    } else {
                        keys[i] = delayedRemoved;
                    }
                    changed = true;
                }
            }
        }
        if (firstDelayedRemoved >= 0) {
            closeDelayedRemoved(firstDelayedRemoved, delayedRemoved);
        }
        return changed;
    }
    
    boolean removeAll(@Nonnull
                              HashLongSet thisC, @Nonnull
                              LongCollection c) {
        if (thisC == ((Object) (c)))
            throw new IllegalArgumentException();
        
        if ((KolobokeLongEntityMap.this.isEmpty()) || (c.isEmpty()))
            return false;
        
        boolean changed = false;
        long free = freeValue;
        long[] keys = set;
        int capacityMask = (keys.length) - 1;
        int firstDelayedRemoved = -1;
        long delayedRemoved = 0L;
        T[] vals = values;
        for (int i = (keys.length) - 1; i >= 0; i--) {
            long key;
            if ((key = keys[i]) != free) {
                if (c.contains(key)) {
                    closeDeletion : if (firstDelayedRemoved < 0) {
                        int indexToRemove = i;
                        int indexToShift = indexToRemove;
                        int shiftDistance = 1;
                        while (true) {
                            indexToShift = (indexToShift - 1) & capacityMask;
                            long keyToShift;
                            if ((keyToShift = keys[indexToShift]) == free) {
                                break;
                            }
                            if ((((LHash.SeparateKVLongKeyMixing.mix(keyToShift)) - indexToShift) & capacityMask) >= shiftDistance) {
                                if (indexToShift > indexToRemove) {
                                    firstDelayedRemoved = i;
                                    delayedRemoved = key;
                                    keys[indexToRemove] = key;
                                    break closeDeletion;
                                }
                                if (indexToRemove == i) {
                                    i++;
                                }
                                keys[indexToRemove] = keyToShift;
                                vals[indexToRemove] = vals[indexToShift];
                                indexToRemove = indexToShift;
                                shiftDistance = 1;
                            } else {
                                shiftDistance++;
                                if (indexToShift == (1 + i)) {
                                    throw new ConcurrentModificationException();
                                }
                            }
                        }
                        keys[indexToRemove] = free;
                        vals[indexToRemove] = null;
                        postRemoveHook();
                    } else {
                        keys[i] = delayedRemoved;
                    }
                    changed = true;
                }
            }
        }
        if (firstDelayedRemoved >= 0) {
            closeDelayedRemoved(firstDelayedRemoved, delayedRemoved);
        }
        return changed;
    }
    
    public boolean retainAll(@Nonnull
                                     HashLongSet thisC, @Nonnull
                                     Collection<?> c) {
        if (c instanceof LongCollection)
            return retainAll(thisC, ((LongCollection) (c)));
        
        if (thisC == ((Object) (c)))
            throw new IllegalArgumentException();
        
        if (KolobokeLongEntityMap.this.isEmpty())
            return false;
        
        if (c.isEmpty()) {
            clear();
            return true;
        }
        boolean changed = false;
        long free = freeValue;
        long[] keys = set;
        int capacityMask = (keys.length) - 1;
        int firstDelayedRemoved = -1;
        long delayedRemoved = 0L;
        T[] vals = values;
        for (int i = (keys.length) - 1; i >= 0; i--) {
            long key;
            if ((key = keys[i]) != free) {
                if (!(c.contains(key))) {
                    closeDeletion : if (firstDelayedRemoved < 0) {
                        int indexToRemove = i;
                        int indexToShift = indexToRemove;
                        int shiftDistance = 1;
                        while (true) {
                            indexToShift = (indexToShift - 1) & capacityMask;
                            long keyToShift;
                            if ((keyToShift = keys[indexToShift]) == free) {
                                break;
                            }
                            if ((((LHash.SeparateKVLongKeyMixing.mix(keyToShift)) - indexToShift) & capacityMask) >= shiftDistance) {
                                if (indexToShift > indexToRemove) {
                                    firstDelayedRemoved = i;
                                    delayedRemoved = key;
                                    keys[indexToRemove] = key;
                                    break closeDeletion;
                                }
                                if (indexToRemove == i) {
                                    i++;
                                }
                                keys[indexToRemove] = keyToShift;
                                vals[indexToRemove] = vals[indexToShift];
                                indexToRemove = indexToShift;
                                shiftDistance = 1;
                            } else {
                                shiftDistance++;
                                if (indexToShift == (1 + i)) {
                                    throw new ConcurrentModificationException();
                                }
                            }
                        }
                        keys[indexToRemove] = free;
                        vals[indexToRemove] = null;
                        postRemoveHook();
                    } else {
                        keys[i] = delayedRemoved;
                    }
                    changed = true;
                }
            }
        }
        if (firstDelayedRemoved >= 0) {
            closeDelayedRemoved(firstDelayedRemoved, delayedRemoved);
        }
        return changed;
    }
    
    private boolean retainAll(@Nonnull
                                      HashLongSet thisC, @Nonnull
                                      LongCollection c) {
        if (thisC == ((Object) (c)))
            throw new IllegalArgumentException();
        
        if (KolobokeLongEntityMap.this.isEmpty())
            return false;
        
        if (c.isEmpty()) {
            clear();
            return true;
        }
        boolean changed = false;
        long free = freeValue;
        long[] keys = set;
        int capacityMask = (keys.length) - 1;
        int firstDelayedRemoved = -1;
        long delayedRemoved = 0L;
        T[] vals = values;
        for (int i = (keys.length) - 1; i >= 0; i--) {
            long key;
            if ((key = keys[i]) != free) {
                if (!(c.contains(key))) {
                    closeDeletion : if (firstDelayedRemoved < 0) {
                        int indexToRemove = i;
                        int indexToShift = indexToRemove;
                        int shiftDistance = 1;
                        while (true) {
                            indexToShift = (indexToShift - 1) & capacityMask;
                            long keyToShift;
                            if ((keyToShift = keys[indexToShift]) == free) {
                                break;
                            }
                            if ((((LHash.SeparateKVLongKeyMixing.mix(keyToShift)) - indexToShift) & capacityMask) >= shiftDistance) {
                                if (indexToShift > indexToRemove) {
                                    firstDelayedRemoved = i;
                                    delayedRemoved = key;
                                    keys[indexToRemove] = key;
                                    break closeDeletion;
                                }
                                if (indexToRemove == i) {
                                    i++;
                                }
                                keys[indexToRemove] = keyToShift;
                                vals[indexToRemove] = vals[indexToShift];
                                indexToRemove = indexToShift;
                                shiftDistance = 1;
                            } else {
                                shiftDistance++;
                                if (indexToShift == (1 + i)) {
                                    throw new ConcurrentModificationException();
                                }
                            }
                        }
                        keys[indexToRemove] = free;
                        vals[indexToRemove] = null;
                        postRemoveHook();
                    } else {
                        keys[i] = delayedRemoved;
                    }
                    changed = true;
                }
            }
        }
        if (firstDelayedRemoved >= 0) {
            closeDelayedRemoved(firstDelayedRemoved, delayedRemoved);
        }
        return changed;
    }
    
    void closeDelayedRemoved(int firstDelayedRemoved, long delayedRemoved) {
        long free = freeValue;
        long[] keys = set;
        T[] vals = values;
        int capacityMask = (keys.length) - 1;
        for (int i = firstDelayedRemoved; i >= 0; i--) {
            if ((keys[i]) == delayedRemoved) {
                int indexToRemove = i;
                int indexToShift = indexToRemove;
                int shiftDistance = 1;
                while (true) {
                    indexToShift = (indexToShift - 1) & capacityMask;
                    long keyToShift;
                    if ((keyToShift = keys[indexToShift]) == free) {
                        break;
                    }
                    if ((keyToShift != delayedRemoved) && ((((LHash.SeparateKVLongKeyMixing.mix(keyToShift)) - indexToShift) & capacityMask) >= shiftDistance)) {
                        keys[indexToRemove] = keyToShift;
                        vals[indexToRemove] = vals[indexToShift];
                        indexToRemove = indexToShift;
                        shiftDistance = 1;
                    } else {
                        shiftDistance++;
                        if (indexToShift == (1 + i)) {
                            throw new ConcurrentModificationException();
                        }
                    }
                }
                keys[indexToRemove] = free;
                vals[indexToRemove] = null;
                postRemoveHook();
            }
        }
    }
    
    public LongIterator iterator() {
        return new NoRemovedKeyIterator();
    }
    
    public LongCursor setCursor() {
        return new NoRemovedKeyCursor();
    }
    
    class NoRemovedKeyIterator extends KolobokeLongEntityMap.NoRemovedIterator {
        T[] vals;
        
        private NoRemovedKeyIterator() {
            super();
            vals = values;
        }
        
        @Override
        public void remove() {
            int index;
            if ((index = KolobokeLongEntityMap.NoRemovedKeyIterator.this.index) >= 0) {
                KolobokeLongEntityMap.NoRemovedKeyIterator.this.index = -1;
                long[] keys = KolobokeLongEntityMap.NoRemovedKeyIterator.this.keys;
                T[] vals = KolobokeLongEntityMap.NoRemovedKeyIterator.this.vals;
                if (keys == (set)) {
                    int capacityMask = KolobokeLongEntityMap.NoRemovedKeyIterator.this.capacityMask;
                    int indexToRemove = index;
                    int indexToShift = indexToRemove;
                    int shiftDistance = 1;
                    while (true) {
                        indexToShift = (indexToShift - 1) & capacityMask;
                        long keyToShift;
                        if ((keyToShift = keys[indexToShift]) == (free)) {
                            break;
                        }
                        if ((((LHash.SeparateKVLongKeyMixing.mix(keyToShift)) - indexToShift) & capacityMask) >= shiftDistance) {
                            if ((KolobokeLongEntityMap.NoRemovedKeyIterator.this.keys) == keys) {
                                if (indexToShift > indexToRemove) {
                                    int slotsToCopy;
                                    if ((slotsToCopy = (nextIndex) + 1) > 0) {
                                        KolobokeLongEntityMap.NoRemovedKeyIterator.this.keys = Arrays.copyOf(keys, slotsToCopy);
                                        KolobokeLongEntityMap.NoRemovedKeyIterator.this.vals = Arrays.copyOf(vals, slotsToCopy);
                                        if (indexToRemove < slotsToCopy) {
                                            KolobokeLongEntityMap.NoRemovedKeyIterator.this.keys[indexToRemove] = free;
                                            KolobokeLongEntityMap.NoRemovedKeyIterator.this.vals[indexToRemove] = null;
                                        }
                                    }
                                } else if (indexToRemove == index) {
                                    KolobokeLongEntityMap.NoRemovedKeyIterator.this.nextIndex = index;
                                    if (indexToShift < (index - 1)) {
                                        KolobokeLongEntityMap.NoRemovedKeyIterator.this.next = keyToShift;
                                    }
                                }
                            }
                            keys[indexToRemove] = keyToShift;
                            vals[indexToRemove] = vals[indexToShift];
                            indexToRemove = indexToShift;
                            shiftDistance = 1;
                        } else {
                            shiftDistance++;
                            if (indexToShift == (1 + index)) {
                                throw new ConcurrentModificationException();
                            }
                        }
                    }
                    keys[indexToRemove] = free;
                    vals[indexToRemove] = null;
                    postRemoveHook();
                } else {
                    justRemove(keys[index]);
                    vals[index] = null;
                }
            } else {
                throw new IllegalStateException();
            }
        }
    }
    
    class NoRemovedKeyCursor extends KolobokeLongEntityMap.NoRemovedCursor {
        T[] vals;
        
        private NoRemovedKeyCursor() {
            super();
            vals = values;
        }
        
        @Override
        public void remove() {
            long curKey;
            long free;
            if ((curKey = KolobokeLongEntityMap.NoRemovedKeyCursor.this.curKey) != (free = KolobokeLongEntityMap.NoRemovedKeyCursor.this.free)) {
                KolobokeLongEntityMap.NoRemovedKeyCursor.this.curKey = free;
                int index = KolobokeLongEntityMap.NoRemovedKeyCursor.this.index;
                long[] keys = KolobokeLongEntityMap.NoRemovedKeyCursor.this.keys;
                T[] vals = KolobokeLongEntityMap.NoRemovedKeyCursor.this.vals;
                if (keys == (set)) {
                    int capacityMask = KolobokeLongEntityMap.NoRemovedKeyCursor.this.capacityMask;
                    int indexToRemove = index;
                    int indexToShift = indexToRemove;
                    int shiftDistance = 1;
                    while (true) {
                        indexToShift = (indexToShift - 1) & capacityMask;
                        long keyToShift;
                        if ((keyToShift = keys[indexToShift]) == free) {
                            break;
                        }
                        if ((((LHash.SeparateKVLongKeyMixing.mix(keyToShift)) - indexToShift) & capacityMask) >= shiftDistance) {
                            if ((KolobokeLongEntityMap.NoRemovedKeyCursor.this.keys) == keys) {
                                if (indexToShift > indexToRemove) {
                                    int slotsToCopy;
                                    if ((slotsToCopy = index) > 0) {
                                        KolobokeLongEntityMap.NoRemovedKeyCursor.this.keys = Arrays.copyOf(keys, slotsToCopy);
                                        KolobokeLongEntityMap.NoRemovedKeyCursor.this.vals = Arrays.copyOf(vals, slotsToCopy);
                                        if (indexToRemove < slotsToCopy) {
                                            KolobokeLongEntityMap.NoRemovedKeyCursor.this.keys[indexToRemove] = free;
                                            KolobokeLongEntityMap.NoRemovedKeyCursor.this.vals[indexToRemove] = null;
                                        }
                                    }
                                } else if (indexToRemove == index) {
                                    KolobokeLongEntityMap.NoRemovedKeyCursor.this.index = ++index;
                                }
                            }
                            keys[indexToRemove] = keyToShift;
                            vals[indexToRemove] = vals[indexToShift];
                            indexToRemove = indexToShift;
                            shiftDistance = 1;
                        } else {
                            shiftDistance++;
                            if (indexToShift == (1 + index)) {
                                throw new ConcurrentModificationException();
                            }
                        }
                    }
                    keys[indexToRemove] = free;
                    vals[indexToRemove] = null;
                    postRemoveHook();
                } else {
                    justRemove(curKey);
                    vals[index] = null;
                }
            } else {
                throw new IllegalStateException();
            }
        }
    }
    
    class EntryView extends AbstractSetView<Map.Entry<Long, T>> implements HashObjSet<Map.Entry<Long, T>> , InternalObjCollectionOps<Map.Entry<Long, T>> { // lgtm[java/inconsistent-equals-and-hashcode]
        @Nonnull
        @Override
        public Equivalence<Map.Entry<Long, T>> equivalence() {
            return Equivalence.entryEquivalence(Equivalence.<Long>defaultEquality(), valueEquivalence());
        }
        
        @Nonnull
        @Override
        public HashConfig hashConfig() {
            return KolobokeLongEntityMap.this.hashConfig();
        }
        
        @Override
        public int size() {
            return size;
        }
        
        @Override
        public double currentLoad() {
            return KolobokeLongEntityMap.this.currentLoad();
        }
        
        @Override
        @SuppressWarnings(value = "unchecked")
        public boolean contains(Object o) {
            try {
                Map.Entry<Long, T> e = ((Map.Entry<Long, T>) (o));
                return containsEntry(e.getKey(), e.getValue());
            } catch (NullPointerException e) {
                return false;
            } catch (ClassCastException e) {
                return false;
            }
        }
        
        @Override
        @Nonnull
        public final Object[] toArray() {
            int size = size();
            Object[] result = new Object[size];
            if (size == 0)
                return result;
            
            int resultIndex = 0;
            long free = freeValue;
            long[] keys = set;
            T[] vals = values;
            for (int i = (keys.length) - 1; i >= 0; i--) {
                long key;
                if ((key = keys[i]) != free) {
                    result[(resultIndex++)] = new MutableEntry(i, key, vals[i]);
                }
            }
            return result;
        }
        
        @Override
        @SuppressWarnings(value = "unchecked")
        @Nonnull
        public final <T2>  T2[] toArray(@Nonnull
                                                T2[] a) {
            int size = size();
            if ((a.length) < size) {
                Class<?> elementType = a.getClass().getComponentType();
                a = ((T2[]) (Array.newInstance(elementType, size)));
            }
            if (size == 0) {
                if ((a.length) > 0)
                    a[0] = null;
                
                return a;
            }
            int resultIndex = 0;
            long free = freeValue;
            long[] keys = set;
            T[] vals = values;
            for (int i = (keys.length) - 1; i >= 0; i--) {
                long key;
                if ((key = keys[i]) != free) {
                    a[(resultIndex++)] = ((T2) (new MutableEntry(i, key, vals[i])));
                }
            }
            if ((a.length) > resultIndex)
                a[resultIndex] = null;
            
            return a;
        }
        
        @Override
        public final void forEach(@Nonnull
                                          Consumer<? super Map.Entry<Long, T>> action) {
            if (action == null)
                throw new NullPointerException();
            
            if (KolobokeLongEntityMap.EntryView.this.isEmpty())
                return ;
            
            long free = freeValue;
            long[] keys = set;
            T[] vals = values;
            for (int i = (keys.length) - 1; i >= 0; i--) {
                long key;
                if ((key = keys[i]) != free) {
                    action.accept(new MutableEntry(i, key, vals[i]));
                }
            }
        }
        
        @Override
        public boolean forEachWhile(@Nonnull
                                            Predicate<? super Map.Entry<Long, T>> predicate) {
            if (predicate == null)
                throw new NullPointerException();
            
            if (KolobokeLongEntityMap.EntryView.this.isEmpty())
                return true;
            
            boolean terminated = false;
            long free = freeValue;
            long[] keys = set;
            T[] vals = values;
            for (int i = (keys.length) - 1; i >= 0; i--) {
                long key;
                if ((key = keys[i]) != free) {
                    if (!(predicate.test(new MutableEntry(i, key, vals[i])))) {
                        terminated = true;
                        break;
                    }
                }
            }
            return !terminated;
        }
        
        @Override
        @Nonnull
        public ObjIterator<Map.Entry<Long, T>> iterator() {
            return new NoRemovedEntryIterator();
        }
        
        @Nonnull
        @Override
        public ObjCursor<Map.Entry<Long, T>> cursor() {
            return new NoRemovedEntryCursor();
        }
        
        @Override
        public final boolean containsAll(@Nonnull
                                                 Collection<?> c) {
            return CommonObjCollectionOps.containsAll(KolobokeLongEntityMap.EntryView.this, c);
        }
        
        @Override
        public final boolean allContainingIn(ObjCollection<?> c) {
            if (KolobokeLongEntityMap.EntryView.this.isEmpty())
                return true;
            
            boolean containsAll = true;
            KolobokeLongEntityMap<T>.ReusableEntry e = new ReusableEntry();
            long free = freeValue;
            long[] keys = set;
            T[] vals = values;
            for (int i = (keys.length) - 1; i >= 0; i--) {
                long key;
                if ((key = keys[i]) != free) {
                    if (!(c.contains(e.with(key, vals[i])))) {
                        containsAll = false;
                        break;
                    }
                }
            }
            return containsAll;
        }
        
        @Override
        public boolean reverseRemoveAllFrom(ObjSet<?> s) {
            if ((KolobokeLongEntityMap.EntryView.this.isEmpty()) || (s.isEmpty()))
                return false;
            
            boolean changed = false;
            KolobokeLongEntityMap<T>.ReusableEntry e = new ReusableEntry();
            long free = freeValue;
            long[] keys = set;
            T[] vals = values;
            for (int i = (keys.length) - 1; i >= 0; i--) {
                long key;
                if ((key = keys[i]) != free) {
                    changed |= s.remove(e.with(key, vals[i]));
                }
            }
            return changed;
        }
        
        @Override
        public final boolean reverseAddAllTo(ObjCollection<? super Map.Entry<Long, T>> c) {
            if (KolobokeLongEntityMap.EntryView.this.isEmpty())
                return false;
            
            boolean changed = false;
            long free = freeValue;
            long[] keys = set;
            T[] vals = values;
            for (int i = (keys.length) - 1; i >= 0; i--) {
                long key;
                if ((key = keys[i]) != free) {
                    changed |= c.add(new MutableEntry(i, key, vals[i]));
                }
            }
            return changed;
        }
        
        public int hashCode() {
            return KolobokeLongEntityMap.this.hashCode();
        }
        
        @Override
        public String toString() {
            if (KolobokeLongEntityMap.EntryView.this.isEmpty())
                return "[]";
            
            StringBuilder sb = new StringBuilder();
            int elementCount = 0;
            long free = freeValue;
            long[] keys = set;
            T[] vals = values;
            for (int i = (keys.length) - 1; i >= 0; i--) {
                long key;
                if ((key = keys[i]) != free) {
                    sb.append(' ');
                    sb.append(key);
                    sb.append('=');
                    Object val = vals[i];
                    sb.append((val != ((Object) (KolobokeLongEntityMap.EntryView.this)) ? val : "(this Collection)"));
                    sb.append(',');
                    if ((++elementCount) == 8) {
                        int expectedLength = (sb.length()) * ((size()) / 8);
                        sb.ensureCapacity((expectedLength + (expectedLength / 2)));
                    }
                }
            }
            sb.setCharAt(0, '[');
            sb.setCharAt(((sb.length()) - 1), ']');
            return sb.toString();
        }
        
        @Override
        public boolean shrink() {
            return KolobokeLongEntityMap.this.shrink();
        }
        
        @Override
        @SuppressWarnings(value = "unchecked")
        public boolean remove(Object o) {
            try {
                Map.Entry<Long, T> e = ((Map.Entry<Long, T>) (o));
                long key = e.getKey();
                T value = e.getValue();
                return KolobokeLongEntityMap.this.remove(key, value);
            } catch (NullPointerException e) {
                return false;
            } catch (ClassCastException e) {
                return false;
            }
        }
        
        @Override
        public final boolean removeIf(@Nonnull
                                              Predicate<? super Map.Entry<Long, T>> filter) {
            if (filter == null)
                throw new NullPointerException();
            
            if (KolobokeLongEntityMap.EntryView.this.isEmpty())
                return false;
            
            boolean changed = false;
            long free = freeValue;
            long[] keys = set;
            int capacityMask = (keys.length) - 1;
            int firstDelayedRemoved = -1;
            long delayedRemoved = 0L;
            T[] vals = values;
            for (int i = (keys.length) - 1; i >= 0; i--) {
                long key;
                if ((key = keys[i]) != free) {
                    if (filter.test(new MutableEntry(i, key, vals[i]))) {
                        closeDeletion : if (firstDelayedRemoved < 0) {
                            int indexToRemove = i;
                            int indexToShift = indexToRemove;
                            int shiftDistance = 1;
                            while (true) {
                                indexToShift = (indexToShift - 1) & capacityMask;
                                long keyToShift;
                                if ((keyToShift = keys[indexToShift]) == free) {
                                    break;
                                }
                                if ((((LHash.SeparateKVLongKeyMixing.mix(keyToShift)) - indexToShift) & capacityMask) >= shiftDistance) {
                                    if (indexToShift > indexToRemove) {
                                        firstDelayedRemoved = i;
                                        delayedRemoved = key;
                                        keys[indexToRemove] = key;
                                        break closeDeletion;
                                    }
                                    if (indexToRemove == i) {
                                        i++;
                                    }
                                    keys[indexToRemove] = keyToShift;
                                    vals[indexToRemove] = vals[indexToShift];
                                    indexToRemove = indexToShift;
                                    shiftDistance = 1;
                                } else {
                                    shiftDistance++;
                                    if (indexToShift == (1 + i)) {
                                        throw new ConcurrentModificationException();
                                    }
                                }
                            }
                            keys[indexToRemove] = free;
                            vals[indexToRemove] = null;
                            postRemoveHook();
                        } else {
                            keys[i] = delayedRemoved;
                        }
                        changed = true;
                    }
                }
            }
            if (firstDelayedRemoved >= 0) {
                closeDelayedRemoved(firstDelayedRemoved, delayedRemoved);
            }
            return changed;
        }
        
        @SuppressWarnings(value = "unchecked")
        @Override
        public final boolean removeAll(@Nonnull
                                               Collection<?> c) {
            if (c instanceof InternalObjCollectionOps) {
                InternalObjCollectionOps c2 = ((InternalObjCollectionOps) (c));
                if ((equivalence().equals(c2.equivalence())) && ((c2.size()) < (KolobokeLongEntityMap.EntryView.this.size()))) {
                    c2.reverseRemoveAllFrom(KolobokeLongEntityMap.EntryView.this);
                }
            }
            if ((KolobokeLongEntityMap.EntryView.this) == ((Object) (c)))
                throw new IllegalArgumentException();
            
            if ((KolobokeLongEntityMap.EntryView.this.isEmpty()) || (c.isEmpty()))
                return false;
            
            boolean changed = false;
            KolobokeLongEntityMap<T>.ReusableEntry e = new ReusableEntry();
            long free = freeValue;
            long[] keys = set;
            int capacityMask = (keys.length) - 1;
            int firstDelayedRemoved = -1;
            long delayedRemoved = 0L;
            T[] vals = values;
            for (int i = (keys.length) - 1; i >= 0; i--) {
                long key;
                if ((key = keys[i]) != free) {
                    if (c.contains(e.with(key, vals[i]))) {
                        closeDeletion : if (firstDelayedRemoved < 0) {
                            int indexToRemove = i;
                            int indexToShift = indexToRemove;
                            int shiftDistance = 1;
                            while (true) {
                                indexToShift = (indexToShift - 1) & capacityMask;
                                long keyToShift;
                                if ((keyToShift = keys[indexToShift]) == free) {
                                    break;
                                }
                                if ((((LHash.SeparateKVLongKeyMixing.mix(keyToShift)) - indexToShift) & capacityMask) >= shiftDistance) {
                                    if (indexToShift > indexToRemove) {
                                        firstDelayedRemoved = i;
                                        delayedRemoved = key;
                                        keys[indexToRemove] = key;
                                        break closeDeletion;
                                    }
                                    if (indexToRemove == i) {
                                        i++;
                                    }
                                    keys[indexToRemove] = keyToShift;
                                    vals[indexToRemove] = vals[indexToShift];
                                    indexToRemove = indexToShift;
                                    shiftDistance = 1;
                                } else {
                                    shiftDistance++;
                                    if (indexToShift == (1 + i)) {
                                        throw new ConcurrentModificationException();
                                    }
                                }
                            }
                            keys[indexToRemove] = free;
                            vals[indexToRemove] = null;
                            postRemoveHook();
                        } else {
                            keys[i] = delayedRemoved;
                        }
                        changed = true;
                    }
                }
            }
            if (firstDelayedRemoved >= 0) {
                closeDelayedRemoved(firstDelayedRemoved, delayedRemoved);
            }
            return changed;
        }
        
        @Override
        public final boolean retainAll(@Nonnull
                                               Collection<?> c) {
            if ((KolobokeLongEntityMap.EntryView.this) == ((Object) (c)))
                throw new IllegalArgumentException();
            
            if (KolobokeLongEntityMap.EntryView.this.isEmpty())
                return false;
            
            if (c.isEmpty()) {
                clear();
                return true;
            }
            boolean changed = false;
            KolobokeLongEntityMap<T>.ReusableEntry e = new ReusableEntry();
            long free = freeValue;
            long[] keys = set;
            int capacityMask = (keys.length) - 1;
            int firstDelayedRemoved = -1;
            long delayedRemoved = 0L;
            T[] vals = values;
            for (int i = (keys.length) - 1; i >= 0; i--) {
                long key;
                if ((key = keys[i]) != free) {
                    if (!(c.contains(e.with(key, vals[i])))) {
                        closeDeletion : if (firstDelayedRemoved < 0) {
                            int indexToRemove = i;
                            int indexToShift = indexToRemove;
                            int shiftDistance = 1;
                            while (true) {
                                indexToShift = (indexToShift - 1) & capacityMask;
                                long keyToShift;
                                if ((keyToShift = keys[indexToShift]) == free) {
                                    break;
                                }
                                if ((((LHash.SeparateKVLongKeyMixing.mix(keyToShift)) - indexToShift) & capacityMask) >= shiftDistance) {
                                    if (indexToShift > indexToRemove) {
                                        firstDelayedRemoved = i;
                                        delayedRemoved = key;
                                        keys[indexToRemove] = key;
                                        break closeDeletion;
                                    }
                                    if (indexToRemove == i) {
                                        i++;
                                    }
                                    keys[indexToRemove] = keyToShift;
                                    vals[indexToRemove] = vals[indexToShift];
                                    indexToRemove = indexToShift;
                                    shiftDistance = 1;
                                } else {
                                    shiftDistance++;
                                    if (indexToShift == (1 + i)) {
                                        throw new ConcurrentModificationException();
                                    }
                                }
                            }
                            keys[indexToRemove] = free;
                            vals[indexToRemove] = null;
                            postRemoveHook();
                        } else {
                            keys[i] = delayedRemoved;
                        }
                        changed = true;
                    }
                }
            }
            if (firstDelayedRemoved >= 0) {
                closeDelayedRemoved(firstDelayedRemoved, delayedRemoved);
            }
            return changed;
        }
        
        @Override
        public void clear() {
            KolobokeLongEntityMap.this.doClear();
        }
    }
    
    abstract class LongObjEntry extends AbstractEntry<Long, T> {
        abstract long key();
        
        @Override
        public final Long getKey() {
            return key();
        }
        
        abstract T value();
        
        @Override
        public final T getValue() {
            return value();
        }
        
        @SuppressWarnings(value = "unchecked")
        @Override
        public boolean equals(Object o) { // lgtm[java/unchecked-cast-in-equals]
            Map.Entry e2;
            long k2;
            T v2;
            try {
                e2 = ((Map.Entry) (o));
                k2 = ((Long) (e2.getKey()));
                v2 = ((T) (e2.getValue()));
                return ((key()) == k2) && (nullableValueEquals(v2, value()));
            } catch (ClassCastException e) {
                return false;
            } catch (NullPointerException e) {
                return false;
            }
        }
        
        @Override
        public int hashCode() {
            return (Primitives.hashCode(key())) ^ (nullableValueHashCode(value()));
        }
    }
    
    class MutableEntry extends KolobokeLongEntityMap<T>.LongObjEntry {
        private final int index;
        
        final long key;
        
        private T value;
        
        MutableEntry(int index, long key, T value) {
            this.index = index;
            this.key = key;
            KolobokeLongEntityMap.MutableEntry.this.value = value;
        }
        
        @Override
        public long key() {
            return key;
        }
        
        @Override
        public T value() {
            return value;
        }
        
        @Override
        public T setValue(T newValue) {
            T oldValue = value;
            T unwrappedNewValue = newValue;
            value = unwrappedNewValue;
            updateValueInTable(unwrappedNewValue);
            return oldValue;
        }
        
        void updateValueInTable(T newValue) {
            values[index] = newValue;
        }
    }
    
    class ReusableEntry extends KolobokeLongEntityMap<T>.LongObjEntry {
        private long key;
        
        private T value;
        
        KolobokeLongEntityMap<T>.ReusableEntry with(long key, T value) {
            KolobokeLongEntityMap.ReusableEntry.this.key = key;
            KolobokeLongEntityMap.ReusableEntry.this.value = value;
            return KolobokeLongEntityMap.ReusableEntry.this;
        }
        
        @Override
        public long key() {
            return key;
        }
        
        @Override
        public T value() {
            return value;
        }
    }
    
    class ValueView extends AbstractObjValueView<T> {
        @Override
        public Equivalence<T> equivalence() {
            return valueEquivalence();
        }
        
        @Override
        public int size() {
            return KolobokeLongEntityMap.this.size();
        }
        
        @Override
        public boolean shrink() {
            return KolobokeLongEntityMap.this.shrink();
        }
        
        @Override
        public boolean contains(Object o) {
            return KolobokeLongEntityMap.this.containsValue(o);
        }
        
        @Override
        public void forEach(Consumer<? super T> action) {
            if (action == null)
                throw new NullPointerException();
            
            if (KolobokeLongEntityMap.ValueView.this.isEmpty())
                return ;
            
            long free = freeValue;
            long[] keys = set;
            T[] vals = values;
            for (int i = (keys.length) - 1; i >= 0; i--) {
                if ((keys[i]) != free) {
                    action.accept(vals[i]);
                }
            }
        }
        
        @Override
        public boolean forEachWhile(Predicate<? super T> predicate) {
            if (predicate == null)
                throw new NullPointerException();
            
            if (KolobokeLongEntityMap.ValueView.this.isEmpty())
                return true;
            
            boolean terminated = false;
            long free = freeValue;
            long[] keys = set;
            T[] vals = values;
            for (int i = (keys.length) - 1; i >= 0; i--) {
                if ((keys[i]) != free) {
                    if (!(predicate.test(vals[i]))) {
                        terminated = true;
                        break;
                    }
                }
            }
            return !terminated;
        }
        
        @Override
        public boolean allContainingIn(ObjCollection<?> c) {
            if (KolobokeLongEntityMap.ValueView.this.isEmpty())
                return true;
            
            boolean containsAll = true;
            long free = freeValue;
            long[] keys = set;
            T[] vals = values;
            for (int i = (keys.length) - 1; i >= 0; i--) {
                if ((keys[i]) != free) {
                    if (!(c.contains(vals[i]))) {
                        containsAll = false;
                        break;
                    }
                }
            }
            return containsAll;
        }
        
        @Override
        public boolean reverseAddAllTo(ObjCollection<? super T> c) {
            if (KolobokeLongEntityMap.ValueView.this.isEmpty())
                return false;
            
            boolean changed = false;
            long free = freeValue;
            long[] keys = set;
            T[] vals = values;
            for (int i = (keys.length) - 1; i >= 0; i--) {
                if ((keys[i]) != free) {
                    changed |= c.add(vals[i]);
                }
            }
            return changed;
        }
        
        @Override
        public boolean reverseRemoveAllFrom(ObjSet<?> s) {
            if ((KolobokeLongEntityMap.ValueView.this.isEmpty()) || (s.isEmpty()))
                return false;
            
            boolean changed = false;
            long free = freeValue;
            long[] keys = set;
            T[] vals = values;
            for (int i = (keys.length) - 1; i >= 0; i--) {
                if ((keys[i]) != free) {
                    changed |= s.remove(vals[i]);
                }
            }
            return changed;
        }
        
        @Override
        @Nonnull
        public ObjIterator<T> iterator() {
            return new NoRemovedValueIterator();
        }
        
        @Nonnull
        @Override
        public ObjCursor<T> cursor() {
            return new NoRemovedValueCursor();
        }
        
        @Override
        @Nonnull
        public Object[] toArray() {
            int size = size();
            Object[] result = new Object[size];
            if (size == 0)
                return result;
            
            int resultIndex = 0;
            long free = freeValue;
            long[] keys = set;
            T[] vals = values;
            for (int i = (keys.length) - 1; i >= 0; i--) {
                if ((keys[i]) != free) {
                    result[(resultIndex++)] = vals[i];
                }
            }
            return result;
        }
        
        @Override
        @SuppressWarnings(value = "unchecked")
        @Nonnull
        public <T2>  T2[] toArray(@Nonnull
                                          T2[] a) {
            int size = size();
            if ((a.length) < size) {
                Class<?> elementType = a.getClass().getComponentType();
                a = ((T2[]) (Array.newInstance(elementType, size)));
            }
            if (size == 0) {
                if ((a.length) > 0)
                    a[0] = null;
                
                return a;
            }
            int resultIndex = 0;
            long free = freeValue;
            long[] keys = set;
            T[] vals = values;
            for (int i = (keys.length) - 1; i >= 0; i--) {
                if ((keys[i]) != free) {
                    a[(resultIndex++)] = ((T2) (vals[i]));
                }
            }
            if ((a.length) > resultIndex)
                a[resultIndex] = null;
            
            return a;
        }
        
        @Override
        public String toString() {
            if (KolobokeLongEntityMap.ValueView.this.isEmpty())
                return "[]";
            
            StringBuilder sb = new StringBuilder();
            int elementCount = 0;
            long free = freeValue;
            long[] keys = set;
            T[] vals = values;
            for (int i = (keys.length) - 1; i >= 0; i--) {
                if ((keys[i]) != free) {
                    T val;
                    sb.append(' ').append(((val = vals[i]) != ((Object) (KolobokeLongEntityMap.ValueView.this)) ? val : "(this Collection)")).append(',');
                    if ((++elementCount) == 8) {
                        int expectedLength = (sb.length()) * ((size()) / 8);
                        sb.ensureCapacity((expectedLength + (expectedLength / 2)));
                    }
                }
            }
            sb.setCharAt(0, '[');
            sb.setCharAt(((sb.length()) - 1), ']');
            return sb.toString();
        }
        
        @Override
        public boolean remove(Object o) {
            return removeValue(o);
        }
        
        @Override
        public void clear() {
            KolobokeLongEntityMap.this.clear();
        }
        
        @Override
        public boolean removeIf(Predicate<? super T> filter) {
            if (filter == null)
                throw new NullPointerException();
            
            if (KolobokeLongEntityMap.ValueView.this.isEmpty())
                return false;
            
            boolean changed = false;
            long free = freeValue;
            long[] keys = set;
            int capacityMask = (keys.length) - 1;
            int firstDelayedRemoved = -1;
            long delayedRemoved = 0L;
            T[] vals = values;
            for (int i = (keys.length) - 1; i >= 0; i--) {
                long key;
                if ((key = keys[i]) != free) {
                    if (filter.test(vals[i])) {
                        closeDeletion : if (firstDelayedRemoved < 0) {
                            int indexToRemove = i;
                            int indexToShift = indexToRemove;
                            int shiftDistance = 1;
                            while (true) {
                                indexToShift = (indexToShift - 1) & capacityMask;
                                long keyToShift;
                                if ((keyToShift = keys[indexToShift]) == free) {
                                    break;
                                }
                                if ((((LHash.SeparateKVLongKeyMixing.mix(keyToShift)) - indexToShift) & capacityMask) >= shiftDistance) {
                                    if (indexToShift > indexToRemove) {
                                        firstDelayedRemoved = i;
                                        delayedRemoved = key;
                                        keys[indexToRemove] = key;
                                        break closeDeletion;
                                    }
                                    if (indexToRemove == i) {
                                        i++;
                                    }
                                    keys[indexToRemove] = keyToShift;
                                    vals[indexToRemove] = vals[indexToShift];
                                    indexToRemove = indexToShift;
                                    shiftDistance = 1;
                                } else {
                                    shiftDistance++;
                                    if (indexToShift == (1 + i)) {
                                        throw new ConcurrentModificationException();
                                    }
                                }
                            }
                            keys[indexToRemove] = free;
                            vals[indexToRemove] = null;
                            postRemoveHook();
                        } else {
                            keys[i] = delayedRemoved;
                        }
                        changed = true;
                    }
                }
            }
            if (firstDelayedRemoved >= 0) {
                closeDelayedRemoved(firstDelayedRemoved, delayedRemoved);
            }
            return changed;
        }
        
        @Override
        public boolean removeAll(@Nonnull
                                         Collection<?> c) {
            if ((KolobokeLongEntityMap.ValueView.this) == ((Object) (c)))
                throw new IllegalArgumentException();
            
            if ((KolobokeLongEntityMap.ValueView.this.isEmpty()) || (c.isEmpty()))
                return false;
            
            boolean changed = false;
            long free = freeValue;
            long[] keys = set;
            int capacityMask = (keys.length) - 1;
            int firstDelayedRemoved = -1;
            long delayedRemoved = 0L;
            T[] vals = values;
            for (int i = (keys.length) - 1; i >= 0; i--) {
                long key;
                if ((key = keys[i]) != free) {
                    if (c.contains(vals[i])) {
                        closeDeletion : if (firstDelayedRemoved < 0) {
                            int indexToRemove = i;
                            int indexToShift = indexToRemove;
                            int shiftDistance = 1;
                            while (true) {
                                indexToShift = (indexToShift - 1) & capacityMask;
                                long keyToShift;
                                if ((keyToShift = keys[indexToShift]) == free) {
                                    break;
                                }
                                if ((((LHash.SeparateKVLongKeyMixing.mix(keyToShift)) - indexToShift) & capacityMask) >= shiftDistance) {
                                    if (indexToShift > indexToRemove) {
                                        firstDelayedRemoved = i;
                                        delayedRemoved = key;
                                        keys[indexToRemove] = key;
                                        break closeDeletion;
                                    }
                                    if (indexToRemove == i) {
                                        i++;
                                    }
                                    keys[indexToRemove] = keyToShift;
                                    vals[indexToRemove] = vals[indexToShift];
                                    indexToRemove = indexToShift;
                                    shiftDistance = 1;
                                } else {
                                    shiftDistance++;
                                    if (indexToShift == (1 + i)) {
                                        throw new ConcurrentModificationException();
                                    }
                                }
                            }
                            keys[indexToRemove] = free;
                            vals[indexToRemove] = null;
                            postRemoveHook();
                        } else {
                            keys[i] = delayedRemoved;
                        }
                        changed = true;
                    }
                }
            }
            if (firstDelayedRemoved >= 0) {
                closeDelayedRemoved(firstDelayedRemoved, delayedRemoved);
            }
            return changed;
        }
        
        @Override
        public boolean retainAll(@Nonnull
                                         Collection<?> c) {
            if ((KolobokeLongEntityMap.ValueView.this) == ((Object) (c)))
                throw new IllegalArgumentException();
            
            if (KolobokeLongEntityMap.ValueView.this.isEmpty())
                return false;
            
            if (c.isEmpty()) {
                clear();
                return true;
            }
            boolean changed = false;
            long free = freeValue;
            long[] keys = set;
            int capacityMask = (keys.length) - 1;
            int firstDelayedRemoved = -1;
            long delayedRemoved = 0L;
            T[] vals = values;
            for (int i = (keys.length) - 1; i >= 0; i--) {
                long key;
                if ((key = keys[i]) != free) {
                    if (!(c.contains(vals[i]))) {
                        closeDeletion : if (firstDelayedRemoved < 0) {
                            int indexToRemove = i;
                            int indexToShift = indexToRemove;
                            int shiftDistance = 1;
                            while (true) {
                                indexToShift = (indexToShift - 1) & capacityMask;
                                long keyToShift;
                                if ((keyToShift = keys[indexToShift]) == free) {
                                    break;
                                }
                                if ((((LHash.SeparateKVLongKeyMixing.mix(keyToShift)) - indexToShift) & capacityMask) >= shiftDistance) {
                                    if (indexToShift > indexToRemove) {
                                        firstDelayedRemoved = i;
                                        delayedRemoved = key;
                                        keys[indexToRemove] = key;
                                        break closeDeletion;
                                    }
                                    if (indexToRemove == i) {
                                        i++;
                                    }
                                    keys[indexToRemove] = keyToShift;
                                    vals[indexToRemove] = vals[indexToShift];
                                    indexToRemove = indexToShift;
                                    shiftDistance = 1;
                                } else {
                                    shiftDistance++;
                                    if (indexToShift == (1 + i)) {
                                        throw new ConcurrentModificationException();
                                    }
                                }
                            }
                            keys[indexToRemove] = free;
                            vals[indexToRemove] = null;
                            postRemoveHook();
                        } else {
                            keys[i] = delayedRemoved;
                        }
                        changed = true;
                    }
                }
            }
            if (firstDelayedRemoved >= 0) {
                closeDelayedRemoved(firstDelayedRemoved, delayedRemoved);
            }
            return changed;
        }
    }
    
    class NoRemovedEntryIterator implements ObjIterator<Map.Entry<Long, T>> {
        long[] keys;
        
        T[] vals;
        
        final long free;
        
        final int capacityMask;
        
        class MutableEntry2 extends KolobokeLongEntityMap<T>.MutableEntry {
            MutableEntry2(int index, long key, T value) {
                super(index, key, value);
            }
            
            @Override
            void updateValueInTable(T newValue) {
                if ((vals) == (values)) {
                    vals[index] = newValue;
                } else {
                    justPut(key, newValue);
                }
            }
        }
        
        int index = -1;
        
        int nextIndex;
        
        KolobokeLongEntityMap<T>.MutableEntry next;
        
        NoRemovedEntryIterator() {
            long[] keys = KolobokeLongEntityMap.NoRemovedEntryIterator.this.keys = set;
            capacityMask = (keys.length) - 1;
            T[] vals = KolobokeLongEntityMap.NoRemovedEntryIterator.this.vals = values;
            long free = this.free = freeValue;
            int nextI = keys.length;
            while ((--nextI) >= 0) {
                long key;
                if ((key = keys[nextI]) != free) {
                    next = new MutableEntry2(nextI, key, vals[nextI]);
                    break;
                }
            }
            nextIndex = nextI;
        }
        
        @Override
        public void forEachRemaining(@Nonnull
                                             Consumer<? super Map.Entry<Long, T>> action) {
            if (action == null)
                throw new NullPointerException();
            
            long[] keys = KolobokeLongEntityMap.NoRemovedEntryIterator.this.keys;
            T[] vals = KolobokeLongEntityMap.NoRemovedEntryIterator.this.vals;
            long free = KolobokeLongEntityMap.NoRemovedEntryIterator.this.free;
            int nextI = nextIndex;
            for (int i = nextI; i >= 0; i--) {
                long key;
                if ((key = keys[i]) != free) {
                    action.accept(new MutableEntry2(i, key, vals[i]));
                }
            }
            if (nextI != (nextIndex)) {
                throw new ConcurrentModificationException();
            }
            index = nextIndex = -1;
        }
        
        @Override
        public boolean hasNext() {
            return (nextIndex) >= 0;
        }
        
        @Override
        public Map.Entry<Long, T> next() {
            int nextI;
            if ((nextI = nextIndex) >= 0) {
                index = nextI;
                long[] keys = KolobokeLongEntityMap.NoRemovedEntryIterator.this.keys;
                long free = KolobokeLongEntityMap.NoRemovedEntryIterator.this.free;
                KolobokeLongEntityMap<T>.MutableEntry prev = next;
                while ((--nextI) >= 0) {
                    long key;
                    if ((key = keys[nextI]) != free) {
                        next = new MutableEntry2(nextI, key, vals[nextI]);
                        break;
                    }
                }
                nextIndex = nextI;
                return prev;
            } else {
                throw new NoSuchElementException();
            }
        }
        
        @Override
        public void remove() {
            int index;
            if ((index = KolobokeLongEntityMap.NoRemovedEntryIterator.this.index) >= 0) {
                KolobokeLongEntityMap.NoRemovedEntryIterator.this.index = -1;
                long[] keys = KolobokeLongEntityMap.NoRemovedEntryIterator.this.keys;
                T[] vals = KolobokeLongEntityMap.NoRemovedEntryIterator.this.vals;
                if (keys == (set)) {
                    int capacityMask = KolobokeLongEntityMap.NoRemovedEntryIterator.this.capacityMask;
                    int indexToRemove = index;
                    int indexToShift = indexToRemove;
                    int shiftDistance = 1;
                    while (true) {
                        indexToShift = (indexToShift - 1) & capacityMask;
                        long keyToShift;
                        if ((keyToShift = keys[indexToShift]) == (free)) {
                            break;
                        }
                        if ((((LHash.SeparateKVLongKeyMixing.mix(keyToShift)) - indexToShift) & capacityMask) >= shiftDistance) {
                            if ((KolobokeLongEntityMap.NoRemovedEntryIterator.this.keys) == keys) {
                                if (indexToShift > indexToRemove) {
                                    int slotsToCopy;
                                    if ((slotsToCopy = (nextIndex) + 1) > 0) {
                                        KolobokeLongEntityMap.NoRemovedEntryIterator.this.keys = Arrays.copyOf(keys, slotsToCopy);
                                        KolobokeLongEntityMap.NoRemovedEntryIterator.this.vals = Arrays.copyOf(vals, slotsToCopy);
                                        if (indexToRemove < slotsToCopy) {
                                            KolobokeLongEntityMap.NoRemovedEntryIterator.this.keys[indexToRemove] = free;
                                            KolobokeLongEntityMap.NoRemovedEntryIterator.this.vals[indexToRemove] = null;
                                        }
                                    }
                                } else if (indexToRemove == index) {
                                    KolobokeLongEntityMap.NoRemovedEntryIterator.this.nextIndex = index;
                                    if (indexToShift < (index - 1)) {
                                        KolobokeLongEntityMap.NoRemovedEntryIterator.this.next = new MutableEntry2(indexToShift, keyToShift, vals[indexToShift]);
                                    }
                                }
                            }
                            keys[indexToRemove] = keyToShift;
                            vals[indexToRemove] = vals[indexToShift];
                            indexToRemove = indexToShift;
                            shiftDistance = 1;
                        } else {
                            shiftDistance++;
                            if (indexToShift == (1 + index)) {
                                throw new ConcurrentModificationException();
                            }
                        }
                    }
                    keys[indexToRemove] = free;
                    vals[indexToRemove] = null;
                    postRemoveHook();
                } else {
                    justRemove(keys[index]);
                    vals[index] = null;
                }
            } else {
                throw new IllegalStateException();
            }
        }
    }
    
    class NoRemovedEntryCursor implements ObjCursor<Map.Entry<Long, T>> {
        long[] keys;
        
        T[] vals;
        
        final long free;
        
        final int capacityMask;
        
        class MutableEntry2 extends KolobokeLongEntityMap<T>.MutableEntry {
            MutableEntry2(int index, long key, T value) {
                super(index, key, value);
            }
            
            @Override
            void updateValueInTable(T newValue) {
                if ((vals) == (values)) {
                    vals[index] = newValue;
                } else {
                    justPut(key, newValue);
                }
            }
        }
        
        int index;
        
        long curKey;
        
        T curValue;
        
        NoRemovedEntryCursor() {
            long[] keys = KolobokeLongEntityMap.NoRemovedEntryCursor.this.keys = set;
            capacityMask = (keys.length) - 1;
            index = keys.length;
            vals = values;
            long free = this.free = freeValue;
            curKey = free;
        }
        
        @Override
        public void forEachForward(Consumer<? super Map.Entry<Long, T>> action) {
            if (action == null)
                throw new NullPointerException();
            
            long[] keys = KolobokeLongEntityMap.NoRemovedEntryCursor.this.keys;
            T[] vals = KolobokeLongEntityMap.NoRemovedEntryCursor.this.vals;
            long free = KolobokeLongEntityMap.NoRemovedEntryCursor.this.free;
            int index = KolobokeLongEntityMap.NoRemovedEntryCursor.this.index;
            for (int i = index - 1; i >= 0; i--) {
                long key;
                if ((key = keys[i]) != free) {
                    action.accept(new MutableEntry2(i, key, vals[i]));
                }
            }
            if (index != (KolobokeLongEntityMap.NoRemovedEntryCursor.this.index)) {
                throw new ConcurrentModificationException();
            }
            KolobokeLongEntityMap.NoRemovedEntryCursor.this.index = -1;
            curKey = free;
        }
        
        @Override
        public Map.Entry<Long, T> elem() {
            long curKey;
            if ((curKey = KolobokeLongEntityMap.NoRemovedEntryCursor.this.curKey) != (free)) {
                return new MutableEntry2(index, curKey, curValue);
            } else {
                throw new IllegalStateException();
            }
        }
        
        @Override
        public boolean moveNext() {
            long[] keys = KolobokeLongEntityMap.NoRemovedEntryCursor.this.keys;
            long free = KolobokeLongEntityMap.NoRemovedEntryCursor.this.free;
            for (int i = (index) - 1; i >= 0; i--) {
                long key;
                if ((key = keys[i]) != free) {
                    index = i;
                    curKey = key;
                    curValue = vals[i];
                    return true;
                }
            }
            curKey = free;
            index = -1;
            return false;
        }
        
        @Override
        public void remove() {
            long curKey;
            long free;
            if ((curKey = KolobokeLongEntityMap.NoRemovedEntryCursor.this.curKey) != (free = KolobokeLongEntityMap.NoRemovedEntryCursor.this.free)) {
                KolobokeLongEntityMap.NoRemovedEntryCursor.this.curKey = free;
                int index = KolobokeLongEntityMap.NoRemovedEntryCursor.this.index;
                long[] keys = KolobokeLongEntityMap.NoRemovedEntryCursor.this.keys;
                T[] vals = KolobokeLongEntityMap.NoRemovedEntryCursor.this.vals;
                if (keys == (set)) {
                    int capacityMask = KolobokeLongEntityMap.NoRemovedEntryCursor.this.capacityMask;
                    int indexToRemove = index;
                    int indexToShift = indexToRemove;
                    int shiftDistance = 1;
                    while (true) {
                        indexToShift = (indexToShift - 1) & capacityMask;
                        long keyToShift;
                        if ((keyToShift = keys[indexToShift]) == free) {
                            break;
                        }
                        if ((((LHash.SeparateKVLongKeyMixing.mix(keyToShift)) - indexToShift) & capacityMask) >= shiftDistance) {
                            if ((KolobokeLongEntityMap.NoRemovedEntryCursor.this.keys) == keys) {
                                if (indexToShift > indexToRemove) {
                                    int slotsToCopy;
                                    if ((slotsToCopy = index) > 0) {
                                        KolobokeLongEntityMap.NoRemovedEntryCursor.this.keys = Arrays.copyOf(keys, slotsToCopy);
                                        KolobokeLongEntityMap.NoRemovedEntryCursor.this.vals = Arrays.copyOf(vals, slotsToCopy);
                                        if (indexToRemove < slotsToCopy) {
                                            KolobokeLongEntityMap.NoRemovedEntryCursor.this.keys[indexToRemove] = free;
                                            KolobokeLongEntityMap.NoRemovedEntryCursor.this.vals[indexToRemove] = null;
                                        }
                                    }
                                } else if (indexToRemove == index) {
                                    KolobokeLongEntityMap.NoRemovedEntryCursor.this.index = ++index;
                                }
                            }
                            keys[indexToRemove] = keyToShift;
                            vals[indexToRemove] = vals[indexToShift];
                            indexToRemove = indexToShift;
                            shiftDistance = 1;
                        } else {
                            shiftDistance++;
                            if (indexToShift == (1 + index)) {
                                throw new ConcurrentModificationException();
                            }
                        }
                    }
                    keys[indexToRemove] = free;
                    vals[indexToRemove] = null;
                    postRemoveHook();
                } else {
                    justRemove(curKey);
                    vals[index] = null;
                }
            } else {
                throw new IllegalStateException();
            }
        }
    }
    
    class NoRemovedValueIterator implements ObjIterator<T> {
        long[] keys;
        
        T[] vals;
        
        final long free;
        
        final int capacityMask;
        
        int index = -1;
        
        int nextIndex;
        
        T next;
        
        NoRemovedValueIterator() {
            long[] keys = KolobokeLongEntityMap.NoRemovedValueIterator.this.keys = set;
            capacityMask = (keys.length) - 1;
            T[] vals = KolobokeLongEntityMap.NoRemovedValueIterator.this.vals = values;
            long free = this.free = freeValue;
            int nextI = keys.length;
            while ((--nextI) >= 0) {
                if ((keys[nextI]) != free) {
                    next = vals[nextI];
                    break;
                }
            }
            nextIndex = nextI;
        }
        
        @Override
        public void forEachRemaining(Consumer<? super T> action) {
            if (action == null)
                throw new NullPointerException();
            
            long[] keys = KolobokeLongEntityMap.NoRemovedValueIterator.this.keys;
            T[] vals = KolobokeLongEntityMap.NoRemovedValueIterator.this.vals;
            long free = KolobokeLongEntityMap.NoRemovedValueIterator.this.free;
            int nextI = nextIndex;
            for (int i = nextI; i >= 0; i--) {
                if ((keys[i]) != free) {
                    action.accept(vals[i]);
                }
            }
            if (nextI != (nextIndex)) {
                throw new ConcurrentModificationException();
            }
            index = nextIndex = -1;
        }
        
        @Override
        public boolean hasNext() {
            return (nextIndex) >= 0;
        }
        
        @Override
        public T next() {
            int nextI;
            if ((nextI = nextIndex) >= 0) {
                index = nextI;
                long[] keys = KolobokeLongEntityMap.NoRemovedValueIterator.this.keys;
                long free = KolobokeLongEntityMap.NoRemovedValueIterator.this.free;
                T prev = next;
                while ((--nextI) >= 0) {
                    if ((keys[nextI]) != free) {
                        next = vals[nextI];
                        break;
                    }
                }
                nextIndex = nextI;
                return prev;
            } else {
                throw new NoSuchElementException();
            }
        }
        
        @Override
        public void remove() {
            int index;
            if ((index = KolobokeLongEntityMap.NoRemovedValueIterator.this.index) >= 0) {
                KolobokeLongEntityMap.NoRemovedValueIterator.this.index = -1;
                long[] keys = KolobokeLongEntityMap.NoRemovedValueIterator.this.keys;
                T[] vals = KolobokeLongEntityMap.NoRemovedValueIterator.this.vals;
                if (keys == (set)) {
                    int capacityMask = KolobokeLongEntityMap.NoRemovedValueIterator.this.capacityMask;
                    int indexToRemove = index;
                    int indexToShift = indexToRemove;
                    int shiftDistance = 1;
                    while (true) {
                        indexToShift = (indexToShift - 1) & capacityMask;
                        long keyToShift;
                        if ((keyToShift = keys[indexToShift]) == (free)) {
                            break;
                        }
                        if ((((LHash.SeparateKVLongKeyMixing.mix(keyToShift)) - indexToShift) & capacityMask) >= shiftDistance) {
                            if ((KolobokeLongEntityMap.NoRemovedValueIterator.this.keys) == keys) {
                                if (indexToShift > indexToRemove) {
                                    int slotsToCopy;
                                    if ((slotsToCopy = (nextIndex) + 1) > 0) {
                                        KolobokeLongEntityMap.NoRemovedValueIterator.this.keys = Arrays.copyOf(keys, slotsToCopy);
                                        KolobokeLongEntityMap.NoRemovedValueIterator.this.vals = Arrays.copyOf(vals, slotsToCopy);
                                        if (indexToRemove < slotsToCopy) {
                                            KolobokeLongEntityMap.NoRemovedValueIterator.this.keys[indexToRemove] = free;
                                            KolobokeLongEntityMap.NoRemovedValueIterator.this.vals[indexToRemove] = null;
                                        }
                                    }
                                } else if (indexToRemove == index) {
                                    KolobokeLongEntityMap.NoRemovedValueIterator.this.nextIndex = index;
                                    if (indexToShift < (index - 1)) {
                                        KolobokeLongEntityMap.NoRemovedValueIterator.this.next = vals[indexToShift];
                                    }
                                }
                            }
                            keys[indexToRemove] = keyToShift;
                            vals[indexToRemove] = vals[indexToShift];
                            indexToRemove = indexToShift;
                            shiftDistance = 1;
                        } else {
                            shiftDistance++;
                            if (indexToShift == (1 + index)) {
                                throw new ConcurrentModificationException();
                            }
                        }
                    }
                    keys[indexToRemove] = free;
                    vals[indexToRemove] = null;
                    postRemoveHook();
                } else {
                    justRemove(keys[index]);
                    vals[index] = null;
                }
            } else {
                throw new IllegalStateException();
            }
        }
    }
    
    class NoRemovedValueCursor implements ObjCursor<T> {
        long[] keys;
        
        T[] vals;
        
        final long free;
        
        final int capacityMask;
        
        int index;
        
        long curKey;
        
        T curValue;
        
        NoRemovedValueCursor() {
            long[] keys = KolobokeLongEntityMap.NoRemovedValueCursor.this.keys = set;
            capacityMask = (keys.length) - 1;
            index = keys.length;
            vals = values;
            long free = this.free = freeValue;
            curKey = free;
        }
        
        @Override
        public void forEachForward(Consumer<? super T> action) {
            if (action == null)
                throw new NullPointerException();
            
            long[] keys = KolobokeLongEntityMap.NoRemovedValueCursor.this.keys;
            T[] vals = KolobokeLongEntityMap.NoRemovedValueCursor.this.vals;
            long free = KolobokeLongEntityMap.NoRemovedValueCursor.this.free;
            int index = KolobokeLongEntityMap.NoRemovedValueCursor.this.index;
            for (int i = index - 1; i >= 0; i--) {
                if ((keys[i]) != free) {
                    action.accept(vals[i]);
                }
            }
            if (index != (KolobokeLongEntityMap.NoRemovedValueCursor.this.index)) {
                throw new ConcurrentModificationException();
            }
            KolobokeLongEntityMap.NoRemovedValueCursor.this.index = -1;
            curKey = free;
        }
        
        @Override
        public T elem() {
            if ((curKey) != (free)) {
                return curValue;
            } else {
                throw new IllegalStateException();
            }
        }
        
        @Override
        public boolean moveNext() {
            long[] keys = KolobokeLongEntityMap.NoRemovedValueCursor.this.keys;
            long free = KolobokeLongEntityMap.NoRemovedValueCursor.this.free;
            for (int i = (index) - 1; i >= 0; i--) {
                long key;
                if ((key = keys[i]) != free) {
                    index = i;
                    curKey = key;
                    curValue = vals[i];
                    return true;
                }
            }
            curKey = free;
            index = -1;
            return false;
        }
        
        @Override
        public void remove() {
            long curKey;
            long free;
            if ((curKey = KolobokeLongEntityMap.NoRemovedValueCursor.this.curKey) != (free = KolobokeLongEntityMap.NoRemovedValueCursor.this.free)) {
                KolobokeLongEntityMap.NoRemovedValueCursor.this.curKey = free;
                int index = KolobokeLongEntityMap.NoRemovedValueCursor.this.index;
                long[] keys = KolobokeLongEntityMap.NoRemovedValueCursor.this.keys;
                T[] vals = KolobokeLongEntityMap.NoRemovedValueCursor.this.vals;
                if (keys == (set)) {
                    int capacityMask = KolobokeLongEntityMap.NoRemovedValueCursor.this.capacityMask;
                    int indexToRemove = index;
                    int indexToShift = indexToRemove;
                    int shiftDistance = 1;
                    while (true) {
                        indexToShift = (indexToShift - 1) & capacityMask;
                        long keyToShift;
                        if ((keyToShift = keys[indexToShift]) == free) {
                            break;
                        }
                        if ((((LHash.SeparateKVLongKeyMixing.mix(keyToShift)) - indexToShift) & capacityMask) >= shiftDistance) {
                            if ((KolobokeLongEntityMap.NoRemovedValueCursor.this.keys) == keys) {
                                if (indexToShift > indexToRemove) {
                                    int slotsToCopy;
                                    if ((slotsToCopy = index) > 0) {
                                        KolobokeLongEntityMap.NoRemovedValueCursor.this.keys = Arrays.copyOf(keys, slotsToCopy);
                                        KolobokeLongEntityMap.NoRemovedValueCursor.this.vals = Arrays.copyOf(vals, slotsToCopy);
                                        if (indexToRemove < slotsToCopy) {
                                            KolobokeLongEntityMap.NoRemovedValueCursor.this.keys[indexToRemove] = free;
                                            KolobokeLongEntityMap.NoRemovedValueCursor.this.vals[indexToRemove] = null;
                                        }
                                    }
                                } else if (indexToRemove == index) {
                                    KolobokeLongEntityMap.NoRemovedValueCursor.this.index = ++index;
                                }
                            }
                            keys[indexToRemove] = keyToShift;
                            vals[indexToRemove] = vals[indexToShift];
                            indexToRemove = indexToShift;
                            shiftDistance = 1;
                        } else {
                            shiftDistance++;
                            if (indexToShift == (1 + index)) {
                                throw new ConcurrentModificationException();
                            }
                        }
                    }
                    keys[indexToRemove] = free;
                    vals[indexToRemove] = null;
                    postRemoveHook();
                } else {
                    justRemove(curKey);
                    vals[index] = null;
                }
            } else {
                throw new IllegalStateException();
            }
        }
    }
    
    KolobokeLongEntityMap(HashConfig hashConfig, int expectedSize) {
        this.init(new HashConfigWrapper(hashConfig), expectedSize);
    }
    
    static class Support {
        static interface LongHash extends Hash {
            long freeValue();
            
            boolean supportRemoved();
            
            long removedValue();
        }
        
        static interface SeparateKVLongLHash extends LHash , KolobokeLongEntityMap.Support.SeparateKVLongHash {        }
        
        static interface SeparateKVLongHash extends KolobokeLongEntityMap.Support.LongHash {
            @Nonnull
            long[] keys();
        }
    }
    
    static final HashConfigWrapper DEFAULT_CONFIG_WRAPPER = new HashConfigWrapper(HashConfig.getDefault());
}