code: /**
   *   Copyright (c) Rich Hickey. All rights reserved.
   *   The use and distribution terms for this software are covered by the
   *   Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
   *   which can be found in the file epl-v10.html at the root of this distribution.
   *   By using this software in any fashion, you are agreeing to be bound by
   * 	 the terms of this license.
   *   You must not remove this notice, or any other, from this software.
   **/
  
  /* rich Jun 19, 2006 */
  
  package clojure.lang;
  
  import java.lang.reflect.Array;
  
  public class ArraySeq extends ASeq implements IndexedSeq, IReduce{
  
  private static final long serialVersionUID = -9069152683729302290L;
  
  public final Object[] array;
  final int i;
  //ISeq _rest;
  
  static public ArraySeq create(){
  	return null;
  }
  
  static public ArraySeq create(Object... array){
  	if(array == null || array.length == 0)
  		return null;
  	return new ArraySeq(array, 0);
  }
  
  static ISeq createFromObject(Object array){
  	if(array == null || Array.getLength(array) == 0)
  		return null;
  	Class aclass = array.getClass();
  	if(aclass == int[].class)
  		return new ArraySeq_int(null, (int[]) array, 0);
  	if(aclass == float[].class)
  		return new ArraySeq_float(null, (float[]) array, 0);
  	if(aclass == double[].class)
  		return new ArraySeq_double(null, (double[]) array, 0);
  	if(aclass == long[].class)
  		return new ArraySeq_long(null, (long[]) array, 0);
  	if(aclass == byte[].class)
  		return new ArraySeq_byte(null, (byte[]) array, 0);
  	if(aclass == char[].class)
  		return new ArraySeq_char(null, (char[]) array, 0);
          if(aclass == short[].class)
              return new ArraySeq_short(null, (short[]) array, 0);
  	if(aclass == boolean[].class)
  		return new ArraySeq_boolean(null, (boolean[]) array, 0);
  	return new ArraySeq(array, 0);
  }
  
  ArraySeq(Object array, int i){
  	this.i = i;
  	this.array = (Object[]) array;
  //    this._rest = this;
  }
  
  ArraySeq(IPersistentMap meta, Object array, int i){
  	super(meta);
  	this.i = i;
  	this.array = (Object[]) array;
  }
  
  public Object first(){
  	if(array != null)
  		return array[i];
  	return null;
  }
  
  public ISeq next(){
  	if(array != null && i + 1 < array.length)
  		return new ArraySeq(array, i + 1);
  	return null;
  }
  
  public int count(){
  	if(array != null)
  		return array.length - i;
  	return 0;
  }
  
  public int index(){
  	return i;
  }
  
  public ArraySeq withMeta(IPersistentMap meta){
  	if(meta() == meta)
  		return this;
  	return new ArraySeq(meta, array, i);
  }
  
  public Object reduce(IFn f) {
  	if(array != null) {
  		Object ret = array[i];
  		for(int x = i + 1; x < array.length; x++)
  			{
  			ret = f.invoke(ret, array[x]);
  			if(RT.isReduced(ret))
  				return ((IDeref)ret).deref();
  			}
  		return ret;
  	}
  	return null;
  }
  
  public Object reduce(IFn f, Object start) {
  	if(array != null) {
  		Object ret = f.invoke(start, array[i]);
  		for(int x = i + 1; x < array.length; x++)
  			{
  			if(RT.isReduced(ret))
  				return ((IDeref)ret).deref();
  			ret = f.invoke(ret, array[x]);
  			}
  		if(RT.isReduced(ret))
  			return ((IDeref)ret).deref();
  		return ret;
  	}
  	return null;
  }
  
  public int indexOf(Object o) {
  	if(array != null)
  		for (int j = i; j < array.length; j++)
  			if (Util.equals(o, array[j])) return j - i;
  	return -1;
  }
  
  public int lastIndexOf(Object o) {
  	if (array != null) {
  		if (o == null) {
  			for (int j = array.length - 1 ; j >= i; j--)
  				if (array[j] == null) return j - i;
  		} else {
  			for (int j = array.length - 1 ; j >= i; j--)
  				if (o.equals(array[j])) return j - i;
  		}
  	}
  	return -1;
  }
  
  public Object[] toArray(){
  	int sz = this.array.length - this.i;
  	Object[] ret = new Object[sz];
  	System.arraycopy(this.array, i, ret, 0, sz);
  	return ret;
  }
  
  //////////////////////////////////// specialized primitive versions ///////////////////////////////
  
  static public class ArraySeq_int extends ASeq implements IndexedSeq, IReduce{
  	public final int[] array;
  	final int i;
  
  	ArraySeq_int(IPersistentMap meta, int[] array, int i){
  		super(meta);
  		this.array = array;
  		this.i = i;
  	}
  
  	public Object first(){
  		return array[i];
  	}
  
  	public ISeq next(){
  		if(i + 1 < array.length)
  			return new ArraySeq_int(meta(), array, i + 1);
  		return null;
  	}
  
  	public int count(){
  		return array.length - i;
  	}
  
  	public int index(){
  		return i;
  	}
  
  	public ArraySeq_int withMeta(IPersistentMap meta){
  		if(meta() == meta)
  			return this;
  		return new ArraySeq_int(meta, array, i);
  	}
  
  	public Object reduce(IFn f) {
  		Object ret = array[i];
  		for(int x = i + 1; x < array.length; x++)
  			{
  			ret = f.invoke(ret, array[x]);
  			if(RT.isReduced(ret))
  				return ((IDeref)ret).deref();
  			}
  		return ret;
  	}
  
  	public Object reduce(IFn f, Object start) {
  		Object ret = f.invoke(start, array[i]);
  		for(int x = i + 1; x < array.length; x++)
  			{
  			if(RT.isReduced(ret))
  				return ((IDeref)ret).deref();
  			ret = f.invoke(ret, array[x]);
  			}
  		if(RT.isReduced(ret))
  			return ((IDeref)ret).deref();
  		return ret;
  	}
  
  	public int indexOf(Object o) {
  		if (o instanceof Number) {
  			int k = ((Number) o).intValue();
  			for (int j = i; j < array.length; j++)
  				if (k == array[j]) return j - i;
  		}
  
  		return -1;
  	}
  	
  	public int lastIndexOf(Object o) {
  		if (o instanceof Number) {
  			int k = ((Number) o).intValue();
  			for (int j = array.length - 1; j >= i; j--)
  				if (k == array[j]) return j - i;
  		}
  
  		return -1;
  	}
  }
  
  
  static public class ArraySeq_float extends ASeq implements IndexedSeq, IReduce{
  	public final float[] array;
  	final int i;
  
  	ArraySeq_float(IPersistentMap meta, float[] array, int i){
  		super(meta);
  		this.array = array;
  		this.i = i;
  	}
  
  	public Object first(){
  		return Numbers.num(array[i]);
  	}
  
  	public ISeq next(){
  		if(i + 1 < array.length)
  			return new ArraySeq_float(meta(), array, i + 1);
  		return null;
  	}
  
  	public int count(){
  		return array.length - i;
  	}
  
  	public int index(){
  		return i;
  	}
  
  	public ArraySeq_float withMeta(IPersistentMap meta){
  		if(meta() == meta)
  			return this;
  		return new ArraySeq_float(meta, array, i);
  	}
  
  	public Object reduce(IFn f) {
  		Object ret = Numbers.num(array[i]);
  		for(int x = i + 1; x < array.length; x++)
  			{
  			ret = f.invoke(ret, Numbers.num(array[x]));
  			if(RT.isReduced(ret))
  				return ((IDeref)ret).deref();
  			}
  		return ret;
  	}
  
  	public Object reduce(IFn f, Object start) {
  		Object ret = f.invoke(start, Numbers.num(array[i]));
  		for(int x = i + 1; x < array.length; x++)
  			{
  			if(RT.isReduced(ret))
  				return ((IDeref)ret).deref();
  			ret = f.invoke(ret, Numbers.num(array[x]));
  			}
  		if(RT.isReduced(ret))
  			return ((IDeref)ret).deref();
  		return ret;
  	}
  
  	public int indexOf(Object o) {
  		if (o instanceof Number) {
  			float f = ((Number) o).floatValue();
  			for (int j = i; j < array.length; j++)
  				if (f == array[j]) return j - i;
  		}
  		return -1;
  	}
  	
  	public int lastIndexOf(Object o) {
  		if (o instanceof Number) {
  			float f = ((Number) o).floatValue();
  			for (int j = array.length - 1; j >= i; j--)
  				if (f == array[j]) return j - i;
  		}
  		return -1;
  	}
  }
  
  static public class ArraySeq_double extends ASeq implements IndexedSeq, IReduce{
  	public final double[] array;
  	final int i;
  
  	ArraySeq_double(IPersistentMap meta, double[] array, int i){
  		super(meta);
  		this.array = array;
  		this.i = i;
  	}
  
  	public Object first(){
  		return array[i];
  	}
  
  	public ISeq next(){
  		if(i + 1 < array.length)
  			return new ArraySeq_double(meta(), array, i + 1);
  		return null;
  	}
  
  	public int count(){
  		return array.length - i;
  	}
  
  	public int index(){
  		return i;
  	}
  
  	public ArraySeq_double withMeta(IPersistentMap meta){
  		if(meta() == meta)
  			return this;
  		return new ArraySeq_double(meta, array, i);
  	}
  
  	public Object reduce(IFn f) {
  		Object ret = array[i];
  		for(int x = i + 1; x < array.length; x++)
  			{
  			ret = f.invoke(ret, array[x]);
  			if(RT.isReduced(ret))
  				return ((IDeref)ret).deref();
  			}
  		return ret;
  	}
  
  	public Object reduce(IFn f, Object start) {
  		Object ret = f.invoke(start, array[i]);
  		for(int x = i + 1; x < array.length; x++)
  			{
  			if(RT.isReduced(ret))
  				return ((IDeref)ret).deref();
  			ret = f.invoke(ret, array[x]);
  			}
  		if(RT.isReduced(ret))
  			return ((IDeref)ret).deref();
  		return ret;
  	}
  
  	public int indexOf(Object o) {
  		if (o instanceof Number) {
  			double d = ((Number) o).doubleValue();
  			for (int j = i; j < array.length; j++)
  				if (d == array[j]) return j - i;
  		}
  
  		return -1;
  	}
  	
  	public int lastIndexOf(Object o) {
  		if (o instanceof Number) {
  			double d = ((Number) o).doubleValue();
  			for (int j = array.length - 1; j >= i; j--)
  				if (d == array[j]) return j - i;
  		}
  
  		return -1;
  	}
  }
  
  static public class ArraySeq_long extends ASeq implements IndexedSeq, IReduce{
  	public final long[] array;
  	final int i;
  
  	ArraySeq_long(IPersistentMap meta, long[] array, int i){
  		super(meta);
  		this.array = array;
  		this.i = i;
  	}
  
  	public Object first(){
  		return Numbers.num(array[i]);
  	}
  
  	public ISeq next(){
  		if(i + 1 < array.length)
  			return new ArraySeq_long(meta(), array, i + 1);
  		return null;
  	}
  
  	public int count(){
  		return array.length - i;
  	}
  
  	public int index(){
  		return i;
  	}
  
  	public ArraySeq_long withMeta(IPersistentMap meta){
  		if(meta() == meta)
  			return this;
  		return new ArraySeq_long(meta, array, i);
  	}
  
  	public Object reduce(IFn f) {
  		Object ret = Numbers.num(array[i]);
  		for(int x = i + 1; x < array.length; x++)
  			{
  			ret = f.invoke(ret, Numbers.num(array[x]));
  			if(RT.isReduced(ret))
  				return ((IDeref)ret).deref();
  			}
  		return ret;
  	}
  
  	public Object reduce(IFn f, Object start) {
  		Object ret = f.invoke(start, Numbers.num(array[i]));
  		for(int x = i + 1; x < array.length; x++)
  			{
  			if(RT.isReduced(ret))
  				return ((IDeref)ret).deref();
  			ret = f.invoke(ret, Numbers.num(array[x]));
  			}
  		if(RT.isReduced(ret))
  			return ((IDeref)ret).deref();
  		return ret;
  	}
  
  	public int indexOf(Object o) {
  		if (o instanceof Number) {
  			long l = ((Number) o).longValue();
  			for (int j = i; j < array.length; j++)
  				if (l == array[j]) return j - i;
  		}
  
  		return -1;
  	}
  	
  	public int lastIndexOf(Object o) {
  		if (o instanceof Number) {
  			long l = ((Number) o).longValue();
  			for (int j = array.length - 1; j >= i; j--)
  				if (l == array[j]) return j - i;
  		}
  
  		return -1;
  	}
  }
  
  static public class ArraySeq_byte extends ASeq implements IndexedSeq, IReduce{
  	public final byte[] array;
  	final int i;
  
  	ArraySeq_byte(IPersistentMap meta, byte[] array, int i){
  		super(meta);
  		this.array = array;
  		this.i = i;
  	}
  
  	public Object first(){
  		return array[i];
  	}
  
  	public ISeq next(){
  		if(i + 1 < array.length)
  			return new ArraySeq_byte(meta(), array, i + 1);
  		return null;
  	}
  
  	public int count(){
  		return array.length - i;
  	}
  
  	public int index(){
  		return i;
  	}
  
  	public ArraySeq_byte withMeta(IPersistentMap meta){
  		if(meta() == meta)
  			return this;
  		return new ArraySeq_byte(meta, array, i);
  	}
  
  	public Object reduce(IFn f) {
  		Object ret = array[i];
  		for(int x = i + 1; x < array.length; x++)
  			{
  			ret = f.invoke(ret, array[x]);
  			if(RT.isReduced(ret))
  				return ((IDeref)ret).deref();
  			}
  		return ret;
  	}
  
  	public Object reduce(IFn f, Object start) {
  		Object ret = f.invoke(start, array[i]);
  		for(int x = i + 1; x < array.length; x++)
  			{
  			if(RT.isReduced(ret))
  				return ((IDeref)ret).deref();
  			ret = f.invoke(ret, array[x]);
  			}
  		if(RT.isReduced(ret))
  			return ((IDeref)ret).deref();
  		return ret;
  	}
  
  	public int indexOf(Object o) {
  		if (o instanceof Byte) {
  			byte b = ((Byte) o).byteValue();
  			for (int j = i; j < array.length; j++)
  				if (b == array[j]) return j - i;
  		}
  		if (o == null) {
  			return -1;
  		}
  		for (int j = i; j < array.length; j++)
  			if (o.equals(array[j])) return j - i;
  		return -1;
  	}
  	
  	public int lastIndexOf(Object o) {
  		if (o instanceof Byte) {
  			byte b = ((Byte) o).byteValue();
  			for (int j = array.length - 1; j >= i; j--)
  				if (b == array[j]) return j - i;
  		}
  		if (o == null) {
  			return -1;
  		}
  		for (int j = array.length - 1; j >= i; j--)
  			if (o.equals(array[j])) return j - i;
  		return -1;
  	}
  }
  
  static public class ArraySeq_char extends ASeq implements IndexedSeq, IReduce{
  	public final char[] array;
  	final int i;
  
  	ArraySeq_char(IPersistentMap meta, char[] array, int i){
  		super(meta);
  		this.array = array;
  		this.i = i;
  	}
  
  	public Object first(){
  		return array[i];
  	}
  
  	public ISeq next(){
  		if(i + 1 < array.length)
  			return new ArraySeq_char(meta(), array, i + 1);
  		return null;
  	}
  
  	public int count(){
  		return array.length - i;
  	}
  
  	public int index(){
  		return i;
  	}
  
  	public ArraySeq_char withMeta(IPersistentMap meta){
  		if(meta() == meta)
  			return this;
  		return new ArraySeq_char(meta, array, i);
  	}
  
  	public Object reduce(IFn f) {
  		Object ret = array[i];
  		for(int x = i + 1; x < array.length; x++)
  			{
  			ret = f.invoke(ret, array[x]);
  			if(RT.isReduced(ret))
  				return ((IDeref)ret).deref();
  			}
  		return ret;
  	}
  
  	public Object reduce(IFn f, Object start) {
  		Object ret = f.invoke(start, array[i]);
  		for(int x = i + 1; x < array.length; x++)
  			{
  			if(RT.isReduced(ret))
  				return ((IDeref)ret).deref();
  			ret = f.invoke(ret, array[x]);
  			}
  		if(RT.isReduced(ret))
  			return ((IDeref)ret).deref();
  		return ret;
  	}
  	
  	public int indexOf(Object o) {
  		if (o instanceof Character) {
  			char c = ((Character) o).charValue();
  			for (int j = i; j < array.length; j++)
  				if (c == array[j]) return j - i;
  		}
  		if (o == null) {
  			return -1;
  		}
  		for (int j = i; j < array.length; j++)
  			if (o.equals(array[j])) return j - i;
  		return -1;
  	}
  	
  	public int lastIndexOf(Object o) {
  		if (o instanceof Character) {
  			char c = ((Character) o).charValue();
  			for (int j = array.length - 1; j >= i; j--)
  				if (c == array[j]) return j - i;
  		}
  		if (o == null) {
  			return -1;
  		}
  		for (int j = array.length - 1; j >= i; j--)
  			if (o.equals(array[j])) return j - i;
  		return -1;
  	}
  }
  
  static public class ArraySeq_short extends ASeq implements IndexedSeq, IReduce{
  	public final short[] array;
  	final int i;
  
  	ArraySeq_short(IPersistentMap meta, short[] array, int i){
  		super(meta);
  		this.array = array;
  		this.i = i;
  	}
  
  	public Object first(){
  		return array[i];
  	}
  
  	public ISeq next(){
  		if(i + 1 < array.length)
  			return new ArraySeq_short(meta(), array, i + 1);
  		return null;
  	}
  
  	public int count(){
  		return array.length - i;
  	}
  
  	public int index(){
  		return i;
  	}
  
  	public ArraySeq_short withMeta(IPersistentMap meta){
  		if(meta() == meta)
  			return this;
  		return new ArraySeq_short(meta, array, i);
  	}
  
  	public Object reduce(IFn f) {
  		Object ret = array[i];
  		for(int x = i + 1; x < array.length; x++)
  			{
  			ret = f.invoke(ret, array[x]);
  			if(RT.isReduced(ret))
  				return ((IDeref)ret).deref();
  			}
  		return ret;
  	}
  
  	public Object reduce(IFn f, Object start) {
  		Object ret = f.invoke(start, array[i]);
  		for(int x = i + 1; x < array.length; x++)
  			{
  			if(RT.isReduced(ret))
  				return ((IDeref)ret).deref();
  			ret = f.invoke(ret, array[x]);
  			}
  		if(RT.isReduced(ret))
  			return ((IDeref)ret).deref();
  		return ret;
  	}
  
  	public int indexOf(Object o) {
  		if (o instanceof Short) {
  			short s = ((Short) o).shortValue();
  			for (int j = i; j < array.length; j++)
  				if (s == array[j]) return j - i;
  		}
  		if (o == null) {
  			return -1;
  		}
  		for (int j = i; j < array.length; j++)
  			if (o.equals(array[j])) return j - i;
  		return -1;
  	}
  
  	public int lastIndexOf(Object o) {
  		if (o instanceof Short) {
  			short s = ((Short) o).shortValue();
  			for (int j = array.length - 1; j >= i; j--)
  				if (s == array[j]) return j - i;
  		}
  		if (o == null) {
  			return -1;
  		}
  		for (int j = array.length - 1; j >= i; j--)
  			if (o.equals(array[j])) return j - i;
  		return -1;
  	}
  }
  
  static public class ArraySeq_boolean extends ASeq implements IndexedSeq, IReduce{
  	public final boolean[] array;
  	final int i;
  
  	ArraySeq_boolean(IPersistentMap meta, boolean[] array, int i){
  		super(meta);
  		this.array = array;
  		this.i = i;
  	}
  
  	public Object first(){
  		return array[i];
  	}
  
  	public ISeq next(){
  		if(i + 1 < array.length)
  			return new ArraySeq_boolean(meta(), array, i + 1);
  		return null;
  	}
  
  	public int count(){
  		return array.length - i;
  	}
  
  	public int index(){
  		return i;
  	}
  
  	public ArraySeq_boolean withMeta(IPersistentMap meta){
  		if(meta() == meta)
  			return this;
  		return new ArraySeq_boolean(meta, array, i);
  	}
  
  	public Object reduce(IFn f) {
  		Object ret = array[i];
  		for(int x = i + 1; x < array.length; x++)
  			{
  			ret = f.invoke(ret, array[x]);
  			if(RT.isReduced(ret))
  				return ((IDeref)ret).deref();
  			}
  		return ret;
  	}
  
  	public Object reduce(IFn f, Object start) {
  		Object ret = f.invoke(start, array[i]);
  		for(int x = i + 1; x < array.length; x++)
  			{
  			if(RT.isReduced(ret))
  				return ((IDeref)ret).deref();
  			ret = f.invoke(ret, array[x]);
  			}
  		if(RT.isReduced(ret))
  			return ((IDeref)ret).deref();
  		return ret;
  	}
  	
  	public int indexOf(Object o) {
  		if (o instanceof Boolean) {
  			boolean b = ((Boolean) o).booleanValue();
  			for (int j = i; j < array.length; j++)
  				if (b == array[j]) return j - i;
  		}
  		if (o == null) {
  			return -1;
  		}
  		for (int j = i; j < array.length; j++)
  			if (o.equals(array[j])) return j - i;
  		return -1;
  	}
  	
  	public int lastIndexOf(Object o) {
  		if (o instanceof Boolean) {
  			boolean b = ((Boolean) o).booleanValue();
  			for (int j = array.length - 1; j >= i; j--)
  				if (b == array[j]) return j - i;
  		}
  		if (o == null) {
  			return -1;
  		}
  		for (int j = array.length - 1; j >= i; j--)
  			if (o.equals(array[j])) return j - i;
  		return -1;
  	}
  }
  
  }
  