diff --git a/Clojure/Clojure/Clojure.csproj b/Clojure/Clojure/Clojure.csproj
index 4f6f99a30..65754216c 100644
--- a/Clojure/Clojure/Clojure.csproj
+++ b/Clojure/Clojure/Clojure.csproj
@@ -99,11 +99,15 @@
+
+
+
+
diff --git a/Clojure/Clojure/Lib/ArrayChunk.cs b/Clojure/Clojure/Lib/ArrayChunk.cs
new file mode 100644
index 000000000..fa769f4e5
--- /dev/null
+++ b/Clojure/Clojure/Lib/ArrayChunk.cs
@@ -0,0 +1,55 @@
+/**
+ * Copyright (c) David Miller. 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.
+ **/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace clojure.lang
+{
+ public class ArrayChunk : Indexed
+ {
+ #region Data
+
+ readonly object[] _array;
+ readonly int _off;
+
+ #endregion
+
+ #region C-tors
+
+ public ArrayChunk(object[] array, int off)
+ {
+ _array = array;
+ _off = off;
+ }
+
+ #endregion
+
+ #region Indexed Members
+
+ public object nth(int i)
+ {
+ return _array[_off + i];
+ }
+
+ #endregion
+
+ #region Counted Members
+
+ public int count()
+ {
+ return _array.Length - _off;
+ }
+
+ #endregion
+ }
+}
diff --git a/Clojure/Clojure/Lib/ChunkedCons.cs b/Clojure/Clojure/Lib/ChunkedCons.cs
new file mode 100644
index 000000000..808069474
--- /dev/null
+++ b/Clojure/Clojure/Lib/ChunkedCons.cs
@@ -0,0 +1,110 @@
+/**
+ * Copyright (c) David Miller. 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.
+ **/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace clojure.lang
+{
+ public class ChunkedCons : ASeq, IChunkedSeq
+ {
+ #region Data
+
+ readonly Indexed _chunk;
+ readonly ISeq _more;
+ readonly int _offset;
+
+ #endregion
+
+ #region C-tors
+
+ ChunkedCons(IPersistentMap meta, Indexed chunk, int offset, ISeq more)
+ : base(meta)
+ {
+ _chunk = chunk;
+ _offset = offset;
+ _more = more;
+ }
+
+ public ChunkedCons(Indexed chunk, ISeq more)
+ : this(chunk, 0, more)
+ {
+ }
+
+ public ChunkedCons(Indexed chunk, int offset, ISeq more)
+ {
+ _chunk = chunk;
+ _offset = offset;
+ _more = more;
+ }
+
+ #endregion
+
+ #region IObj methods
+
+ public override IObj withMeta(IPersistentMap meta)
+ {
+ return (meta == _meta)
+ ? this
+ :new ChunkedCons(meta, _chunk, _offset, _more);
+ }
+
+ #endregion
+
+ #region ISeq methods
+
+ public override object first()
+ {
+ return _chunk.nth(_offset);
+ }
+
+ public override ISeq next()
+ {
+ if (_offset + 1 < _chunk.count())
+ return new ChunkedCons(_chunk, _offset + 1, _more);
+ return chunkedNext();
+ }
+
+ #endregion
+
+ #region IChunkedSeq Members
+
+ public Indexed chunkedFirst()
+ {
+ return _chunk;
+ }
+
+ public ISeq chunkedNext()
+ {
+ return chunkedMore().seq();
+ }
+
+ public ISeq chunkedMore()
+ {
+ if (_more == null)
+ return PersistentList.EMPTY;
+ return _more;
+ }
+
+ #endregion
+
+ #region IPersistentCollection Members
+
+
+ //public new IPersistentCollection cons(object o)
+ //{
+ // throw new NotImplementedException();
+ //}
+
+ #endregion
+ }
+}
diff --git a/Clojure/Clojure/Lib/IChunkedSeq.cs b/Clojure/Clojure/Lib/IChunkedSeq.cs
new file mode 100644
index 000000000..6575ffa79
--- /dev/null
+++ b/Clojure/Clojure/Lib/IChunkedSeq.cs
@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) David Miller. 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.
+ **/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace clojure.lang
+{
+ public interface IChunkedSeq : ISeq
+ {
+ Indexed chunkedFirst();
+ ISeq chunkedNext();
+ ISeq chunkedMore();
+ }
+}
diff --git a/Clojure/Clojure/Lib/IPersistentVector.cs b/Clojure/Clojure/Lib/IPersistentVector.cs
index 1ea614c1e..14b929550 100644
--- a/Clojure/Clojure/Lib/IPersistentVector.cs
+++ b/Clojure/Clojure/Lib/IPersistentVector.cs
@@ -18,7 +18,7 @@ namespace clojure.lang
///
/// Represents an immutable vector (int-indexing).
///
- public interface IPersistentVector: Associative, Sequential, IPersistentStack, Reversible, Counted
+ public interface IPersistentVector: Associative, Sequential, IPersistentStack, Reversible, Indexed
{
///
/// Gets the number of items in the vector.
@@ -27,14 +27,6 @@ public interface IPersistentVector: Associative, Sequential, IPersistentStack, R
/// Not sure why you wouldn't use count() intead.
int length();
- ///
- /// Get the i-th item in the vector.
- ///
- /// The index of the item to retrieve/
- /// The i-th item
- /// Throws an exception if the index i is not in the range of the vector's elements.
- object nth(int i);
-
///
/// Return a new vector with the i-th value set to val.
///
diff --git a/Clojure/Clojure/Lib/Indexed.cs b/Clojure/Clojure/Lib/Indexed.cs
new file mode 100644
index 000000000..99157502e
--- /dev/null
+++ b/Clojure/Clojure/Lib/Indexed.cs
@@ -0,0 +1,27 @@
+/**
+ * Copyright (c) David Miller. 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.
+ **/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace clojure.lang
+{
+ public interface Indexed : Counted
+ {
+ ///
+ /// Returns the n-th item.
+ ///
+ /// Index of the item to access
+ /// The item at the given index
+ object nth(int i);
+ }
+}
diff --git a/Clojure/Clojure/Lib/LazySeq.cs b/Clojure/Clojure/Lib/LazySeq.cs
index 0362f5b69..2696b88f8 100644
--- a/Clojure/Clojure/Lib/LazySeq.cs
+++ b/Clojure/Clojure/Lib/LazySeq.cs
@@ -22,6 +22,7 @@ public sealed class LazySeq : Obj, ISeq, ICollection, IList // Should we do ILi
#region Data
private IFn _fn;
+ private object _sv;
private ISeq _s;
#endregion
@@ -77,12 +78,30 @@ public override IObj withMeta(IPersistentMap meta)
/// An for iteration.
[MethodImpl(MethodImplOptions.Synchronized)]
public ISeq seq()
+ {
+ sval();
+ if (_sv != null)
+ {
+ object ls = _sv;
+ _sv = null;
+ while (ls is LazySeq)
+ ls = ((LazySeq)ls).sval();
+ _s = RT.seq(ls);
+ }
+ return _s;
+ }
+
+ [MethodImpl(MethodImplOptions.Synchronized)]
+ object sval()
{
if (_fn != null)
{
- _s = RT.seq(_fn.invoke());
- _fn = null;
+ _sv = _fn.invoke();
+ _fn = null;
}
+ if ( _sv != null )
+ return _sv;
+
return _s;
}
diff --git a/Clojure/Clojure/Lib/PersistentVector.cs b/Clojure/Clojure/Lib/PersistentVector.cs
index 507ae4363..68386a5f5 100644
--- a/Clojure/Clojure/Lib/PersistentVector.cs
+++ b/Clojure/Clojure/Lib/PersistentVector.cs
@@ -137,18 +137,25 @@ int tailoff()
/// Throws an exception if the index i is not in the range of the vector's elements.
public override object nth(int i)
{
- if ( i >= 0 && i < _cnt )
+ object[] node = NodeFor(i);
+ return node[i & 0x01f];
+ }
+
+ object[] NodeFor(int i)
+ {
+ if (i >= 0 && i < _cnt)
{
- if ( i >= tailoff() )
- return _tail[i & 0x01f];
+ if (i >= tailoff())
+ return _tail;
object[] arr = _root;
- for ( int level = _shift; level > 0; level -= 5)
- arr = (object[]) arr[ (i >> level) & 0x01f];
- return arr[i & 0x01f];
+ for (int level = _shift; level > 0; level -= 5)
+ arr = (object[])arr[(i >> level) & 0x01f];
+ return arr;
}
throw new IndexOutOfRangeException();
}
+
///
/// Return a new vector with the i-th value set to val.
///
@@ -333,6 +340,118 @@ private object[] popTail(int shift, object[] arr, Box ptail)
+ #endregion
+
+ #region ChunkedSeq
+
+ public IChunkedSeq chunkedSeq()
+ {
+ if (count() == 0)
+ return null;
+ return new ChunkedSeq(this, 0, 0);
+ }
+
+ sealed public class ChunkedSeq : ASeq, IChunkedSeq
+ {
+ #region Data
+
+ readonly PersistentVector _vec;
+ readonly object[] _node;
+ readonly int _i;
+ readonly int _offset;
+
+ #endregion
+
+ #region C-tors
+
+ public ChunkedSeq(PersistentVector vec, int i, int offset)
+ {
+ _vec = vec;
+ _i = i;
+ _offset = offset;
+ _node = vec.NodeFor(i);
+ }
+
+ ChunkedSeq(IPersistentMap meta, PersistentVector vec, object[] node, int i, int offset)
+ : base(meta)
+ {
+ _vec = vec;
+ _node = node;
+ _i = i;
+ _offset = offset;
+ }
+
+ public ChunkedSeq(PersistentVector vec, object[] node, int i, int offset)
+ {
+ _vec = vec;
+ _node = node;
+ _i = i;
+ _offset = offset;
+ }
+
+ #endregion
+
+ #region IObj members
+
+
+ public override IObj withMeta(IPersistentMap meta)
+ {
+ return (meta == _meta)
+ ? this
+ : new ChunkedSeq(meta, _vec, _node, _i, _offset);
+ }
+
+ #endregion
+
+ #region IChunkedSeq Members
+
+ public Indexed chunkedFirst()
+ {
+ return new ArrayChunk(_node, _offset);
+ }
+
+ public ISeq chunkedNext()
+ {
+ if (_i + _node.Length < _vec._cnt)
+ return new ChunkedSeq(_vec, _i + _node.Length, 0);
+ return null;
+ }
+
+ public ISeq chunkedMore()
+ {
+ ISeq s = chunkedNext();
+ if (s == null)
+ return PersistentList.EMPTY;
+ return s;
+ }
+
+ #endregion
+
+ #region IPersistentCollection Members
+
+
+ //public new IPersistentCollection cons(object o)
+ //{
+ // throw new NotImplementedException();
+ //}
+
+ #endregion
+
+ public override object first()
+ {
+ return _node[_offset];
+ }
+
+ public override ISeq next()
+ {
+ if (_offset + 1 < _node.Length)
+ return new ChunkedSeq(_vec, _node, _i, _offset + 1);
+ return chunkedNext();
+ }
+
+ }
+
+
#endregion
}
}
diff --git a/Clojure/Clojure/Lib/RT.cs b/Clojure/Clojure/Lib/RT.cs
index f69327f3f..88617be13 100644
--- a/Clojure/Clojure/Lib/RT.cs
+++ b/Clojure/Clojure/Lib/RT.cs
@@ -623,10 +623,11 @@ public static IPersistentMap meta(object x)
public static int count(object o)
{
+ if (o is Counted)
+ return ((Counted)o).count();
+
if (o == null)
return 0;
- else if (o is Counted)
- return ((Counted)o).count();
else if (o is IPersistentCollection)
{
ISeq s = seq(o);
@@ -836,10 +837,10 @@ public static object dissoc(object coll, object key)
static public Object nth(Object coll, int n)
{
+ if (coll is Indexed)
+ return ((Indexed)coll).nth(n);
if (coll == null)
return null;
- else if (coll is IPersistentVector)
- return ((IPersistentVector)coll).nth(n);
else if (coll is String)
return ((string)coll)[n];
else if (coll.GetType().IsArray)