// 
// Decompiled by Procyon v0.6.0
// 

package it.unimi.dsi.fastutil.doubles;

import it.unimi.dsi.fastutil.objects.AbstractReferenceCollection;
import java.util.function.DoubleConsumer;
import it.unimi.dsi.fastutil.objects.ObjectSpliterators;
import java.util.Spliterator;
import it.unimi.dsi.fastutil.objects.ObjectSpliterator;
import java.util.function.Consumer;
import java.util.NoSuchElementException;
import it.unimi.dsi.fastutil.objects.AbstractObjectSet;
import java.util.Set;
import java.util.Collection;
import it.unimi.dsi.fastutil.objects.ObjectSet;
import java.io.ObjectInputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.Iterator;
import java.util.Map;
import it.unimi.dsi.fastutil.objects.ObjectIterator;
import it.unimi.dsi.fastutil.objects.ObjectArrays;
import it.unimi.dsi.fastutil.objects.ReferenceCollection;
import java.io.Serializable;

public class Double2ReferenceArrayMap<V> extends AbstractDouble2ReferenceMap<V> implements Serializable, Cloneable
{
    private static final long serialVersionUID = 1L;
    protected transient double[] key;
    protected transient Object[] value;
    protected int size;
    protected transient Double2ReferenceMap.FastEntrySet<V> entries;
    protected transient DoubleSet keys;
    protected transient ReferenceCollection<V> values;
    
    public Double2ReferenceArrayMap(final double[] key, final Object[] value) {
        this.key = key;
        this.value = value;
        this.size = key.length;
        if (key.length != value.length) {
            throw new IllegalArgumentException("Keys and values have different lengths (" + key.length + ", " + value.length + ")");
        }
    }
    
    public Double2ReferenceArrayMap() {
        this.key = DoubleArrays.EMPTY_ARRAY;
        this.value = ObjectArrays.EMPTY_ARRAY;
    }
    
    public Double2ReferenceArrayMap(final int capacity) {
        this.key = new double[capacity];
        this.value = new Object[capacity];
    }
    
    public Double2ReferenceArrayMap(final Double2ReferenceMap<V> m) {
        this(m.size());
        int i = 0;
        for (final Double2ReferenceMap.Entry<V> e : m.double2ReferenceEntrySet()) {
            this.key[i] = e.getDoubleKey();
            this.value[i] = e.getValue();
            ++i;
        }
        this.size = i;
    }
    
    public Double2ReferenceArrayMap(final Map<? extends Double, ? extends V> m) {
        this(m.size());
        int i = 0;
        for (final Map.Entry<? extends Double, ? extends V> e : m.entrySet()) {
            this.key[i] = (double)e.getKey();
            this.value[i] = e.getValue();
            ++i;
        }
        this.size = i;
    }
    
    public Double2ReferenceArrayMap(final double[] key, final Object[] value, final int size) {
        this.key = key;
        this.value = value;
        this.size = size;
        if (key.length != value.length) {
            throw new IllegalArgumentException("Keys and values have different lengths (" + key.length + ", " + value.length + ")");
        }
        if (size > key.length) {
            throw new IllegalArgumentException("The provided size (" + size + ") is larger than or equal to the backing-arrays size (" + key.length + ")");
        }
    }
    
    @Override
    public Double2ReferenceMap.FastEntrySet<V> double2ReferenceEntrySet() {
        if (this.entries == null) {
            this.entries = new EntrySet();
        }
        return this.entries;
    }
    
    private int findKey(final double k) {
        final double[] key = this.key;
        int i = this.size;
        while (i-- != 0) {
            if (Double.doubleToLongBits(key[i]) == Double.doubleToLongBits(k)) {
                return i;
            }
        }
        return -1;
    }
    
    @Override
    public V get(final double k) {
        final double[] key = this.key;
        int i = this.size;
        while (i-- != 0) {
            if (Double.doubleToLongBits(key[i]) == Double.doubleToLongBits(k)) {
                return (V)this.value[i];
            }
        }
        return this.defRetValue;
    }
    
    @Override
    public int size() {
        return this.size;
    }
    
    @Override
    public void clear() {
        int i = this.size;
        while (i-- != 0) {
            this.value[i] = null;
        }
        this.size = 0;
    }
    
    @Override
    public boolean containsKey(final double k) {
        return this.findKey(k) != -1;
    }
    
    @Override
    public boolean containsValue(final Object v) {
        int i = this.size;
        while (i-- != 0) {
            if (this.value[i] == v) {
                return true;
            }
        }
        return false;
    }
    
    @Override
    public boolean isEmpty() {
        return this.size == 0;
    }
    
    @Override
    public V put(final double k, final V v) {
        final int oldKey = this.findKey(k);
        if (oldKey != -1) {
            final V oldValue = (V)this.value[oldKey];
            this.value[oldKey] = v;
            return oldValue;
        }
        if (this.size == this.key.length) {
            final double[] newKey = new double[(this.size == 0) ? 2 : (this.size * 2)];
            final Object[] newValue = new Object[(this.size == 0) ? 2 : (this.size * 2)];
            int i = this.size;
            while (i-- != 0) {
                newKey[i] = this.key[i];
                newValue[i] = this.value[i];
            }
            this.key = newKey;
            this.value = newValue;
        }
        this.key[this.size] = k;
        this.value[this.size] = v;
        ++this.size;
        return this.defRetValue;
    }
    
    @Override
    public V remove(final double k) {
        final int oldPos = this.findKey(k);
        if (oldPos == -1) {
            return this.defRetValue;
        }
        final V oldValue = (V)this.value[oldPos];
        final int tail = this.size - oldPos - 1;
        System.arraycopy(this.key, oldPos + 1, this.key, oldPos, tail);
        System.arraycopy(this.value, oldPos + 1, this.value, oldPos, tail);
        --this.size;
        this.value[this.size] = null;
        return oldValue;
    }
    
    @Override
    public DoubleSet keySet() {
        if (this.keys == null) {
            this.keys = new KeySet();
        }
        return this.keys;
    }
    
    @Override
    public ReferenceCollection<V> values() {
        if (this.values == null) {
            this.values = new ValuesCollection();
        }
        return this.values;
    }
    
    public Double2ReferenceArrayMap<V> clone() {
        Double2ReferenceArrayMap<V> c;
        try {
            c = (Double2ReferenceArrayMap)super.clone();
        }
        catch (final CloneNotSupportedException cantHappen) {
            throw new InternalError();
        }
        c.key = this.key.clone();
        c.value = this.value.clone();
        c.entries = null;
        c.keys = null;
        c.values = null;
        return c;
    }
    
    private void writeObject(final ObjectOutputStream s) throws IOException {
        s.defaultWriteObject();
        for (int i = 0, max = this.size; i < max; ++i) {
            s.writeDouble(this.key[i]);
            s.writeObject(this.value[i]);
        }
    }
    
    private void readObject(final ObjectInputStream s) throws IOException, ClassNotFoundException {
        s.defaultReadObject();
        this.key = new double[this.size];
        this.value = new Object[this.size];
        for (int i = 0; i < this.size; ++i) {
            this.key[i] = s.readDouble();
            this.value[i] = s.readObject();
        }
    }
    
    private final class EntrySet extends AbstractObjectSet<Double2ReferenceMap.Entry<V>> implements Double2ReferenceMap.FastEntrySet<V>
    {
        @Override
        public ObjectIterator<Double2ReferenceMap.Entry<V>> iterator() {
            return new ObjectIterator<Double2ReferenceMap.Entry<V>>() {
                int curr = -1;
                int next = 0;
                
                @Override
                public boolean hasNext() {
                    return this.next < Double2ReferenceArrayMap.this.size;
                }
                
                @Override
                public Double2ReferenceMap.Entry<V> next() {
                    if (!this.hasNext()) {
                        throw new NoSuchElementException();
                    }
                    final double[] key = Double2ReferenceArrayMap.this.key;
                    final int next = this.next;
                    this.curr = next;
                    return new BasicEntry<V>(key[next], Double2ReferenceArrayMap.this.value[this.next++]);
                }
                
                @Override
                public void remove() {
                    if (this.curr == -1) {
                        throw new IllegalStateException();
                    }
                    this.curr = -1;
                    final int tail = Double2ReferenceArrayMap.this.size-- - this.next--;
                    System.arraycopy(Double2ReferenceArrayMap.this.key, this.next + 1, Double2ReferenceArrayMap.this.key, this.next, tail);
                    System.arraycopy(Double2ReferenceArrayMap.this.value, this.next + 1, Double2ReferenceArrayMap.this.value, this.next, tail);
                    Double2ReferenceArrayMap.this.value[Double2ReferenceArrayMap.this.size] = null;
                }
                
                @Override
                public void forEachRemaining(final Consumer<? super Double2ReferenceMap.Entry<V>> action) {
                    final int max = Double2ReferenceArrayMap.this.size;
                    while (this.next < max) {
                        final double[] key = Double2ReferenceArrayMap.this.key;
                        final int next = this.next;
                        this.curr = next;
                        action.accept((Object)new BasicEntry(key[next], Double2ReferenceArrayMap.this.value[this.next++]));
                    }
                }
            };
        }
        
        @Override
        public ObjectIterator<Double2ReferenceMap.Entry<V>> fastIterator() {
            return new ObjectIterator<Double2ReferenceMap.Entry<V>>() {
                int next = 0;
                int curr = -1;
                final BasicEntry<V> entry = new BasicEntry<V>();
                
                @Override
                public boolean hasNext() {
                    return this.next < Double2ReferenceArrayMap.this.size;
                }
                
                @Override
                public Double2ReferenceMap.Entry<V> next() {
                    if (!this.hasNext()) {
                        throw new NoSuchElementException();
                    }
                    final BasicEntry<V> entry = this.entry;
                    final double[] key = Double2ReferenceArrayMap.this.key;
                    final int next = this.next;
                    this.curr = next;
                    entry.key = key[next];
                    this.entry.value = (V)Double2ReferenceArrayMap.this.value[this.next++];
                    return this.entry;
                }
                
                @Override
                public void remove() {
                    if (this.curr == -1) {
                        throw new IllegalStateException();
                    }
                    this.curr = -1;
                    final int tail = Double2ReferenceArrayMap.this.size-- - this.next--;
                    System.arraycopy(Double2ReferenceArrayMap.this.key, this.next + 1, Double2ReferenceArrayMap.this.key, this.next, tail);
                    System.arraycopy(Double2ReferenceArrayMap.this.value, this.next + 1, Double2ReferenceArrayMap.this.value, this.next, tail);
                    Double2ReferenceArrayMap.this.value[Double2ReferenceArrayMap.this.size] = null;
                }
                
                @Override
                public void forEachRemaining(final Consumer<? super Double2ReferenceMap.Entry<V>> action) {
                    final int max = Double2ReferenceArrayMap.this.size;
                    while (this.next < max) {
                        final BasicEntry<V> entry = this.entry;
                        final double[] key = Double2ReferenceArrayMap.this.key;
                        final int next = this.next;
                        this.curr = next;
                        entry.key = key[next];
                        this.entry.value = (V)Double2ReferenceArrayMap.this.value[this.next++];
                        action.accept(this.entry);
                    }
                }
            };
        }
        
        @Override
        public ObjectSpliterator<Double2ReferenceMap.Entry<V>> spliterator() {
            return new EntrySetSpliterator(0, Double2ReferenceArrayMap.this.size);
        }
        
        @Override
        public void forEach(final Consumer<? super Double2ReferenceMap.Entry<V>> action) {
            for (int i = 0, max = Double2ReferenceArrayMap.this.size; i < max; ++i) {
                action.accept((Object)new BasicEntry(Double2ReferenceArrayMap.this.key[i], (V)Double2ReferenceArrayMap.this.value[i]));
            }
        }
        
        @Override
        public void fastForEach(final Consumer<? super Double2ReferenceMap.Entry<V>> action) {
            final BasicEntry<V> entry = new BasicEntry<V>();
            for (int i = 0, max = Double2ReferenceArrayMap.this.size; i < max; ++i) {
                entry.key = Double2ReferenceArrayMap.this.key[i];
                entry.value = (V)Double2ReferenceArrayMap.this.value[i];
                action.accept(entry);
            }
        }
        
        @Override
        public int size() {
            return Double2ReferenceArrayMap.this.size;
        }
        
        @Override
        public boolean contains(final Object o) {
            if (!(o instanceof Map.Entry)) {
                return false;
            }
            final Map.Entry<?, ?> e = (Map.Entry<?, ?>)o;
            if (e.getKey() == null || !(e.getKey() instanceof Double)) {
                return false;
            }
            final double k = (double)e.getKey();
            return Double2ReferenceArrayMap.this.containsKey(k) && Double2ReferenceArrayMap.this.get(k) == e.getValue();
        }
        
        @Override
        public boolean remove(final Object o) {
            if (!(o instanceof Map.Entry)) {
                return false;
            }
            final Map.Entry<?, ?> e = (Map.Entry<?, ?>)o;
            if (e.getKey() == null || !(e.getKey() instanceof Double)) {
                return false;
            }
            final double k = (double)e.getKey();
            final V v = (V)e.getValue();
            final int oldPos = Double2ReferenceArrayMap.this.findKey(k);
            if (oldPos == -1 || v != Double2ReferenceArrayMap.this.value[oldPos]) {
                return false;
            }
            final int tail = Double2ReferenceArrayMap.this.size - oldPos - 1;
            System.arraycopy(Double2ReferenceArrayMap.this.key, oldPos + 1, Double2ReferenceArrayMap.this.key, oldPos, tail);
            System.arraycopy(Double2ReferenceArrayMap.this.value, oldPos + 1, Double2ReferenceArrayMap.this.value, oldPos, tail);
            final Double2ReferenceArrayMap this$0 = Double2ReferenceArrayMap.this;
            --this$0.size;
            Double2ReferenceArrayMap.this.value[Double2ReferenceArrayMap.this.size] = null;
            return true;
        }
        
        final class EntrySetSpliterator extends ObjectSpliterators.EarlyBindingSizeIndexBasedSpliterator<Double2ReferenceMap.Entry<V>> implements ObjectSpliterator<Double2ReferenceMap.Entry<V>>
        {
            EntrySetSpliterator(final int pos, final int maxPos) {
                super(pos, maxPos);
            }
            
            @Override
            public int characteristics() {
                return 16465;
            }
            
            @Override
            protected final Double2ReferenceMap.Entry<V> get(final int location) {
                return new BasicEntry<V>(Double2ReferenceArrayMap.this.key[location], (V)Double2ReferenceArrayMap.this.value[location]);
            }
            
            @Override
            protected final EntrySetSpliterator makeForSplit(final int pos, final int maxPos) {
                return new EntrySetSpliterator(pos, maxPos);
            }
        }
    }
    
    private final class KeySet extends AbstractDoubleSet
    {
        @Override
        public boolean contains(final double k) {
            return Double2ReferenceArrayMap.this.findKey(k) != -1;
        }
        
        @Override
        public boolean remove(final double k) {
            final int oldPos = Double2ReferenceArrayMap.this.findKey(k);
            if (oldPos == -1) {
                return false;
            }
            final int tail = Double2ReferenceArrayMap.this.size - oldPos - 1;
            System.arraycopy(Double2ReferenceArrayMap.this.key, oldPos + 1, Double2ReferenceArrayMap.this.key, oldPos, tail);
            System.arraycopy(Double2ReferenceArrayMap.this.value, oldPos + 1, Double2ReferenceArrayMap.this.value, oldPos, tail);
            final Double2ReferenceArrayMap this$0 = Double2ReferenceArrayMap.this;
            --this$0.size;
            Double2ReferenceArrayMap.this.value[Double2ReferenceArrayMap.this.size] = null;
            return true;
        }
        
        @Override
        public DoubleIterator iterator() {
            return new DoubleIterator() {
                int pos = 0;
                
                @Override
                public boolean hasNext() {
                    return this.pos < Double2ReferenceArrayMap.this.size;
                }
                
                @Override
                public double nextDouble() {
                    if (!this.hasNext()) {
                        throw new NoSuchElementException();
                    }
                    return Double2ReferenceArrayMap.this.key[this.pos++];
                }
                
                @Override
                public void remove() {
                    if (this.pos == 0) {
                        throw new IllegalStateException();
                    }
                    final int tail = Double2ReferenceArrayMap.this.size - this.pos;
                    System.arraycopy(Double2ReferenceArrayMap.this.key, this.pos, Double2ReferenceArrayMap.this.key, this.pos - 1, tail);
                    System.arraycopy(Double2ReferenceArrayMap.this.value, this.pos, Double2ReferenceArrayMap.this.value, this.pos - 1, tail);
                    final Double2ReferenceArrayMap this$0 = Double2ReferenceArrayMap.this;
                    --this$0.size;
                    --this.pos;
                    Double2ReferenceArrayMap.this.value[Double2ReferenceArrayMap.this.size] = null;
                }
                
                @Override
                public void forEachRemaining(final DoubleConsumer action) {
                    final int max = Double2ReferenceArrayMap.this.size;
                    while (this.pos < max) {
                        action.accept(Double2ReferenceArrayMap.this.key[this.pos++]);
                    }
                }
            };
        }
        
        @Override
        public DoubleSpliterator spliterator() {
            return new KeySetSpliterator(0, Double2ReferenceArrayMap.this.size);
        }
        
        @Override
        public void forEach(final DoubleConsumer action) {
            for (int i = 0, max = Double2ReferenceArrayMap.this.size; i < max; ++i) {
                action.accept(Double2ReferenceArrayMap.this.key[i]);
            }
        }
        
        @Override
        public int size() {
            return Double2ReferenceArrayMap.this.size;
        }
        
        @Override
        public void clear() {
            Double2ReferenceArrayMap.this.clear();
        }
        
        final class KeySetSpliterator extends DoubleSpliterators.EarlyBindingSizeIndexBasedSpliterator implements DoubleSpliterator
        {
            KeySetSpliterator(final int pos, final int maxPos) {
                super(pos, maxPos);
            }
            
            @Override
            public int characteristics() {
                return 16721;
            }
            
            @Override
            protected final double get(final int location) {
                return Double2ReferenceArrayMap.this.key[location];
            }
            
            @Override
            protected final KeySetSpliterator makeForSplit(final int pos, final int maxPos) {
                return new KeySetSpliterator(pos, maxPos);
            }
            
            @Override
            public void forEachRemaining(final DoubleConsumer action) {
                final int max = Double2ReferenceArrayMap.this.size;
                while (this.pos < max) {
                    action.accept(Double2ReferenceArrayMap.this.key[this.pos++]);
                }
            }
        }
    }
    
    private final class ValuesCollection extends AbstractReferenceCollection<V>
    {
        @Override
        public boolean contains(final Object v) {
            return Double2ReferenceArrayMap.this.containsValue(v);
        }
        
        @Override
        public ObjectIterator<V> iterator() {
            return new ObjectIterator<V>() {
                int pos = 0;
                
                @Override
                public boolean hasNext() {
                    return this.pos < Double2ReferenceArrayMap.this.size;
                }
                
                @Override
                public V next() {
                    if (!this.hasNext()) {
                        throw new NoSuchElementException();
                    }
                    return (V)Double2ReferenceArrayMap.this.value[this.pos++];
                }
                
                @Override
                public void remove() {
                    if (this.pos == 0) {
                        throw new IllegalStateException();
                    }
                    final int tail = Double2ReferenceArrayMap.this.size - this.pos;
                    System.arraycopy(Double2ReferenceArrayMap.this.key, this.pos, Double2ReferenceArrayMap.this.key, this.pos - 1, tail);
                    System.arraycopy(Double2ReferenceArrayMap.this.value, this.pos, Double2ReferenceArrayMap.this.value, this.pos - 1, tail);
                    final Double2ReferenceArrayMap this$0 = Double2ReferenceArrayMap.this;
                    --this$0.size;
                    --this.pos;
                    Double2ReferenceArrayMap.this.value[Double2ReferenceArrayMap.this.size] = null;
                }
                
                @Override
                public void forEachRemaining(final Consumer<? super V> action) {
                    final int max = Double2ReferenceArrayMap.this.size;
                    while (this.pos < max) {
                        action.accept((Object)Double2ReferenceArrayMap.this.value[this.pos++]);
                    }
                }
            };
        }
        
        @Override
        public ObjectSpliterator<V> spliterator() {
            return new ValuesSpliterator(0, Double2ReferenceArrayMap.this.size);
        }
        
        @Override
        public void forEach(final Consumer<? super V> action) {
            for (int i = 0, max = Double2ReferenceArrayMap.this.size; i < max; ++i) {
                action.accept((Object)Double2ReferenceArrayMap.this.value[i]);
            }
        }
        
        @Override
        public int size() {
            return Double2ReferenceArrayMap.this.size;
        }
        
        @Override
        public void clear() {
            Double2ReferenceArrayMap.this.clear();
        }
        
        final class ValuesSpliterator extends ObjectSpliterators.EarlyBindingSizeIndexBasedSpliterator<V> implements ObjectSpliterator<V>
        {
            ValuesSpliterator(final int pos, final int maxPos) {
                super(pos, maxPos);
            }
            
            @Override
            public int characteristics() {
                return 16464;
            }
            
            @Override
            protected final V get(final int location) {
                return (V)Double2ReferenceArrayMap.this.value[location];
            }
            
            @Override
            protected final ValuesSpliterator makeForSplit(final int pos, final int maxPos) {
                return new ValuesSpliterator(pos, maxPos);
            }
            
            @Override
            public void forEachRemaining(final Consumer<? super V> action) {
                final int max = Double2ReferenceArrayMap.this.size;
                while (this.pos < max) {
                    action.accept((Object)Double2ReferenceArrayMap.this.value[this.pos++]);
                }
            }
        }
    }
}
