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

de.tum.in.naturals.map.Int2DoubleSortedArrayMap 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.doubles.AbstractDoubleCollection;
import it.unimi.dsi.fastutil.doubles.DoubleArrays;
import it.unimi.dsi.fastutil.doubles.DoubleCollection;
import it.unimi.dsi.fastutil.doubles.DoubleIterator;
import it.unimi.dsi.fastutil.ints.AbstractInt2DoubleMap;
import it.unimi.dsi.fastutil.ints.AbstractIntSet;
import it.unimi.dsi.fastutil.ints.Int2DoubleMap;
import it.unimi.dsi.fastutil.ints.IntArrays;
import it.unimi.dsi.fastutil.ints.IntIterator;
import it.unimi.dsi.fastutil.ints.IntIterators;
import it.unimi.dsi.fastutil.ints.IntSet;
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.function.IntConsumer;
import javax.annotation.Nullable;

public class Int2DoubleSortedArrayMap extends AbstractInt2DoubleMap {
    private static final long serialVersionUID = 4177317104795467442L;

    @Nullable
    private transient EntrySetView entrySetView = null;

    @Nullable
    private transient KeySetView keySetView = null;

    private int[] keys;
    private int size = 0;
    private double[] values;

    @Nullable
    private transient ValuesView valuesView = null;

    @SuppressWarnings("OverridableMethodCallDuringObjectConstruction")
    public Int2DoubleSortedArrayMap(Map map) {
        if (map instanceof Int2DoubleSortedArrayMap) {
            Int2DoubleSortedArrayMap arrayMap = (Int2DoubleSortedArrayMap) map;
            size = arrayMap.size;
            keys = Arrays.copyOf(arrayMap.keys, size);
            values = Arrays.copyOf(arrayMap.values, size);
        } else {
            int size = map.size();
            keys = new int[size];
            values = new double[size];
            putAll(map);
        }
    }

    public Int2DoubleSortedArrayMap() {
        keys = IntArrays.EMPTY_ARRAY;
        values = DoubleArrays.EMPTY_ARRAY;
        size = 0;
    }

    public Int2DoubleSortedArrayMap(int capacity) {
        keys = new int[capacity];
        values = new double[capacity];
    }

    public Int2DoubleSortedArrayMap(Int2DoubleMap map) {
        this((Map) map);
    }

    public Int2DoubleSortedArrayMap(int key, double value) {
        keys = new int[] {key};
        values = new double[] {value};
    }

    private int keyIndex(int key) {
        return Arrays.binarySearch(keys, 0, size, key);
    }

    protected void removeIndex(int index) {
        assert index < size;
        int nextIndex = index + 1;
        if (nextIndex < size) {
            int tail = size - nextIndex;
            System.arraycopy(keys, nextIndex, keys, index, tail);
            System.arraycopy(values, nextIndex, values, index, tail);
        }
        size--;
    }

    public void trim() {
        if (keys.length == size) {
            return;
        }
        keys = Arrays.copyOf(keys, size);
        values = Arrays.copyOf(values, size);
    }

    @Override
    public boolean isEmpty() {
        return size == 0;
    }

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

    @Override
    public boolean containsKey(int key) {
        return keyIndex(key) >= 0;
    }

    @Override
    public boolean containsValue(double v) {
        long valueBits = Double.doubleToRawLongBits(v);
        double[] values = this.values;
        for (int index = 0; index < size; index++) {
            if (Double.doubleToRawLongBits(values[index]) == valueBits) {
                return true;
            }
        }
        return false;
    }

    @Override
    public double get(int key) {
        int index = keyIndex(key);
        return 0 <= index ? values[index] : defRetValue;
    }

    @Override
    public double getOrDefault(int key, double defaultValue) {
        int index = keyIndex(key);
        return 0 <= index ? values[index] : defaultValue;
    }

    @Override
    public double put(int key, double value) {
        if (keys.length == 0) {
            keys = new int[] {key, 0};
            values = new double[] {value, 0.0d};
            size = 1;
            return defRetValue;
        }

        int index = keyIndex(key);
        assert -(size + 1) <= index && index < size;

        if (index >= 0) {
            double oldValue = values[index];
            values[index] = value;
            return oldValue;
        }

        int insertionPoint = -(index + 1);
        int tailLength = size - insertionPoint;

        if (size == keys.length) {
            int newSize = size * 2;
            assert size < newSize;
            if (insertionPoint == size) {
                keys = Arrays.copyOf(keys, newSize);
                values = Arrays.copyOf(values, newSize);
                keys[insertionPoint] = key;
                values[insertionPoint] = value;
            } else {
                int[] newKeys = new int[newSize];
                System.arraycopy(keys, 0, newKeys, 0, insertionPoint);
                System.arraycopy(keys, insertionPoint, newKeys, insertionPoint + 1, tailLength);
                double[] newValues = new double[newSize];
                System.arraycopy(values, 0, newValues, 0, insertionPoint);
                System.arraycopy(values, insertionPoint, newValues, insertionPoint + 1, tailLength);

                keys = newKeys;
                values = newValues;
                newKeys[insertionPoint] = key;
                newValues[insertionPoint] = value;
            }
        } else if (insertionPoint == size) {
            keys[size] = key;
            values[size] = value;
        } else {
            assert insertionPoint < size && size < keys.length;
            assert 0 <= tailLength && insertionPoint + 1 + tailLength <= keys.length;

            System.arraycopy(keys, insertionPoint, keys, insertionPoint + 1, tailLength);
            System.arraycopy(values, insertionPoint, values, insertionPoint + 1, tailLength);
            keys[insertionPoint] = key;
            values[insertionPoint] = value;
        }
        size++;
        return defRetValue;
    }

    @Override
    public void clear() {
        size = 0;
    }

    @Override
    public double remove(int key) {
        int index = keyIndex(key);
        if (index < 0) {
            return defRetValue;
        }
        double value = values[index];
        removeIndex(index);
        return value;
    }

    @SuppressWarnings("NonFinalFieldReferenceInEquals")
    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o instanceof Int2DoubleSortedArrayMap) {
            Int2DoubleSortedArrayMap other = (Int2DoubleSortedArrayMap) o;
            return Arrays.equals(keys, 0, size, other.keys, 0, other.size)
                    && Arrays.equals(values, 0, size, other.values, 0, other.size);
        }
        return super.equals(o);
    }

    @SuppressWarnings("NonFinalFieldReferencedInHashCode")
    @Override
    public int hashCode() {
        int hash = HashCommon.mix(size);
        for (int i = 0; i < size; i++) {
            hash += HashCommon.mix(keys[i]);
            hash += Double.hashCode(values[i]);
        }
        return hash;
    }

    @Override
    public String toString() {
        if (isEmpty()) {
            return "{}";
        }

        StringBuilder builder = new StringBuilder(20 + size * 10);
        builder.append('{').append(keys[0]).append('=').append(values[0]);
        for (int keyIndex = 1; keyIndex < size; keyIndex++) {
            builder.append(", ").append(keys[keyIndex]).append("=>").append(values[keyIndex]);
        }
        builder.append('}');
        return builder.toString();
    }

    @SuppressWarnings("AssignmentOrReturnOfFieldWithMutableType")
    @Override
    public IntSet keySet() {
        if (keySetView == null) {
            keySetView = new KeySetView(this);
        }
        return keySetView;
    }

    @SuppressWarnings("AssignmentOrReturnOfFieldWithMutableType")
    @Override
    public DoubleCollection values() {
        if (valuesView == null) {
            valuesView = new ValuesView(this);
        }
        return valuesView;
    }

    @SuppressWarnings("AssignmentOrReturnOfFieldWithMutableType")
    @Override
    public ObjectSet int2DoubleEntrySet() {
        if (entrySetView == null) {
            entrySetView = new EntrySetView(this);
        }
        return entrySetView;
    }

    private static class EntryIterator implements ObjectIterator {
        private final Int2DoubleSortedArrayMap map;
        private int index = 0;

        EntryIterator(Int2DoubleSortedArrayMap map) {
            this.map = map;
        }

        @Override
        public boolean hasNext() {
            return index < map.size();
        }

        @Override
        public MapEntry next() {
            if (!hasNext()) {
                throw new NoSuchElementException();
            }
            MapEntry entry = new MapEntry(map, index);
            index += 1;
            return entry;
        }

        @Override
        public void remove() {
            if (index == 0) {
                throw new IllegalStateException();
            }
            index -= 1;
            map.removeIndex(index);
        }
    }

    private static class EntrySetView extends AbstractInt2DoubleEntrySet {
        EntrySetView(Int2DoubleSortedArrayMap 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);
        }
    }

    @SuppressWarnings("AccessingNonPublicFieldOfAnotherObject")
    private static class FastEntryIterator implements ObjectIterator {
        private final FastMapEntry entry;
        private final Int2DoubleSortedArrayMap map;

        FastEntryIterator(Int2DoubleSortedArrayMap map) {
            entry = new FastMapEntry(map);
            this.map = map;
        }

        @Override
        public boolean hasNext() {
            return entry.index + 1 < map.size;
        }

        @Override
        public Entry next() {
            if (!hasNext()) {
                throw new NoSuchElementException();
            }
            entry.index += 1;
            return entry;
        }

        @Override
        public void remove() {
            if (entry.index == -1) {
                throw new IllegalStateException();
            }
            map.removeIndex(entry.index);
        }
    }

    @SuppressWarnings("AccessingNonPublicFieldOfAnotherObject")
    private static class FastMapEntry extends AbstractInt2DoubleMap.BasicEntry {
        private final Int2DoubleSortedArrayMap map;
        int index = -1;

        public FastMapEntry(Int2DoubleSortedArrayMap map) {
            this.map = map;
        }

        @Override
        public double getDoubleValue() {
            return map.values[index];
        }

        @Override
        public int getIntKey() {
            return map.keys[index];
        }

        @Override
        public double setValue(double v) {
            double oldValue = map.values[index];
            map.values[index] = v;
            return oldValue;
        }
    }

    @SuppressWarnings("AccessingNonPublicFieldOfAnotherObject")
    private static class KeySetView extends AbstractIntSet {
        private final Int2DoubleSortedArrayMap map;

        KeySetView(Int2DoubleSortedArrayMap map) {
            this.map = map;
        }

        @SuppressWarnings("MethodDoesntCallSuperMethod")
        @Override
        public KeySetView clone() {
            return this;
        }

        @Override
        public void forEach(IntConsumer action) {
            int[] keys = map.keys;
            for (int index = 0; index < map.size; index++) {
                action.accept(keys[index]);
            }
        }

        @Override
        public IntIterator iterator() {
            return IntIterators.wrap(map.keys, 0, map.size);
        }

        @Override
        public boolean remove(int key) {
            if (!map.containsKey(key)) {
                return false;
            }
            map.remove(key);
            return true;
        }

        @Override
        public int size() {
            return map.size;
        }
    }

    @SuppressWarnings("AccessingNonPublicFieldOfAnotherObject")
    private static class MapEntry extends AbstractInt2DoubleMap.BasicEntry {
        private final int index;
        private final Int2DoubleSortedArrayMap map;

        MapEntry(Int2DoubleSortedArrayMap map, int index) {
            this.map = map;
            this.index = index;
        }

        @Override
        public double getDoubleValue() {
            return map.values[index];
        }

        @Override
        public int getIntKey() {
            return map.keys[index];
        }

        @Override
        public double setValue(double v) {
            double oldValue = map.values[index];
            map.values[index] = v;
            return oldValue;
        }
    }

    @SuppressWarnings("AccessingNonPublicFieldOfAnotherObject")
    private static class ValuesIterator implements DoubleIterator {
        private final Int2DoubleSortedArrayMap map;
        private int nextIndex = 0;

        ValuesIterator(Int2DoubleSortedArrayMap map) {
            this.map = map;
        }

        @Override
        public boolean hasNext() {
            return nextIndex < map.size;
        }

        @Override
        public double nextDouble() {
            if (!hasNext()) {
                throw new NoSuchElementException();
            }
            double value = map.values[nextIndex];
            nextIndex += 1;
            return value;
        }

        @Override
        public void remove() {
            if (nextIndex == 0) {
                throw new IllegalStateException();
            }
            nextIndex -= 1;
            map.removeIndex(nextIndex);
        }
    }

    @SuppressWarnings("AccessingNonPublicFieldOfAnotherObject")
    private static class ValuesView extends AbstractDoubleCollection {
        private final Int2DoubleSortedArrayMap map;

        ValuesView(Int2DoubleSortedArrayMap map) {
            this.map = map;
        }

        @Override
        public void clear() {
            map.clear();
        }

        @Override
        public boolean contains(double 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 map.hashCode() * 31;
        }

        @Override
        public DoubleIterator iterator() {
            return new ValuesIterator(map);
        }

        @Override
        public int size() {
            return map.size;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy