blob: feef2ee3e241f9d5d0e90266d59fcbabd122d2ef [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package io.v.v23.vdl;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;
/**
* VdlArray is a representation of a VDL array. It has fixed length and it is
* backed by an array.
*
* @param <T> The type of the array element.
*/
public class VdlArray<T> extends VdlValue implements List<T> {
private static final long serialVersionUID = 1L;
private final T[] backingArray;
private final int start, end;
/**
* Creates a VDL array based on a backing array. The backing array
* isn't copied.
*
* @param type runtime VDL type of the wrapped array
* @param backingArray The array that backs the fixed length list.
*/
public VdlArray(VdlType type, final T[] backingArray) {
this(type, backingArray, 0, backingArray.length);
}
/**
* Creates a VDL array based on a backing array. The backing array
* isn't copied.
*
* @param type runtime VDL type of the wrapped array
* @param backingArray The array that backs the fixed length list.
* @param start The index in the array where the list should start
* (inclusive index)
* @param end The index after the point in the array where the list should
* end (exclusive index).
*/
public VdlArray(VdlType type, final T[] backingArray, final int start, final int end) {
super(type);
assertKind(Kind.ARRAY);
if (type.getLength() != end - start) {
throw new IllegalArgumentException(
"Length of the array should be the same as specified in VDL type");
}
if (start < 0 || end > backingArray.length) {
throw new IllegalArgumentException("indexes out of range of backing array");
}
this.backingArray = backingArray;
this.start = start;
this.end = end;
}
@Override
public int hashCode() {
// This specific hash code algorithm is required by the Java spec and
// defined in the List interface Javadoc.
int hashCode = 1;
for (T e : this) {
hashCode = 31 * hashCode + (e == null ? 0 : e.hashCode());
}
return hashCode;
}
private static boolean elementsEqual(Object e1, Object e2) {
if (e1 == null) {
return e2 == null;
}
return e1.equals(e2);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!(obj instanceof List))
return false;
List<?> other = (List<?>) obj;
if (other.size() != size()) {
return false;
}
for (int i = 0; i < size(); i++) {
Object e1 = other.get(i);
Object e2 = get(i);
if (!elementsEqual(e1, e2)) {
return false;
}
}
return true;
}
@Override
public String toString() {
return Arrays.deepToString(backingArray);
}
@Override
public void add(int location, T object) {
throw new UnsupportedOperationException("add() not supported");
}
@Override
public boolean add(T object) {
throw new UnsupportedOperationException("add() not supported");
}
@Override
public boolean addAll(int location, Collection<? extends T> collection) {
throw new UnsupportedOperationException("addAll() not supported");
}
@Override
public boolean addAll(Collection<? extends T> collection) {
throw new UnsupportedOperationException("addAll() not supported");
}
@Override
public void clear() {
throw new UnsupportedOperationException("clear() not supported");
}
@Override
public boolean contains(Object obj) {
return indexOf(obj) >= 0;
}
@Override
public boolean containsAll(Collection<?> collection) {
for (Object obj : collection) {
if (!this.contains(obj)) {
return false;
}
}
return true;
}
@Override
public T get(int location) {
if (location < start || location >= end) {
throw new IndexOutOfBoundsException("index " + location + " outside of range [" + start
+ "," + end + ")");
}
return backingArray[location];
}
@Override
public int indexOf(Object object) {
for (int i = start; i < end; i++) {
T t = backingArray[i];
if (elementsEqual(t, object)) {
return i - start;
}
}
return -1;
}
@Override
public int lastIndexOf(Object object) {
for (int i = end - 1; i >= start; i--) {
T t = backingArray[i];
if (elementsEqual(t, object)) {
return i - start;
}
}
return -1;
}
@Override
public boolean isEmpty() {
return start == end;
}
@Override
public Iterator<T> iterator() {
return listIterator();
}
@Override
public ListIterator<T> listIterator() {
return listIterator(0);
}
@Override
public ListIterator<T> listIterator(int location) {
return new VdlArrayIterator(location);
}
@Override
public T remove(int location) {
throw new UnsupportedOperationException("remove() not supported");
}
@Override
public boolean remove(Object object) {
throw new UnsupportedOperationException("remove() not supported");
}
@Override
public boolean removeAll(Collection<?> collection) {
throw new UnsupportedOperationException("removeAll() not supported");
}
@Override
public boolean retainAll(Collection<?> collection) {
throw new UnsupportedOperationException("retainAll() not supported");
}
@Override
public T set(int location, T object) {
if (location < start || location >= end) {
throw new IndexOutOfBoundsException("index " + location + " outside of range [" + start
+ "," + end + ")");
}
T prev = backingArray[location];
backingArray[location] = object;
return prev;
}
@Override
public int size() {
return end - start;
}
@Override
public List<T> subList(int start, int end) {
VdlType.Builder builder = new VdlType.Builder();
VdlType.PendingType subListType = builder.newPending(Kind.ARRAY)
.setLength(end - start).setElem(vdlType().getElem());
builder.build();
return new VdlArray<T>(subListType.built(), backingArray, start, end);
}
@Override
public Object[] toArray() {
return Arrays.copyOfRange(backingArray, start, end);
}
@Override
@SuppressWarnings("unchecked")
public <ToType> ToType[] toArray(ToType[] array) {
if (array.length < size()) {
return Arrays.copyOfRange(backingArray, start, end, (Class<ToType[]>) array.getClass());
}
System.arraycopy(backingArray, start, array, 0, size());
return array;
}
private class VdlArrayIterator implements ListIterator<T> {
private int position;
public VdlArrayIterator(int index) {
if (index < 0 || index >= VdlArray.this.size()) {
throw new IllegalArgumentException("Index out of bounds");
}
position = index + start;
}
@Override
public void add(T object) {
throw new UnsupportedOperationException("add() not supported");
}
@Override
public boolean hasNext() {
return position < end;
}
@Override
public boolean hasPrevious() {
return position > start;
}
@Override
public T next() {
if (position >= end) {
throw new NoSuchElementException("beyond end of list");
}
return backingArray[position++];
}
@Override
public int nextIndex() {
if (position >= end) {
return end - start;
}
return position - start;
}
@Override
public T previous() {
if (position < start) {
throw new NoSuchElementException("before beginning of list");
}
return backingArray[position--];
}
@Override
public int previousIndex() {
if (position < start) {
return 0;
}
return position - start;
}
@Override
public void remove() {
throw new UnsupportedOperationException("remove() not supported");
}
@Override
public void set(T object) {
throw new UnsupportedOperationException("set() not supported");
}
}
}