Mercurial > hg > Members > kono > jpf-core
diff src/main/gov/nasa/jpf/util/ObjVector.java @ 0:61d41facf527
initial v8 import (history reset)
author | Peter Mehlitz <Peter.C.Mehlitz@nasa.gov> |
---|---|
date | Fri, 23 Jan 2015 10:14:01 -0800 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/gov/nasa/jpf/util/ObjVector.java Fri Jan 23 10:14:01 2015 -0800 @@ -0,0 +1,631 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.util; + +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * more customizable alternative to java.util.Vector. Other than Vector, it + * supports dynamic growth on set() operations. While it supports list + * functions such as append, ObjVector resembles mostly an array, i.e. + * is meant to be a random-access collection + * + * this collection does not keep a count of non-null elements, but does maintain the + * highest set index as its size through set/add and remove operations. Note that size + * only shrinks through remove operations, not by setting null values. This means there + * is no guarantee that data[size-1] is not null. The converse however is true - there is no + * non-null element at an index >= size. + * + * @author pcd + */ +public class ObjVector<E> implements ReadOnlyObjList<E>, Cloneable { + public static final int defaultInitCap = 40; + + /** <i>size</i> as in a java.util.Vector. */ + protected int size; + + /** the backing array. */ + protected Object[] data; + + /** growth strategy. */ + protected Growth growth; + + + //--- constructors + + public ObjVector(Growth initGrowth, int initCap) { + growth = initGrowth; + data = new Object[initCap]; + size = 0; + } + + public ObjVector(Growth initGrowth) { + this(initGrowth,defaultInitCap); + } + + public ObjVector(int initCap) { + this(Growth.defaultGrowth, initCap); + } + + public ObjVector() { + this(Growth.defaultGrowth,defaultInitCap); + } + + public <F extends E> ObjVector(F[] init) { + this(init.length); + append(init); + } + + public <F extends E> ObjVector(ObjVector<F> from) { + this.data = new Object[from.data.length]; + this.size = from.size; + this.growth = from.growth; + System.arraycopy(from.data, 0, this.data, 0, size); + } + + //--- set/add/remove operations + + public void add(E x) { + if (size >= data.length) { + ensureCapacity(size+1); + } + data[size] = x; + size++; + } + + public void addNulls (int length) { + int newSize = size + length; + if (newSize > data.length) { + ensureCapacity(size + length); + } + for (int i = size; i < newSize; i++) { + data[i] = null; + } + size = newSize; + } + + public <F extends E> void append(F[] x) { + if (size + x.length > data.length) { + ensureCapacity(size + x.length); + } + System.arraycopy(x, 0, data, size, x.length); + size += x.length; + } + + public <F extends E> void append(F[] x, int pos, int len) { + if (size + len > data.length) { + ensureCapacity(size + len); + } + System.arraycopy(x, pos, data, size, len); + size += len; + } + + public <F extends E> void append(ObjVector<F> x) { + if (size + x.size > data.length) { + ensureCapacity(size + x.size); + } + System.arraycopy(x.data, 0, data, size, x.size); + size += x.size; + } + + @SuppressWarnings("unchecked") + public <F extends E> void append(ObjArray<F> x) { + append((F[])(x.data)); + } + + public <F extends E> void append(ArrayList<F> x){ + int n = x.size(); + int newSize = size + n; + if (newSize > data.length) { + ensureCapacity(newSize); + } + for (int i = size, j=0; i < newSize; i++,j++) { + data[i] = x.get(j); + } + size = newSize; + } + + public <F extends E> void addAll(Iterable<F> x) { + if (x instanceof ObjVector) { + append((ObjVector<F>) x); + return; + } + // else + if (x instanceof ObjArray) { + append((ObjArray<F>) x); + return; + } + // else + if (x == null) return; + // else + for (F e : x) { + add(e); + } + } + + public int nextNull (int fromIndex){ + for (int i=fromIndex; i<size; i++){ + if (data[i] == null){ + return i; + } + } + + ensureCapacity(size+1); + return size; + } + + @Override +@SuppressWarnings("unchecked") + public E get(int idx) { + if (idx >= size) { + return null; + } else { + return (E) data[idx]; + } + } + + public void set(int idx, E v) { + ensureSize(idx+1); + data[idx] = v; + } + + /** + * set range of values + * @param fromIndex first index (inclusive) + * @param toIndex last index (exclusive) + * @param val value to set + */ + public void setRange (int fromIndex, int toIndex, E val) { + ensureSize(toIndex); + Arrays.fill(data, fromIndex, toIndex, val); + } + + public <F> F[] toArray (F[] dst) { + System.arraycopy(data,0,dst,0,size); + return dst; + } + + public ObjArray<E> toObjArray () { + ObjArray<E> dst = new ObjArray<E>(size); + System.arraycopy(data,0,dst.data,0,size); + return dst; + } + + public int dumpTo (Object[] dst, int pos) { + System.arraycopy(data,0,dst,pos,size); + return pos + size; + } + + @Override + public ObjVector<E> clone() { + return new ObjVector<E>(this); + } + + public void squeeze() { + while (size > 0 && data[size - 1] == null) size--; + } + + public void setSize(int sz) { + if (sz > size) { + ensureCapacity(sz); + size = sz; + } else { + while (size > sz) { + size--; + data[size] = null; + } + } + } + + public void clear() { + // faster than iterating over the whole array + data = new Object[data.length]; + size = 0; + } + + @SuppressWarnings("unchecked") + public void clearAllSatisfying (Predicate<E> pred) { + Object[] d = data; + int newSize = 0; + for (int i=size-1; i>=0; i--) { + E e = (E)d[i]; + if (e != null) { + if (pred.isTrue(e)) { + d[i] = null; + } else { + if (newSize == 0) { + newSize = i+1; + } + } + } + } + + size = newSize; + } + + public int size() { + return size; + } + + @Override + public int length() { + return size; + } + + public void ensureSize(int sz) { + if (size < sz) { + ensureCapacity(sz); + size = sz; + } + } + + public void ensureCapacity(int desiredCap) { + if (data.length < desiredCap) { + Object[] newData = new Object[growth.grow(data.length, desiredCap)]; + System.arraycopy(data, 0, newData, 0, size); + data = newData; + } + } + + @SuppressWarnings("unchecked") + public void sort(Comparator<? super E> comp) { + Arrays.sort(data, 0, size, (Comparator<Object>) comp); + } + + public static <E> void copy(ObjVector<? extends E> src, int srcPos, + ObjVector<E> dst, int dstPos, int len) { + src.ensureCapacity(srcPos + len); + dst.ensureSize(dstPos+len); + System.arraycopy(src.data, srcPos, dst.data, dstPos, len); + } + + public static <E> void copy(ObjVector<? extends E> src, int srcPos, + E[] dst, int dstPos, int len) { + src.ensureCapacity(srcPos + len); + //dst.ensureSize(dstPos+len); + System.arraycopy(src.data, srcPos, dst, dstPos, len); + } + + /** + * remove all non-null elements between 'fromIdx' (inclusive) and + * 'toIdx' (exclusive) + * throw IndexOutOfBoundsException if index values are out of range + */ + public int removeRange(int fromIdx, int toIdx){ + int n = 0; + Object[] data = this.data; + + // it's the callers responsibility to ensure proper index ranges + //if (fromIdx < 0) fromIdx = 0; + //if (toIdx > size) toIdx = size; + + for (int i=fromIdx; i<toIdx; i++){ + if (data[i] != null){ + data[i] = null; + n++; + } + } + + if (toIdx >= size){ + int i=fromIdx-1; + for (; i>=0 && (data[i] == null); i--); + size = i+1; + } + + return n; + } + + public int removeFrom(int fromIdx){ + return removeRange(fromIdx,size); + } + + public E remove (int i) { + E e = (E) data[i]; + + if (e != null) { + data[i] = null; + if (i+1 == size) { + int j=i-1; + for (; j>=0 && (data[j] == null); j--); + size = j+1; + } + } + + return e; + } + + //--- store/restore snapshot operations + + static final int DEFAULT_MAX_GAP = 10; + + /** + * this is a block operation snapshot that stores chunks of original data with + * not more than DEFAULT_MAX_GAP consecutive null elements. Use this if + * elements can be stored directly + */ + public static class Snapshot<E> { + static class Block { + int baseIndex; + Object[] data; + Block next; + + Block (int baseIndex, Object[] data, Block next){ + this.baseIndex = baseIndex; + this.data = data; + this.next = next; + } + } + + // the ObjVector state we directly store + int size; + Growth growth; + + // where we keep the data + Block head; + + int saveBlock (Object[] d, int start, int end) { + int len = end-start+1; + Object[] bd = new Object[len]; + System.arraycopy(d, start, bd, 0, len); + head = new Block(start, bd, head); + + return len; + } + + Snapshot (ObjVector<E> v, int maxGap){ + int n = v.size; + size = n; + growth = v.growth; + Object[] d = v.data; + + int end = -1, start = -1; + + for (int i=n-1; (i>=0) && (n>0); i--) { + if (d[i] != null) { + if (start > 0 && (start - i) > maxGap ) { // store prev block + n -= saveBlock( d, start, end); + end = i; + start = i; + + } else { + if (end < 0) { + end = i; + } + start = i; + } + } + } + + if (end >=0 && end >= start) { + saveBlock( d, start, end); + } + } + + public void restore (ObjVector<E> v) { + // this is faster than iterating through the array + Object[] d = new Object[size]; + v.data = d; + + for (Block block = head; block != null; block = block.next) { + Object[] bd = block.data; + System.arraycopy(bd, 0, d, block.baseIndex, bd.length); + } + + v.size = size; + v.growth = growth; + } + } + + + public Snapshot<E> getSnapshot(){ + return new Snapshot<E>(this, DEFAULT_MAX_GAP); + } + + /** + * create a snapshot that doesn't store more than maxGap consecutive null values + */ + public Snapshot<E> getSnapshot( int maxGap){ + return new Snapshot<E>(this, maxGap); + } + + public void restore (Snapshot<E> snap) { + snap.restore(this); + } + + + /** + * snapshot that can mutate element values, but therefore can't use block operations. + * This is slower to store/restore, but can be more memory efficient if the elements + * are fragmented (lots of small holes in data) + */ + + public static class MutatingSnapshot<E,T>{ + T[] values; + int[] indices; + + @SuppressWarnings("unchecked") + MutatingSnapshot (ObjVector<E> vec, Transformer<E,T> transformer){ + E[] d = (E[])vec.data; + int size = vec.size; + int len = 0; + + //--- get number of non-null elements + for (int i=0; i<size; i++) { + if (d[i] != null) { + len++; + } + } + + //--- allocate data + T[] values = (T[])new Object[len]; + int[] indices = new int[len]; + + //--- fill it + int j=0; + for (int i=0; j < len; i++) { + if (d[i] != null) { + indices[j] = i; + values[j] = transformer.transform(d[i]); + j++; + } + } + + this.values = values; + this.indices = indices; + } + + @SuppressWarnings("unchecked") + protected void restore (ObjVector<E> vec, Transformer<T,E> transformer) { + T[] values = this.values; + int[] indices = this.indices; + int len = indices.length; + int size = indices[len-1] +1; + + vec.clear(); + vec.ensureSize(size); + E[] d = (E[])vec.data; + + for (int i=0; i<len; i++){ + E obj = transformer.transform(values[i]); + int index = indices[i]; + d[index] = obj; + } + + vec.size = size; + } + } + + public <T> MutatingSnapshot<E,T> getSnapshot( Transformer<E,T> transformer){ + return new MutatingSnapshot<E,T>(this, transformer); + } + + public <T> void restore (MutatingSnapshot<E,T> snap, Transformer<T,E> transformer) { + snap.restore(this, transformer); + } + + + //--- iterators + + /** + * iterator that goes over all elements regardless of value (i.e. also includes null values) + */ + protected class OVIterator implements Iterator<E> { + int idx = 0; + + @Override + public boolean hasNext () { + return idx < size; + } + + @Override + @SuppressWarnings("unchecked") + public E next () { + if (idx >= data.length) throw new NoSuchElementException(); + E e = (E) data[idx]; + idx++; + return e; + } + + @Override + public void remove () { + throw new UnsupportedOperationException(); + } + } + + @Override + public Iterator<E> iterator () { + return new OVIterator(); + } + + /** + * iterator that only includes element values that are not null + */ + protected class NonNullIterator implements Iterator<E>, Iterable<E> { + int idx = 0; + //int count = 0; + + @Override + public boolean hasNext() { + return (idx < size); // size is max set index + } + + @Override + @SuppressWarnings("unchecked") + public E next () { + int len = data.length; + for (int i=idx; i<len; i++){ + Object o = data[i]; + if (o != null){ + //count++; + idx = i+1; + return (E)o; + } + } + + throw new NoSuchElementException(); + } + + @Override + public void remove () { + throw new UnsupportedOperationException(); + } + + @Override + public Iterator<E> iterator() { + return this; + } + } + + + + public Iterator<E> nonNullIterator() { + return new NonNullIterator(); + } + + public Iterable<E> elements() { + return new NonNullIterator(); + } + + public void process (Processor<E> processor) { + for (int i=0; i<data.length; i++) { + Object o = data[i]; + if (o != null) { + processor.process( (E)o); + } + } + } + + //--- misc (debugging etc.) + + public void printOn (PrintStream ps) { + ps.println("ObjVector = ["); + for (int i=0; i<size; i++) { + ps.print(" "); + ps.print(i); + ps.print(": "); + ps.println(get(i)); + } + ps.println(']'); + } + +}