de.prob.prolog.term.ListPrologTerm Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of prologlib Show documentation
Show all versions of prologlib Show documentation
Part of the ProB Parser library
The newest version!
/*
* (c) 2009-2022 Lehrstuhl fuer Softwaretechnik und Programmiersprachen, Heinrich
* Heine Universitaet Duesseldorf This software is licenced under EPL 1.0
* (http://www.eclipse.org/org/documents/epl-v10.html)
* */
package de.prob.prolog.term;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;
import java.util.Objects;
import de.prob.prolog.output.IPrologTermOutput;
/**
* Represents a Prolog list.
*/
public final class ListPrologTerm extends PrologTerm implements List {
private static final ListPrologTerm EMPTY_LIST = new ListPrologTerm(null, 0, 0);
private final PrologTerm[] elements;
private final int start;
private final int end;
public ListPrologTerm(final PrologTerm... elements) {
this.elements = elements != null && elements.length > 0 ? elements : null;
this.start = 0;
this.end = elements != null ? elements.length : 0;
}
private ListPrologTerm(final PrologTerm[] elements, final int start, final int end) {
this.elements = elements;
this.start = start;
this.end = end;
}
public static ListPrologTerm fromCollection(final Collection extends PrologTerm> elements) {
if (elements == null || elements.isEmpty()) {
return EMPTY_LIST;
}
return new ListPrologTerm(elements.toArray(new PrologTerm[0]));
}
public static ListPrologTerm emptyList() {
return EMPTY_LIST;
}
@Override
public String getFunctor() {
return isEmpty() ? "[]" : ".";
}
@Override
public int getArity() {
return this.isEmpty() ? 0 : 2;
}
@Override
public boolean isAtom() {
// The empty list is an atom in Prolog.
return this.isEmpty();
}
@Override
public boolean isCompound() {
return !this.isAtom();
}
@Override
public boolean isList() {
return true;
}
@Override
public PrologTerm getArgument(final int index) {
if (this.isEmpty()) {
throw new IndexOutOfBoundsException("List has no arguments");
} else if (index == 1) {
return this.head();
} else if (index == 2) {
return this.tail();
} else {
throw new IndexOutOfBoundsException("Argument index out of bounds");
}
}
@Override
public boolean hasFunctor(String functor) {
return this.isEmpty() ? "[]".equals(functor) : (".".equals(functor) || "[|]".equals(functor));
}
@Override
public int size() {
return end - start;
}
@Override
public PrologTerm get(final int index) {
int i = index + start;
if (i < start || i >= end) {
throw new ArrayIndexOutOfBoundsException();
}
return elements[i];
}
@Override
public void toTermOutput(final IPrologTermOutput pto) {
if (isEmpty()) {
pto.emptyList();
} else {
pto.openList();
for (PrologTerm t : this) {
t.toTermOutput(pto);
}
pto.closeList();
}
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
} else if (!(obj instanceof List>)) {
// does not work with the atom [] or the term .(H, T)
return false;
}
List> other = (List>) obj;
if (size() != other.size()) {
return false;
}
Iterator e1 = iterator();
Iterator> e2 = other.iterator();
while (e1.hasNext() && e2.hasNext()) {
PrologTerm o1 = e1.next();
Object o2 = e2.next();
if (!Objects.equals(o1, o2)) {
return false;
}
}
return !(e1.hasNext() || e2.hasNext());
}
@Override
public int hashCode() {
int result = 1;
for (int i = start; i < end; i++) {
result = 31 * result + elements[i].hashCode();
}
return result;
}
@Override
public Iterator iterator() {
return listIterator();
}
@Override
public boolean add(final PrologTerm o) {
throw new UnsupportedOperationException();
}
@Override
public boolean addAll(final Collection extends PrologTerm> c) {
throw new UnsupportedOperationException();
}
@Override
public void clear() {
throw new UnsupportedOperationException();
}
@Override
public boolean contains(final Object o) {
for (PrologTerm t : this) {
if (Objects.equals(t, o)) {
return true;
}
}
return false;
}
@Override
public boolean containsAll(final Collection> c) {
for (Object o : c) {
if (!contains(o)) {
return false;
}
}
return true;
}
@Override
public boolean isEmpty() {
return size() == 0;
}
@Override
public boolean remove(final Object o) {
throw new UnsupportedOperationException();
}
@Override
public boolean removeAll(final Collection> c) {
throw new UnsupportedOperationException();
}
@Override
public boolean retainAll(final Collection> c) {
throw new UnsupportedOperationException();
}
@Override
public Object[] toArray() {
if (isEmpty()) {
return new PrologTerm[0];
} else {
return Arrays.copyOfRange(elements, start, end);
}
}
@Override
@SuppressWarnings("unchecked")
public T[] toArray(T[] a) {
int size = size();
if (a.length < size) {
a = (T[]) Array.newInstance(a.getClass().getComponentType(), size);
}
if (size > 0) {
System.arraycopy(elements, 0, a, 0, size);
}
if (a.length > size) {
a[size] = null;
}
return a;
}
@Override
public void add(final int index, final PrologTerm element) {
throw new UnsupportedOperationException();
}
@Override
public boolean addAll(final int index, final Collection extends PrologTerm> c) {
throw new UnsupportedOperationException();
}
@Override
public int indexOf(final Object object) {
for (int i = 0, size = size(); i < size; i++) {
if (Objects.equals(get(i), object)) {
return i;
}
}
return -1;
}
@Override
public int lastIndexOf(final Object object) {
for (int i = size() - 1; i >= 0; i--) {
if (Objects.equals(get(i), object)) {
return i;
}
}
return -1;
}
@Override
public ListIterator listIterator() {
return listIterator(0);
}
@Override
public ListIterator listIterator(final int index) {
if (index < 0 || index > this.size()) {
throw new IndexOutOfBoundsException();
}
return new PrologTermListIterator(index);
}
@Override
public PrologTerm remove(final int index) {
throw new UnsupportedOperationException();
}
@Override
public PrologTerm set(final int index, final PrologTerm element) {
throw new UnsupportedOperationException();
}
@Override
public ListPrologTerm subList(int fromIndex, int toIndex) {
if (fromIndex < 0 || toIndex > this.size() || fromIndex > toIndex) {
throw new IndexOutOfBoundsException();
} else if (fromIndex == toIndex) {
return EMPTY_LIST;
}
return new ListPrologTerm(this.elements, this.start + fromIndex, this.start + toIndex);
}
public ListPrologTerm tail() {
return tail(1);
}
public ListPrologTerm tail(int start) {
if (start == 0) {
return this;
} else if (start < 0) {
throw new IllegalArgumentException("start must be non-negative");
}
int size = size();
if (size < start) {
throw new IllegalStateException("Cannot call tail on an empty list");
} else if (size == start) {
return EMPTY_LIST;
}
return new ListPrologTerm(this.elements, this.start + start, this.end);
}
public PrologTerm head() {
if (isEmpty()) {
throw new IllegalStateException("Cannot call head on an empty list");
}
return get(0);
}
private final class PrologTermListIterator implements ListIterator {
private int cursor;
PrologTermListIterator(int cursor) {
this.cursor = cursor;
}
@Override
public boolean hasNext() {
return cursor < size();
}
@Override
public PrologTerm next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
PrologTerm term = get(cursor);
cursor++;
return term;
}
@Override
public boolean hasPrevious() {
return cursor > 0;
}
@Override
public PrologTerm previous() {
if (!hasPrevious()) {
throw new NoSuchElementException();
}
--cursor;
return get(cursor);
}
@Override
public int nextIndex() {
return cursor;
}
@Override
public int previousIndex() {
return cursor - 1;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
@Override
public void set(PrologTerm t) {
throw new UnsupportedOperationException();
}
@Override
public void add(PrologTerm t) {
throw new UnsupportedOperationException();
}
}
}