blob: 58bb18cf7224a895fa0d3540f2955d7998b8b5c2 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License 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 org.apache.tuscany;
import static java.util.Arrays.*;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
/**
* Utility functions to help work efficiently with iterable lists, inspired from Lisp.
*/
public class IterableUtil {
/**
* Convert an array or a variable list of arguments to an iterable list.
*/
public static <T> Iterable<T> list(final Object... a) {
return new ArrayIterable<T>(a, 0);
}
/**
* Convert an iterable list to a java.util.Collection.
*/
@SuppressWarnings("unchecked")
public static <T> Collection<T> collection(final Object l) {
final Collection<T> c = new ArrayList<T>();
for(final Object x : (Iterable<?>)l)
c.add((T)x);
return c;
}
/**
* Construct a new list from an element and a list.
*/
public static <T> Iterable<T> cons(final Object car, final Iterable<?> cdr) {
return new PairIterable<T>(car, cdr);
}
/**
* Return true if a list is nil (empty).
*/
public static boolean isNull(final Object l) {
if(l instanceof BasicIterable<?>)
return ((BasicIterable<?>)l).isNull();
if(l instanceof Collection<?>)
return ((Collection<?>)l).isEmpty();
return !((Iterable<?>)l).iterator().hasNext();
}
/**
* Return the car (first element) of a list.
*/
@SuppressWarnings("unchecked")
public static <T> T car(final Object l) {
if(l instanceof BasicIterable<?>)
return ((BasicIterable<T>)l).car();
if(l instanceof List<?>)
return (T)((List<?>)l).get(0);
return (T)((Iterable<?>)l).iterator().next();
}
/**
* Return the cdr (rest after the first element) of a list.
*/
@SuppressWarnings("unchecked")
public static <T> Iterable<T> cdr(final Object l) {
if(l instanceof BasicIterable<?>)
return ((BasicIterable<T>)l).cdr();
if(l instanceof List<?>)
return new ListIterable<T>((List<?>)l, 1);
if(l instanceof Collection<?>)
return new ArrayIterable<T>(((Collection<?>)l).toArray(), 1);
return new Iterable<T>() {
public Iterator<T> iterator() {
final Iterator<T> i = ((Iterable<T>)l).iterator();
i.next();
return i;
}
};
}
/**
* Return the car of the cdr of a list.
*/
@SuppressWarnings("unchecked")
public static <T> T cadr(final Object l) {
return (T)car(cdr(l));
}
/**
* Return the cdr of the cdr of a list.
*/
public static <T> Iterable<T> cddr(final Object l) {
return cdr(cdr(l));
}
/**
* Return the cdr of the cdr of the cdr of a list.
*/
public static <T> Iterable<T> cdddr(final Object l) {
return cdr(cdr(cdr(l)));
}
/**
* Return the car of the cdr of the cdr of a list.
*/
@SuppressWarnings("unchecked")
public static <T> T caddr(final Object l) {
return (T)car(cddr(l));
}
/**
* Return the car of the cdr of the cdr of the cdr of a list.
*/
@SuppressWarnings("unchecked")
public static <T> T cadddr(final Object l) {
return (T)car(cdddr(l));
}
/**
* Appends a list and another list.
*/
@SuppressWarnings("unchecked")
public static <T> Iterable<T> append(final Object a, final Object b) {
if (isNull(a))
return (Iterable<T>)b;
return cons(car(a), append(cdr(a), b));
}
/**
* Return the first pair matching a key from a list of key value pairs.
*/
public static <T> Iterable<T> assoc(final Object k, final Object l) {
if(isNull(l))
return list();
if(k.equals(car(car(l))))
return car(l);
return assoc(k, cdr(l));
}
/**
* Internal base implementation class for iterable and immutable lists.
*/
static abstract class BasicIterable<T> extends AbstractList<T> {
abstract T car();
abstract Iterable<T> cdr();
abstract Boolean isNull();
@Override
public int size() {
return this.isNull()? 0 : 1 + ((List<T>)this.cdr()).size();
}
@Override
public T get(final int index) {
throw new UnsupportedOperationException();
}
}
/**
* Internal implementation of a list backed by an array.
*/
static class ArrayIterable<T> extends BasicIterable<T> {
final Object[] a;
final int start;
ArrayIterable(final Object[] a, final int start) {
this.a = a;
this.start = start;
}
@Override
Boolean isNull() {
return this.a.length - this.start == 0;
}
@SuppressWarnings("unchecked")
@Override
T car() {
return (T)this.a[this.start];
}
@Override
BasicIterable<T> cdr() {
return new ArrayIterable<T>(this.a, this.start + 1);
}
@Override
public Iterator<T> iterator() {
return new Iterator<T>() {
int i = ArrayIterable.this.start;
public boolean hasNext() {
return this.i < ArrayIterable.this.a.length;
}
@SuppressWarnings("unchecked")
public T next() {
return (T)ArrayIterable.this.a[this.i++];
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
}
/**
* Internal implementation of a list backed by a java.util.List.
*/
static class ListIterable<T> extends BasicIterable<T> {
final List<?> l;
final int start;
ListIterable(final List<?> l, final int start) {
this.l = l;
this.start = start;
}
@Override
Boolean isNull() {
return this.l.size() - this.start == 0;
}
@SuppressWarnings("unchecked")
@Override
T car() {
return (T)this.l.get(this.start);
}
@Override
BasicIterable<T> cdr() {
return new ListIterable<T>(this.l, this.start + 1);
}
@Override
public Iterator<T> iterator() {
return new Iterator<T>() {
int i = ListIterable.this.start;
public boolean hasNext() {
return this.i < ListIterable.this.l.size();
}
@SuppressWarnings("unchecked")
public T next() {
return (T)ListIterable.this.l.get(this.i++);
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
}
/**
* Internal implementation of a list backed by an element / iterable pair.
*/
static class PairIterable<T> extends BasicIterable<T> {
final Object car;
final Iterable<?> cdr;
PairIterable(final Object car, final Iterable<?> cdr) {
this.car = car;
this.cdr = cdr;
}
@Override
Boolean isNull() {
return false;
}
@SuppressWarnings("unchecked")
@Override
T car() {
return (T)this.car;
}
@SuppressWarnings("unchecked")
@Override
Iterable<T> cdr() {
return (Iterable<T>)this.cdr;
}
@Override
public Iterator<T> iterator() {
return new Iterator<T>() {
boolean carIterator = true;
Iterator<?> cdrIterator = PairIterable.this.cdr.iterator();
public boolean hasNext() {
if(this.carIterator)
return true;
return this.cdrIterator.hasNext();
}
@SuppressWarnings("unchecked")
public T next() {
if(this.carIterator) {
this.carIterator = false;
return (T)PairIterable.this.car;
}
return (T)this.cdrIterator.next();
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
}
/**
* Test the list functions.
*/
static class Test {
Boolean testList() {
final Iterable<Object> l = list(2, 3, 4);
assert car(l) == Integer.valueOf(2);
assert cadr(l) == Integer.valueOf(3);
assert caddr(l) == Integer.valueOf(4);
final Iterable<Object> c = cons(0, cons(1, l));
assert car(c) == Integer.valueOf(0);
assert cadr(c) == Integer.valueOf(1);
assert caddr(c) == Integer.valueOf(2);
assert c.toString().equals("[0, 1, 2, 3, 4]");
final Iterable<Object> cl = cons(0, cons(1, new ArrayList<Object>(asList(2, 3, 4))));
assert car(cl) == Integer.valueOf(0);
assert cadr(cl) == Integer.valueOf(1);
assert caddr(cl) == Integer.valueOf(2);
assert cl.toString().equals("[0, 1, 2, 3, 4]");
final List<Object> jl = new ArrayList<Object>(collection(cl));
assert jl.size() == 5;
assert jl.get(0) == Integer.valueOf(0);
assert jl.get(1) == Integer.valueOf(1);
assert jl.get(2) == Integer.valueOf(2);
final Iterable<Object> n = list();
assert isNull(n);
assert n.toString().equals("[]");
final Iterable<Object> cn = cons(0, n);
assert !isNull(cn);
assert isNull(cdr(cn));
assert cn.toString().equals("[0]");
final Iterable<Object> al = new ArrayList<Object>(Arrays.asList(1, 2, 3));
assert car(al) == Integer.valueOf(1);
assert cadr(al) == Integer.valueOf(2);
assert caddr(al) == Integer.valueOf(3);
final Iterable<Object> a = list(0, 1, 2);
final Iterable<Object> b = list(3, 4);
final Iterable<Object> ab = append(a, b);
assert ab.toString().equals("[0, 1, 2, 3, 4]");
return true;
}
}
public static void main(final String[] args) {
System.out.println("Testing...");
Test.class.getClassLoader().setDefaultAssertionStatus(true);
new Test().testList();
System.out.println("OK");
}
}