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

de.tum.in.naturals.map.Nat2ObjectDenseArrayMap Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2017 Tobias Meggendorfer
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */

package de.tum.in.naturals.map;

import it.unimi.dsi.fastutil.HashCommon;
import it.unimi.dsi.fastutil.ints.AbstractInt2ObjectMap;
import it.unimi.dsi.fastutil.ints.AbstractIntSet;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.IntIterator;
import it.unimi.dsi.fastutil.ints.IntSet;
import it.unimi.dsi.fastutil.objects.AbstractObjectSet;
import it.unimi.dsi.fastutil.objects.ObjectCollection;
import it.unimi.dsi.fastutil.objects.ObjectIterator;
import it.unimi.dsi.fastutil.objects.ObjectSet;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.PrimitiveIterator;
import java.util.function.BiFunction;
import java.util.function.IntConsumer;
import java.util.function.IntFunction;
import javax.annotation.Nullable;

/**
 * An efficient representation of a total mapping from {0, ..., n} to objects.
 *
 * 

This implementation does not allow {@code null} keys.

*/ @SuppressWarnings("PMD.AssignmentInOperand") public class Nat2ObjectDenseArrayMap extends AbstractInt2ObjectMap { public static final int DEFAULT_SIZE = 16; private static final long serialVersionUID = 630710213786009957L; private V[] array; private int size = 0; @Nullable private transient EntrySetView entriesView = null; @Nullable private transient KeySetView keySetView = null; @Nullable private transient ValuesView valuesView = null; @SuppressWarnings("AssignmentOrReturnOfFieldWithMutableType") public Nat2ObjectDenseArrayMap(V[] array) { this.array = array; for (V value : array) { if (!isAbsent(value)) { size++; } } } @SuppressWarnings({"unchecked", "SuspiciousArrayCast"}) public Nat2ObjectDenseArrayMap(int initialSize) { this.array = (V[]) new Object[initialSize]; } @SuppressWarnings({"unchecked", "SuspiciousArrayCast"}) public Nat2ObjectDenseArrayMap(int initialSize, V initialValue) { checkNotAbsent(initialValue); this.array = (V[]) new Object[initialSize]; Arrays.fill(array, initialValue); this.size = initialSize; } @SuppressWarnings({"unchecked", "SuspiciousArrayCast"}) public Nat2ObjectDenseArrayMap(int initialSize, IntFunction initialValues) { this.array = (V[]) new Object[initialSize]; for (int i = 0; i < array.length; i++) { V value = initialValues.apply(i); checkNotAbsent(value); array[i] = value; } this.size = initialSize; } private boolean isAbsent(@Nullable Object value) { return value == null; } private void checkNotAbsent(@Nullable V value) { if (isAbsent(value)) { // noinspection ProhibitedExceptionThrown throw new NullPointerException("Null value not allowed"); // NOPMD } } private int nextKey(int index) { for (int i = index; i < array.length; i++) { if (!isAbsent(array[i])) { return i; } } return -1; } private boolean ensureSize(int index) { int length = this.array.length; if (length <= index) { this.array = Arrays.copyOf(this.array, Math.max(length * 2, index + 1)); return true; } return false; } @Override public boolean isEmpty() { return size == 0; } @Override public int size() { return size; } @Override public boolean containsKey(int key) { return 0 <= key && key < array.length && !isAbsent(array[key]); } @Override public boolean containsValue(@Nullable Object v) { if (isAbsent(v)) { return false; } V[] array = this.array; for (V value : array) { if (!isAbsent(value) && value.equals(v)) { return true; } } return false; } @Override public V get(int key) { if (array.length <= key) { return defaultReturnValue(); } V value = array[key]; return isAbsent(value) ? defaultReturnValue() : value; } @Override public V getOrDefault(int key, V defaultValue) { if (array.length <= key) { return defaultValue; } V value = array[key]; return isAbsent(value) ? defaultValue : value; } @Override public V put(int key, V value) { checkNotAbsent(value); V previous; //noinspection NestedAssignment if (ensureSize(key) || isAbsent(previous = array[key])) { assert isAbsent(array[key]); array[key] = value; size++; return defaultReturnValue(); } array[key] = value; return previous; } @Override public V putIfAbsent(int key, V value) { checkNotAbsent(value); V previous; //noinspection NestedAssignment if (ensureSize(key) || isAbsent(previous = array[key])) { array[key] = value; size++; return defaultReturnValue(); } return previous; } @Override public V computeIfAbsent(int key, IntFunction mappingFunction) { V previous; //noinspection NestedAssignment if (ensureSize(key) || isAbsent(previous = array[key])) { V value = mappingFunction.apply(key); checkNotAbsent(value); array[key] = value; size++; return value; } return previous; } @Override public V merge(int key, V value, BiFunction remappingFunction) { checkNotAbsent(value); V previous; //noinspection NestedAssignment if (ensureSize(key) || isAbsent(previous = array[key])) { assert isAbsent(array[key]); array[key] = value; size++; return value; } V merge = remappingFunction.apply(previous, value); if (merge == null) { //noinspection AssignmentToNull array[key] = null; size--; return defaultReturnValue(); } checkNotAbsent(merge); array[key] = merge; return merge; } @SuppressWarnings("AssignmentToNull") @Override public V remove(int key) { V previous; //noinspection NestedAssignment if (array.length <= key || isAbsent(previous = array[key])) { return defaultReturnValue(); } array[key] = null; size--; return previous; } public void fill(int from, int to, V value) { checkNotAbsent(value); ensureSize(to); Arrays.fill(array, from, to, value); } public void fill(PrimitiveIterator.OfInt iterator, V value) { checkNotAbsent(value); V[] array = this.array; while (iterator.hasNext()) { int index = iterator.nextInt(); ensureSize(index); array[index] = value; } } public void setAll(int from, int to, IntFunction generator) { ensureSize(to); V[] array = this.array; for (int i = from; i < to; i++) { V value = generator.apply(i); assert !isAbsent(value); if (isAbsent(array[i])) { size += 1; } array[i] = value; } } @Override public void clear() { if (isEmpty()) { return; } Arrays.fill(array, null); size = 0; } @SuppressWarnings("NonFinalFieldReferenceInEquals") @Override public boolean equals(Object o) { if (this == o) { return true; } if (o instanceof Nat2ObjectDenseArrayMap) { Nat2ObjectDenseArrayMap other = (Nat2ObjectDenseArrayMap) o; if (size != other.size) { return false; } // Note: Number of elements in the two arrays is the same here int mismatch = Arrays.mismatch(this.array, other.array); return mismatch == -1 || mismatch == this.array.length || mismatch == other.array.length; } return super.equals(o); } @SuppressWarnings("NonFinalFieldReferencedInHashCode") @Override public int hashCode() { int hash = HashCommon.mix(size); int elements = 0; int index = 0; V[] array = this.array; while (elements < size) { V element = array[index]; if (!isAbsent(element)) { hash ^= element.hashCode() ^ HashCommon.mix(index); elements += 1; } index += 1; } return hash; } @SuppressWarnings("AssignmentOrReturnOfFieldWithMutableType") @Override public IntSet keySet() { if (keySetView == null) { keySetView = new KeySetView(this); } return keySetView; } @SuppressWarnings("AssignmentOrReturnOfFieldWithMutableType") @Override public ObjectCollection values() { if (valuesView == null) { valuesView = new ValuesView<>(this); } return valuesView; } @SuppressWarnings("AssignmentOrReturnOfFieldWithMutableType") @Override public ObjectSet> int2ObjectEntrySet() { if (entriesView == null) { entriesView = new EntrySetView<>(this); } return entriesView; } @SuppressWarnings("AccessingNonPublicFieldOfAnotherObject") private static class EntryIterator implements ObjectIterator> { private final Nat2ObjectDenseArrayMap map; private int current = -1; private int next; EntryIterator(Nat2ObjectDenseArrayMap map) { this.map = map; next = map.nextKey(0); } @Override public boolean hasNext() { return next != -1; } @Override public Int2ObjectMap.Entry next() { if (!hasNext()) { throw new NoSuchElementException(); } current = next; next = map.nextKey(next + 1); assert map.containsKey(current); return new Entry<>(map, current); } @Override public void remove() { if (current == -1) { throw new IllegalStateException(); } map.remove(current); current = -1; } } private static final class Entry implements Int2ObjectMap.Entry { private final Nat2ObjectDenseArrayMap map; private final int index; Entry(Nat2ObjectDenseArrayMap map, int index) { this.map = map; this.index = index; } @Override public int getIntKey() { return index; } @Override public V getValue() { return map.array[index]; } @Override public V setValue(V value) { return map.put(index, value); } @Override public boolean equals(final Object o) { if (!(o instanceof Map.Entry)) { return false; } if (o instanceof Int2ObjectMap.Entry) { Int2ObjectMap.Entry e = (Int2ObjectMap.Entry) o; return getIntKey() == e.getIntKey() && Objects.equals(getValue(), e.getValue()); } Map.Entry e = (Map.Entry) o; Object key = e.getKey(); return key instanceof Integer && getIntKey() == (Integer) key && Objects.equals(getValue(), e.getValue()); } @Override public int hashCode() { return HashCommon.mix(index) ^ getValue().hashCode(); } } private static class EntrySetView extends AbstractInt2ObjectEntrySet> { EntrySetView(Nat2ObjectDenseArrayMap map) { super(map); } @Override public EntrySetView clone() throws CloneNotSupportedException { return (EntrySetView) super.clone(); } @Override public ObjectIterator> fastIterator() { return new FastEntryIterator<>(map); } @Override public ObjectIterator> iterator() { return new EntryIterator<>(map); } } private static class FastEntryIterator implements ObjectIterator> { private final FastMapEntry entry; private final Nat2ObjectDenseArrayMap map; private int next; FastEntryIterator(Nat2ObjectDenseArrayMap map) { entry = new FastMapEntry<>(map); this.map = map; next = map.nextKey(0); } @Override public boolean hasNext() { return next >= 0; } @Override public Int2ObjectMap.Entry next() { if (!hasNext()) { throw new NoSuchElementException(); } entry.index = next; next = map.nextKey(next + 1); return entry; } @Override public void remove() { if (entry.index == -1) { throw new IllegalStateException(); } map.remove(entry.index); entry.index = -1; } } @SuppressWarnings("AccessingNonPublicFieldOfAnotherObject") private static class FastMapEntry extends AbstractInt2ObjectMap.BasicEntry { int index = -1; private final Nat2ObjectDenseArrayMap map; FastMapEntry(Nat2ObjectDenseArrayMap map) { this.map = map; } @Override public int getIntKey() { return index; } @Override public V getValue() { return map.array[index]; } @Override public V setValue(V v) { return map.put(index, v); } } private static class KeySetIterator implements IntIterator { private final Nat2ObjectDenseArrayMap map; private int current = -1; private int next; KeySetIterator(Nat2ObjectDenseArrayMap map) { this.map = map; next = map.nextKey(0); } @Override public boolean hasNext() { return next >= 0; } @Override public int nextInt() { if (!hasNext()) { throw new NoSuchElementException(); } current = next; next = map.nextKey(next + 1); return current; } @Override public void remove() { if (current == -1) { throw new IllegalStateException(); } map.remove(current); current = -1; } } private static class KeySetView extends AbstractIntSet { private final Nat2ObjectDenseArrayMap map; KeySetView(Nat2ObjectDenseArrayMap map) { this.map = map; } @SuppressWarnings("MethodDoesntCallSuperMethod") @Override public KeySetView clone() { return this; } @Override public void forEach(IntConsumer action) { for (int index = map.nextKey(0); index >= 0; index = map.nextKey(index + 1)) { action.accept(index); } } @Override public IntIterator iterator() { return new KeySetIterator(map); } @Override public boolean remove(int key) { if (!map.containsKey(key)) { return false; } map.remove(key); return true; } @Override public int size() { return map.size(); } } private static class ValuesIterator implements ObjectIterator { private final Nat2ObjectDenseArrayMap map; private int current; private int next; ValuesIterator(Nat2ObjectDenseArrayMap map) { this.map = map; current = -1; next = map.nextKey(0); } @Override public boolean hasNext() { return next >= 0; } @SuppressWarnings("AccessingNonPublicFieldOfAnotherObject") @Override public V next() { if (!hasNext()) { throw new NoSuchElementException(); } V value = map.array[next]; current = next; next = map.nextKey(next + 1); return value; } @Override public void remove() { if (current == -1) { throw new IllegalStateException(); } map.remove(current); current = -1; } } private static class ValuesView extends AbstractObjectSet { private final Nat2ObjectDenseArrayMap map; ValuesView(Nat2ObjectDenseArrayMap map) { this.map = map; } @Override public void clear() { map.clear(); } @SuppressWarnings("unchecked") @Override public ValuesView clone() throws CloneNotSupportedException { return (ValuesView) super.clone(); } @SuppressWarnings("SuspiciousMethodCalls") @Override public boolean contains(Object v) { return map.containsValue(v); } @Override public boolean equals(Object o) { if (o == this) { return true; } if (!(o instanceof Collection)) { return false; } Collection other = (Collection) o; return other.size() == size() && containsAll(other); } @Override public int hashCode() { return HashCommon.mix(map.hashCode()); } @Override public ObjectIterator iterator() { return new ValuesIterator<>(map); } @Override public int size() { return map.size(); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy