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

package it.unimi.dsi.fastutil.ints;

import java.util.Arrays;
import java.io.IOException;
import java.nio.ByteOrder;
import java.nio.channels.FileChannel;
import java.nio.IntBuffer;

public class IntMappedBigList extends AbstractIntBigList
{
    public static int LOG2_BYTES;
    @Deprecated
    public static int LOG2_BITS;
    private static int CHUNK_SHIFT;
    public static final long CHUNK_SIZE;
    private static final long CHUNK_MASK;
    private final IntBuffer[] buffer;
    private final boolean[] readyToUse;
    private final int n;
    private final long size;
    
    protected IntMappedBigList(final IntBuffer[] buffer, final long size, final boolean[] readyToUse) {
        this.buffer = buffer;
        this.n = buffer.length;
        this.size = size;
        this.readyToUse = readyToUse;
        for (int i = 0; i < this.n; ++i) {
            if (i < this.n - 1 && buffer[i].capacity() != IntMappedBigList.CHUNK_SIZE) {
                throw new IllegalArgumentException();
            }
        }
    }
    
    public static IntMappedBigList map(final FileChannel fileChannel) throws IOException {
        return map(fileChannel, ByteOrder.BIG_ENDIAN);
    }
    
    public static IntMappedBigList map(final FileChannel fileChannel, final ByteOrder byteOrder) throws IOException {
        return map(fileChannel, byteOrder, FileChannel.MapMode.READ_ONLY);
    }
    
    public static IntMappedBigList map(final FileChannel fileChannel, final ByteOrder byteOrder, final FileChannel.MapMode mapMode) throws IOException {
        final long size = fileChannel.size() / 4L;
        final int chunks = (int)((size + (IntMappedBigList.CHUNK_SIZE - 1L)) / IntMappedBigList.CHUNK_SIZE);
        final IntBuffer[] buffer = new IntBuffer[chunks];
        for (int i = 0; i < chunks; ++i) {
            buffer[i] = fileChannel.map(mapMode, i * IntMappedBigList.CHUNK_SIZE * 4L, Math.min(IntMappedBigList.CHUNK_SIZE, size - i * IntMappedBigList.CHUNK_SIZE) * 4L).order(byteOrder).asIntBuffer();
        }
        final boolean[] readyToUse = new boolean[chunks];
        Arrays.fill(readyToUse, true);
        return new IntMappedBigList(buffer, size, readyToUse);
    }
    
    private IntBuffer IntBuffer(final int n) {
        if (this.readyToUse[n]) {
            return this.buffer[n];
        }
        this.readyToUse[n] = true;
        return this.buffer[n] = this.buffer[n].duplicate();
    }
    
    public IntMappedBigList copy() {
        return new IntMappedBigList(this.buffer.clone(), this.size, new boolean[this.n]);
    }
    
    @Override
    public int getInt(final long index) {
        return this.IntBuffer((int)(index >>> IntMappedBigList.CHUNK_SHIFT)).get((int)(index & IntMappedBigList.CHUNK_MASK));
    }
    
    @Override
    public void getElements(final long from, final int[] a, int offset, int length) {
        int chunk = (int)(from >>> IntMappedBigList.CHUNK_SHIFT);
        int displ = (int)(from & IntMappedBigList.CHUNK_MASK);
        while (length > 0) {
            final IntBuffer b = this.IntBuffer(chunk);
            final int l = Math.min(b.capacity() - displ, length);
            if (l == 0) {
                throw new ArrayIndexOutOfBoundsException();
            }
            b.position();
            b.get(a, offset, l);
            if ((displ += l) == IntMappedBigList.CHUNK_SIZE) {
                displ = 0;
                ++chunk;
            }
            offset += l;
            length -= l;
        }
    }
    
    @Override
    public int set(final long index, final int value) {
        final IntBuffer b = this.IntBuffer((int)(index >>> IntMappedBigList.CHUNK_SHIFT));
        final int i = (int)(index & IntMappedBigList.CHUNK_MASK);
        final int previousValue = b.get(i);
        b.put(i, value);
        return previousValue;
    }
    
    @Override
    public long size64() {
        return this.size;
    }
    
    static {
        IntMappedBigList.LOG2_BYTES = 63 - Long.numberOfLeadingZeros(4L);
        IntMappedBigList.LOG2_BITS = 63 - Long.numberOfLeadingZeros(4L);
        IntMappedBigList.CHUNK_SHIFT = 30 - IntMappedBigList.LOG2_BYTES;
        CHUNK_SIZE = 1L << IntMappedBigList.CHUNK_SHIFT;
        CHUNK_MASK = IntMappedBigList.CHUNK_SIZE - 1L;
    }
}
