alloy2b.edu.mit.csail.sdg.alloy4.JoinableList Maven / Gradle / Ivy
/* Alloy Analyzer 4 -- Copyright (c) 2006-2009, Felix Chang
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify,
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package edu.mit.csail.sdg.alloy4;
import java.io.Serializable;
import java.util.AbstractList;
/** Immutable; implements a list where it is combine them; null values are NOT allowed. */
public final class JoinableList extends AbstractList implements Serializable {
/** This ensures the class can be serialized reliably. */
private static final long serialVersionUID = 0;
/** The number of items stored in this list.
* Invariant: count == (pre!=null ? pre.count : 0) + (item!=null ? 1 : 0) + (post!=null ? post.count : 0)
*/
private final int count;
/** The list of items before "this.item"; may be null. */
private final JoinableList pre;
/** The list of items after "this.item"; may be null. */
private final JoinableList post;
/** If nonnull, it stores an item. */
private final E item;
/** Construct a JoinableList object. */
private JoinableList(int count, JoinableList pre, E item, JoinableList post) {
this.count = count;
this.pre = pre;
this.item = item;
this.post = post;
}
/** Construct an empty list. */
public JoinableList() { this(0, null, null, null); }
/** Construct a list containing a single item, or return an empty list if item==null. */
public JoinableList(E item) { this((item!=null ? 1 : 0), null, item, null); }
/** Returns a list that represents the concatenation of this list and that list. */
public JoinableList make(JoinableList that) {
if (that == null || that.count == 0) return this; else if (count == 0) return that;
int sum = count + that.count;
if (sum < count) throw new OutOfMemoryError(); // integer overflow
if (post != null) return new JoinableList(sum, this, null, that); else return new JoinableList(sum, pre, item, that);
}
/** Returns a list that represents the result of appending newItem onto this list; if newItem==null we return this list as-is. */
public JoinableList make(E newItem) {
if (newItem == null) return this;
int sum = count + 1; // integer overflow
if (sum < 1) throw new OutOfMemoryError();
if (post != null) return new JoinableList(sum, this, newItem, null);
if (item != null) return new JoinableList(sum, pre, item, new JoinableList(newItem));
return new JoinableList(sum, pre, newItem, null);
}
/** If the list if nonempty, arbitrarily return one of the item, otherwise throw ArrayIndexOutOfBoundsException. */
public E pick() { if (item!=null) return item; else return get(0); }
/** Return the i-th element
* @throws ArrayIndexOutOfBoundsException if the given index doesn't exist
*/
@Override public E get(int i) {
if (i < 0 || i >= count) throw new ArrayIndexOutOfBoundsException();
JoinableList x = this;
while(true) {
int pre = (x.pre == null) ? 0 : x.pre.count;
if (i < pre) { x = x.pre; continue; }
if (x.item == null) { i = i - pre; x = x.post; } else if (i != pre) { i = i - pre - 1; x = x.post; } else return x.item;
}
}
/** Returns the number of elements in this list. */
@Override public int size() { return count; }
}