Subversion Repositories splitter

Rev

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

/*
 * Copyright (c) 2009.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * 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.
 */


/**
 * Chris Miller
 */

package uk.me.parabola.splitter;

/**
 * Maintains a list of int primitives. Internally the ints are held
 * in multiple arrays so we can grow without having to copy one huge
 * array and momentarily require 2x the amount of memory.
 */

public class SplitIntList {
        private static final int DEFAULT_SEGMENT_SIZE = 1000000;

        private final int segmentSize;
        private int[][] segments = new int[0][];
        private int size;

        public SplitIntList() {
                this(DEFAULT_SEGMENT_SIZE);
        }

        public SplitIntList(int segmentSize) {
                this.segmentSize = segmentSize;
        }

        public void add(int value) {
                ensureCapacity();
                segments[segments.length - 1][size++ % segmentSize] = value;
        }

        public int get(int i) {
                return segments[i / segmentSize][i % segmentSize];
        }

        public int size() {
                return size;
        }

        private void ensureCapacity() {
                if (size % segmentSize == 0) {
                        int[][] temp = segments;
                        segments = new int[temp.length + 1][];
                        System.arraycopy(temp, 0, segments, 0, temp.length);
                        segments[temp.length] = new int[segmentSize];
                }
        }

        public Iterator getIterator() {
                return new Iterator();
        }

        /**
         * @return an iterator that deletes segments as it is finished with
         * them. This is useful when copying the contents into other lists
         * since it means we can free up some memory as we go rather than
         * holding it all until the copy has finished.
         */

        public Iterator getDeletingIterator() {
                return new Iterator(true);
        }

        /**
         * Iterates over all the segments.
         */

        public class Iterator {
                private final boolean deleteAfter;
                private int currentIndex;

                private Iterator(boolean deleteAfter) {
                        this.deleteAfter = deleteAfter;
                }

                private Iterator() {
                        this(false);
                }

                public boolean hasNext() {
                        return currentIndex < size;
                }

                public int next() {
                        int result = SplitIntList.this.get(currentIndex++);
                        if (deleteAfter && currentIndex % segmentSize == 0) {
                                // throw away the previous segment
                                segments[(currentIndex - 1) / segmentSize] = null;
                        }
                        return result;
                }
        }
}