All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.ajjpj.abase.collection.immutable.AList Maven / Gradle / Ivy

Go to download

a-base is a library of basic (hence the name) classes, most notably immutable collection classes with copy-on-write operations

There is a newer version: 1.0-pre11
Show newest version
package com.ajjpj.abase.collection.immutable;

import com.ajjpj.abase.collection.ACollectionHelper;
import com.ajjpj.abase.collection.AEquality;
import com.ajjpj.abase.function.AFunction1;
import com.ajjpj.abase.function.APredicate;

import java.io.*;
import java.lang.reflect.Array;
import java.util.*;


/**
 * This is an immutable linked list implementation. It provides "mutators" that return copies of the list without
 *  affecting the original ("copy on write").

* * The API is based on terminology of functional languages. NIL is the empty list, head is the list's * first element, tail is the list without its first element, and cons() is the * operation that prepends an element to an existing list. * * @author arno */ abstract public class AList extends AbstractACollection> implements Serializable { private final int size; protected AList(int size) { this.size = size; } /** * Returns the empty list. All calls to this method are guaranteed to return the same instance. */ @SuppressWarnings("unchecked") public static AList nil() { return (AList) Nil.INSTANCE; } /** * Creates an AList based on the contents of an existing java.util.Iterable, copying its contents. */ public static AList create(Iterable elements) { if(elements instanceof List) { return create((List) elements); } AList result = nil(); for(T el: elements) { result = result.cons(el); } return result.reverse(); } /** * Creates an AList based on the contents of an existing java.util.List, copying its content. */ public static AList create(List elements) { AList result = nil(); for(int i=elements.size()-1; i>=0; i--) { result = result.cons(elements.get(i)); } return result; } /** * Creates an AList from a given list of elements. */ @SafeVarargs public static AList create(T... elements) { return create(Arrays.asList(elements)); } /** * Returns a read-only java.util.List view of this AList. */ public java.util.List asJavaUtilList() { return new JuListWrapper<>(this); } @Override protected AList createInternal(Collection elements) { return AList.create(elements); } @Override protected AEquality equalityForEquals() { return AEquality.EQUALS; } /** * Returns this AList's head, if any. */ public abstract AOption optHead(); /** * Returns the list's head, i.e. its first element. If called on the empty list, it throws a NoSuchElementException. */ public abstract T head(); /** * Returns the list's tail, i.e. the list without its first element. If called on the empty list, it throws a * NoSuchElementException. */ public abstract AList tail(); /** * Returns a new AList with the new element prepended. This is the only operation to 'add' elements to an AList. */ public AList cons(T el) { return new AHead<>(el, this); } /** * Returns a copy of this AList with elements in reversed order. */ public AList reverse() { AList remaining = this; AList result = nil(); while(! remaining.isEmpty()) { result = result.cons(remaining.head()); remaining = remaining.tail(); } return result; } public int size() { return size; } @Override public AList toList() { // override as an optimization return this; } @Override public AList map (AFunction1 f) throws E { return create(ACollectionHelper.map(this, f)); } @Override public AList flatMap(AFunction1, E> f) throws E { return create(ACollectionHelper.flatMap(this, f)); } @SuppressWarnings("unchecked") @Override public AList flatten() { return (AList) create(ACollectionHelper.flatten((Iterable>) this)); } /** * Returns a java.util.Iterator over this AList's elements, allowing ALists to be used with Java's * for(...: list) syntax introduced in version 1.5. */ @Override public Iterator iterator() { return new Iterator() { AList pos = AList.this; @Override public boolean hasNext() { return pos.nonEmpty(); } @Override public T next() { final T result = pos.head(); pos = pos.tail(); return result; } @Override public void remove() { throw new UnsupportedOperationException(); } }; } static final class AHead extends AList { private final T head; private final AList tail; AHead(T head, AList tail) { super(tail.size() + 1); this.head = head; this.tail = tail; } @Override public AOption optHead() { return AOption.some(head); } @Override public T head() { return head; } @Override public AList tail() { return tail; } } static final class Nil extends AList { public Nil() { super(0); } public static final Nil INSTANCE = new Nil(); private Object readResolve() { return INSTANCE; } @Override public AOption optHead() { return AOption.none(); } @Override public Object head() { throw new NoSuchElementException("no 'head' for an empty list."); } @Override public AList tail() { throw new NoSuchElementException("no 'tail' for an empty list."); } @Override public boolean forAll(APredicate pred) throws E { return true; } @Override public boolean exists(APredicate pred) throws E { return false; } } // ------------------------------- java.com.ajjpj.abase.util wrappers static class JuListIteratorWrapper implements java.util.ListIterator { private AList inner; private int idx; JuListIteratorWrapper(AList inner, int idx) { this.inner = inner; this.idx = idx; } @Override public boolean hasNext() { return ! inner.isEmpty(); } @Override public T next() { final T result = inner.head(); inner = inner.tail(); idx += 1; return result; } @Override public boolean hasPrevious() { return false; } @Override public T previous() { return null; } @Override public int nextIndex() { return idx+1; } @Override public int previousIndex() { return idx-1; } @Override public void remove() { throw new UnsupportedOperationException(); } @Override public void set(T t) { throw new UnsupportedOperationException(); } @Override public void add(T t) { throw new UnsupportedOperationException(); } } static class JuListWrapper implements java.util.List { private final AList inner; JuListWrapper(AList inner) { this.inner = inner; } @Override public int size() { return inner.size(); } @Override public boolean isEmpty() { return inner.isEmpty(); } @Override public boolean contains(Object o) { return indexOf(o) >= 0; } @Override public boolean containsAll(Collection c) { for(Object o: c) { if(! contains(o)) { return false; } } return true; } @Override public T get(int index) { AList l = inner; for(int i=0; i l = inner; while(! inner.isEmpty()) { if(AEquality.EQUALS.equals(inner.head(), o)) { return idx; } idx += 1; l = l.tail(); } return -1; } @Override public int lastIndexOf(Object o) { int idx = 0; AList l = inner; int result = -1; while(! inner.isEmpty()) { if(AEquality.EQUALS.equals(inner.head(), o)) { result = idx; } idx += 1; l = l.tail(); } return result; } @Override public Iterator iterator() { return listIterator(); } @Override public Object[] toArray() { final Object[] result = new Object[inner.size()]; int idx = 0; for(Object o: this) { result[idx] = o; idx += 1; } return result; } @SuppressWarnings("unchecked") @Override public T1[] toArray(T1[] a) { if(a.length < size()) { a = (T1[]) Array.newInstance(a.getClass().getComponentType(), size()); } if(a.length >= size()) { int idx = 0; for(Object o: this) { a[idx] = (T1) o; idx += 1; } if(a.length > size()) { a[size()] = null; } } return a; } @Override public ListIterator listIterator() { return new JuListIteratorWrapper<>(inner, 0); } @Override public ListIterator listIterator(int index) { AList l = inner; for(int i=0; i(l, index); } @Override public List subList(int fromIndex, int toIndex) { throw new UnsupportedOperationException(); } // ------------------- mutators @Override public T set(int index, T element) { throw new UnsupportedOperationException(); } @Override public void add(int index, T element) { throw new UnsupportedOperationException(); } @Override public T remove(int index) { throw new UnsupportedOperationException(); } @Override public boolean add(T t) { throw new UnsupportedOperationException(); } @Override public boolean remove(Object o) { throw new UnsupportedOperationException(); } @Override public boolean addAll(Collection c) { throw new UnsupportedOperationException(); } @Override public boolean addAll(int index, Collection c) { throw new UnsupportedOperationException(); } @Override public boolean removeAll(Collection c) { throw new UnsupportedOperationException(); } @Override public boolean retainAll(Collection c) { throw new UnsupportedOperationException(); } @Override public void clear() { throw new UnsupportedOperationException(); } } }