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)