| /* |
| * 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"); |
| } |
| |
| } |