com.amazon.ion.impl.lite.IonSequenceLite Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ion-java Show documentation
Show all versions of ion-java Show documentation
A Java implementation of the Amazon Ion data notation.
/*
* Copyright 2007-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file 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 com.amazon.ion.impl.lite;
import com.amazon.ion.ContainedValueException;
import com.amazon.ion.IonSequence;
import com.amazon.ion.IonValue;
import com.amazon.ion.ValueFactory;
import com.amazon.ion.impl._Private_CurriedValueFactory;
import com.amazon.ion.impl._Private_IonValue;
import java.lang.reflect.Array;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Collection;
import java.util.ConcurrentModificationException;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
abstract class IonSequenceLite
extends IonContainerLite
implements IonSequence
{
/**
* A zero-length array.
*/
protected static final IonValueLite[] EMPTY_VALUE_ARRAY = new IonValueLite[0];
IonSequenceLite(ContainerlessContext context, boolean isNull)
{
super(context, isNull);
}
IonSequenceLite(IonSequenceLite existing, IonContext context) {
super(existing, context);
}
/**
* Constructs a sequence value not backed by binary.
*
* @param elements
* the initial set of child elements. If null
, then the new
* instance will have {@link #isNullValue()} == true
.
*
* @throws ContainedValueException if any value in elements
* has {@link IonValue#getContainer()} != null
.
* @throws IllegalArgumentException
* @throws NullPointerException
*/
IonSequenceLite(ContainerlessContext context,
Collection extends IonValue> elements)
throws ContainedValueException, NullPointerException,
IllegalArgumentException
{
this(context, (elements == null));
assert _children == null;
if (elements != null)
{
_children = new IonValueLite[elements.size()];
for (Iterator i = elements.iterator(); i.hasNext();)
{
IonValueLite element = (IonValueLite) i.next();
super.add(element);
}
}
}
//=========================================================================
@Override
public IonSequence clone() {
return (IonSequence) deepClone(false);
}
@Override
// Increasing visibility
public boolean add(IonValue element)
throws ContainedValueException, NullPointerException
{
// super.add will check for the lock
return super.add(element);
}
public boolean addAll(Collection extends IonValue> c)
{
checkForLock();
if (c == null) {
throw new NullPointerException();
}
boolean changed = false;
for (IonValue v : c)
{
changed = add(v) || changed;
}
return changed;
}
public boolean addAll(int index, Collection extends IonValue> c)
{
checkForLock();
if (c == null) {
throw new NullPointerException();
}
if (index < 0 || index > size())
{
throw new IndexOutOfBoundsException();
}
// TODO optimize to avoid n^2 shifting and renumbering of elements.
boolean changed = false;
for (IonValue v : c)
{
add(index++, v);
changed = true;
}
if (changed) {
patch_elements_helper(index);
}
return changed;
}
public ValueFactory add()
{
return new _Private_CurriedValueFactory(this.getSystem())
{
@Override
protected void handle(IonValue newValue)
{
add(newValue);
}
};
}
public void add(int index, IonValue element)
throws ContainedValueException, NullPointerException
{
add(index, (IonValueLite) element);
}
public ValueFactory add(final int index)
{
return new _Private_CurriedValueFactory(getSystem())
{
@Override
protected void handle(IonValue newValue)
{
add(index, newValue);
patch_elements_helper(index + 1);
}
};
}
public IonValue set(int index, IonValue element)
{
checkForLock();
final IonValueLite concrete = ((IonValueLite) element);
// NOTE: size calls makeReady() so we don't have to
if (index < 0 || index >= size())
{
throw new IndexOutOfBoundsException("" + index);
}
validateNewChild(element);
assert _children != null; // else index would be out of bounds above.
concrete._context = getContextForIndex(element, index);
IonValueLite removed = set_child(index, concrete);
concrete._elementid(index);
removed.detachFromContainer();
// calls setDirty(), UNLESS it hits an IOException
return removed;
}
public IonValue remove(int index)
{
checkForLock();
if (index < 0 || index >= get_child_count()) {
throw new IndexOutOfBoundsException("" + index);
}
IonValueLite v = get_child(index);
assert(v._elementid() == index);
remove_child(index);
patch_elements_helper(index);
return v;
}
public boolean remove(Object o)
{
checkForLock();
int idx = lastIndexOf(o);
if (idx < 0) {
return false;
}
assert(o instanceof IonValueLite); // since it's in our current array
assert( ((IonValueLite)o)._elementid() == idx );
remove_child(idx);
patch_elements_helper(idx);
return true;
}
public boolean removeAll(Collection> c)
{
boolean changed = false;
checkForLock();
// remove the collection member if it is a
// member of our child array keep track of
// the lowest array index for later patching
for (Object o : c) {
int idx = lastIndexOf(o);
if (idx >= 0) {
assert(o == get_child(idx));
remove_child(idx);
patch_elements_helper(idx);
changed = true;
}
}
return changed;
}
public boolean retainAll(Collection> c)
{
checkForLock();
if (get_child_count() < 1) return false;
// TODO this method (and probably several others) needs optimization.
IdentityHashMap keepers =
new IdentityHashMap();
for (Object o : c)
{
IonValue v = (IonValue) o;
if (this == v.getContainer()) keepers.put(v, v);
}
boolean changed = false;
for (int ii = get_child_count(); ii > 0; )
{
ii--;
IonValue v = get_child(ii);
if (! keepers.containsKey(v))
{
remove(v);
patch_elements_helper(ii);
changed = true;
}
}
return changed;
}
public boolean contains(Object o)
{
if (o == null) {
throw new NullPointerException();
}
if (!(o instanceof IonValue)) {
throw new ClassCastException();
}
return ((IonValue)o).getContainer() == this;
}
public boolean containsAll(Collection> c)
{
for (Object o : c)
{
if (! contains(o)) return false;
}
return true;
}
public int indexOf(Object o)
{
if (o == null) {
throw new NullPointerException();
}
_Private_IonValue v = (_Private_IonValue) o;
if (this != v.getContainer()) return -1;
return v.getElementId();
}
public int lastIndexOf(Object o)
{
return indexOf(o);
}
private static void checkSublistParameters(int size, int fromIndex, int toIndex)
{
if(fromIndex < 0)
{
throw new IndexOutOfBoundsException("fromIndex is less than zero");
}
if(toIndex < fromIndex)
{
throw new IllegalArgumentException("toIndex may not be less than fromIndex");
}
if(toIndex > size)
{
throw new IndexOutOfBoundsException("toIndex exceeds size");
}
}
public List subList(int fromIndex, int toIndex)
{
checkSublistParameters(this.size(), fromIndex, toIndex);
return new SubListView(fromIndex, toIndex);
}
public IonValue[] toArray()
{
if (get_child_count() < 1) return EMPTY_VALUE_ARRAY;
IonValue[] array = new IonValue[get_child_count()];
System.arraycopy(_children, 0, array, 0, get_child_count());
return array;
}
@SuppressWarnings("unchecked")
public T[] toArray(T[] a)
{
int size = get_child_count();
if (a.length < size)
{
// TODO JDK 1.6 this could use Arrays.copyOf
Class> type = a.getClass().getComponentType();
// generates unchecked warning
a = (T[]) Array.newInstance(type, size);
}
if (size > 0) {
System.arraycopy(_children, 0, a, 0, size);
}
if (size < a.length) {
// A surprising bit of spec.
// this is required even with a 0 entries
a[size] = null;
}
return a;
}
@SuppressWarnings("unchecked")
public T[] extract(Class type)
{
checkForLock();
if (isNullValue()) return null;
T[] array = (T[]) Array.newInstance(type, size());
toArray(array);
clear();
return array;
}
/**
* SubListView throws a {@link ConcurrentModificationException} if the parent list has any
* structural modifications, i.e. any operation that cause its size to change. To determine if
* a parent structural modification happened it keeps track of the structural modification count
* to compare against the parent
*
* Structural modifications from the sublist itself are allowed.
*/
private class SubListView extends AbstractList {
/**
* index in top level IonSequenceLite that marks the start of this sublist view. For nested
* sublists fromIndex will be in relation to the root parent which must be a IonSequenceLite
*/
private final int fromIndex;
private int size;
private SubListView(final int fromIndex, final int toIndex) {
this.fromIndex = fromIndex;
this.size = toIndex - fromIndex;
super.modCount = IonSequenceLite.this.structuralModificationCount;
}
@Override
public int size() {
checkForParentModification();
return size;
}
@Override
public boolean isEmpty() {
checkForParentModification();
return size == 0;
}
@Override
public IonValue get(final int index) {
checkForParentModification();
rangeCheck(index);
return IonSequenceLite.this.get(toParentIndex(index));
}
@Override
public IonValue set(final int index, final IonValue element) {
checkForParentModification();
rangeCheck(index);
return IonSequenceLite.this.set(toParentIndex(index), element);
}
@Override
public boolean contains(final Object o) {
checkForParentModification();
return super.contains(o);
}
@Override
public boolean containsAll(final Collection> collection) {
checkForParentModification();
return super.containsAll(collection);
}
@Override
public Object[] toArray() {
checkForParentModification();
return super.toArray();
}
@Override
public T[] toArray(T[] ts) {
checkForParentModification();
return super.toArray(ts);
}
@Override
public boolean add(final IonValue ionValue) {
checkForParentModification();
int parentIndex = toParentIndex(size);
// adds at end of parent list
if (parentIndex == IonSequenceLite.this.size()) {
IonSequenceLite.this.add(ionValue);
} else {
IonSequenceLite.this.add(parentIndex, ionValue);
}
super.modCount = IonSequenceLite.this.structuralModificationCount;
size++;
return true;
}
@Override
public void add(final int index, final IonValue ionValue) {
checkForParentModification();
rangeCheck(index);
IonSequenceLite.this.add(toParentIndex(index), ionValue);
super.modCount = IonSequenceLite.this.structuralModificationCount;
size++;
}
@Override
public boolean addAll(int i, Collection extends IonValue> collection) {
checkForParentModification();
return super.addAll(i, collection);
}
@Override
public boolean addAll(Collection extends IonValue> collection) {
checkForParentModification();
return super.addAll(collection);
}
// retainAll has no functionality that is specific to SubListView but
// needs to be implemented because the AbstractList.retainAll() throws [UnsupportedOperationException].
@Override
public boolean retainAll(final Collection> c) {
checkForParentModification();
if (size < 1) {
return false;
}
final Map