Subversion Repositories splitter

Rev

Rev 170 | Blame | Compare with Previous | Last modification | View Log | RSS feed

package uk.me.parabola.splitter;

import java.util.Arrays;

import it.unimi.dsi.bits.Fast;
import it.unimi.dsi.fastutil.ints.Int2ShortFunction;
import it.unimi.dsi.fastutil.longs.LongArrayList;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import it.unimi.dsi.fastutil.shorts.ShortArrayList;

public class SparseInt2ShortMapInline  implements Int2ShortFunction {
        static final int CHUNK_SIZE = 64; // MUST be <= 64.
        static final int SIZE_INCR = 65536;
        /** What to return on unassigned indices */
        short unassigned = -1;
       
        ObjectArrayList<short []> valschunks;
        LongArrayList bitmasks;
        int capacity;
        int size;
        int lastTrim = 0;


        void arrayPush(short [] array, int index) {
                for (int j=array.length-1 ; j > index ; j--)
                        array[j]=array[j-1];
        }
        void arrayUnpush(short [] array,int index) {
                for (int j=index ; j < array.length ; j++)
                        array[j]=array[j+1];
                array[array.length-1] = unassigned;
        }

        void arrayCopyFill(short [] from, short [] to) {
                int j=0;
                for ( ; j < from.length ; j++)
                        to[j]=from[j];
                for ( ; j < to.length ; j++)
                        to[j] = unassigned;
        }
       
        short []chunkAdd(short[] array, int index, short val) {
                if (array[array.length-1] != unassigned) {
                        short tmp[] = new short[array.length+4];
                        arrayCopyFill(array,tmp);
                        array = tmp;
                }
                arrayPush(array,index);
                array[index] = val;
                return array;
        }
        short []chunkMake() {
                short out[] = new short[4];
                Arrays.fill(out,(short)4);
                return out;
                }
        void chunkSet(short[] array, int index, short val) {
                array[index] = val;
        }
        short chunkGet(short[] array, int index) {
                return array[index];
        }
        void chunkRem(short[] array, int index) {
                arrayUnpush(array,index);
        }
       
        void chunkAdd(ShortArrayList arraylist, int index, short val) {
                arraylist.add(index,val);
        }
        void chunkSet(ShortArrayList arraylist, int index, short val) {
                arraylist.set(index,val);
        }
        short chunkGet(ShortArrayList arraylist, int index) {
                return arraylist.get(index);
        }
        void chunkRem(ShortArrayList arraylist, int index) {
                arraylist.rem(index);
        }
       
        SparseInt2ShortMapInline() {
                clear();
        }
       
        void resizeTo(int key) {
                //for (int i = lastTrim ; i < capacity ; i += CHUNK_SIZE) {
                //      ShortArrayList tmp = valschunks.get(i/CHUNK_SIZE);
                //      if (tmp != null)
                //              valschunks.get(i/CHUNK_SIZE).trim();
                //}
                lastTrim = capacity;
               
                if (key <= capacity)
                        return;
                capacity = key + key/8 + SIZE_INCR;
                if (capacity < 0 || capacity > 2000000000)
                        capacity = 2000000000;
                bitmasks.size(1+capacity/CHUNK_SIZE);
                valschunks.size(1+capacity/CHUNK_SIZE);
        }

        /** Count how many of the lowest X bits in mask are set
         * @return */

        int countUnder(long mask, int lowest) {
                return Fast.count(mask & ((1L << lowest) -1));
        }
       
        public boolean containsKey(int key) {
                int chunkid = key/CHUNK_SIZE;
                int chunkoffset = key%CHUNK_SIZE;
                if (chunkid >= valschunks.size())
                        return false;
                long chunkmask = bitmasks.get(chunkid);
                long elementmask = 1L << chunkoffset;
                return (chunkmask & elementmask) != 0;
        }
       
        public short put(int key, short val) {
                if (val == unassigned) {
                        throw new IllegalArgumentException("Cannot store the value that is reserved as being unassigned. val="+val);
                }
                if (key < 0) {
                        throw new IllegalArgumentException("Cannot store the negative key,"+key);
                }

                resizeTo(key);
                int chunkid = key/CHUNK_SIZE;
                int chunkoffset = key%CHUNK_SIZE;
                if (valschunks.get(chunkid) == null)
                        valschunks.set(chunkid, chunkMake());
                short[] chunk = valschunks.get(chunkid);
                long chunkmask = bitmasks.get(chunkid);
                long elementmask = 1L << chunkoffset;
                if ((chunkmask & elementmask) != 0) {
                        // Already in the array, find the offset and store.
                        short out = chunkGet(chunk,countUnder(chunkmask,chunkoffset));
                        chunkSet(chunk,countUnder(chunkmask,chunkoffset), val);
                        //System.out.println("Returning found key "+out+" from put "+ key + " " + val);
                        return out;
                } else {
                        size++;
                        // Not in the array. Time to insert.
                        int offset = countUnder(chunkmask,chunkoffset);
                        valschunks.set(chunkid,chunkAdd(chunk,offset,val));
                        bitmasks.set(chunkid, elementmask | chunkmask);
                        //System.out.println("Returning unassigned from put "+ key + " " + val);
                        return unassigned;
                }
        }

        public short get(int key) {
                int chunkid = key/CHUNK_SIZE;
                int chunkoffset = key%CHUNK_SIZE;
                if (key <= 0 || chunkid >= valschunks.size())
                        return unassigned;
                short[] chunk = valschunks.get(chunkid);
                long chunkmask = bitmasks.get(chunkid);
                long elementmask = 1L << chunkoffset;
                if ((chunkmask & elementmask) == 0) {
                        return unassigned;
                } else {
                        return chunkGet(chunk,countUnder(chunkmask,chunkoffset));
                }
        }

        public short remove(int key) {
                int chunkid = key/CHUNK_SIZE;
                int chunkoffset = key%CHUNK_SIZE;
                if (chunkid >= valschunks.size())
                        return unassigned;
                short[] chunk = valschunks.get(chunkid);
                long chunkmask = bitmasks.get(chunkid);
                long elementmask = 1L << chunkoffset;
                if ((chunkmask & elementmask) == 0) {
                        // Not in the array.
                        // Do nothing;
                        return unassigned;
                } else {
                        size--;
                        // In the array. Time to insert.
                        int offset = countUnder(chunkmask,chunkoffset);
                        short out = chunkGet(chunk,offset);
                        chunkRem(chunk,offset);
                        bitmasks.set(chunkid, (~elementmask) & chunkmask);
                        return out;
                }              
        }

        @Override
        public void clear() {
                valschunks = new ObjectArrayList<short[]>();
                bitmasks = new LongArrayList();
                capacity = 0;
                size = 0;
        }

        @Override
        public boolean containsKey(Object arg0) {
                throw new UnsupportedOperationException("TODO: Implement");
        }

        @Override
        public Short get(Object arg0) {
                throw new UnsupportedOperationException("TODO: Implement");
        }

        @Override
        public Short put(Integer arg0, Short arg1) {
                return put(arg0.intValue(),arg1.shortValue());
        }

        @Override
        public Short remove(Object arg0) {
                throw new UnsupportedOperationException("TODO: Implement");
        }

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

        @Override
        public short defaultReturnValue() {
                return unassigned;
        }

        @Override
        public void defaultReturnValue(short arg0) {
                unassigned = arg0;
        }
}