|
23 | 23 | */ |
24 | 24 |
|
25 | 25 | @SuppressWarnings("unchecked") |
26 | | -public class SortedSet extends ASortedSet implements IEditableCollection, ITransientCollection, Reversible { |
| 26 | +public class SortedSet extends ASortedSet implements IEditableCollection, ITransientCollection, Reversible, IReduce { |
27 | 27 |
|
28 | 28 | static Leaf[] EARLY_EXIT = new Leaf[0], |
29 | 29 | UNCHANGED = new Leaf[0]; |
@@ -168,10 +168,16 @@ public SortedSet withMeta(IPersistentMap meta) { |
168 | 168 | // Reversible |
169 | 169 | public ISeq rseq() { return rslice(null, null, _cmp); } |
170 | 170 |
|
171 | | - // IChunkedSeq |
172 | | - // public IChunk chunkedFirst() {} |
173 | | - // public ISeq chunkedNext() {} |
174 | | - // public ISeq chunkedMore() {} |
| 171 | + // IReduce |
| 172 | + public Object reduce(IFn f) { |
| 173 | + Seq seq = seq(); |
| 174 | + return seq == null ? f.invoke() : seq.reduce(f); |
| 175 | + } |
| 176 | + |
| 177 | + public Object reduce(IFn f, Object start) { |
| 178 | + Seq seq = seq(); |
| 179 | + return seq == null ? start : seq().reduce(f, start); |
| 180 | + } |
175 | 181 |
|
176 | 182 | // IPersistentCollection |
177 | 183 | public SortedSet empty() { |
@@ -870,9 +876,84 @@ public Object next() { |
870 | 876 | } |
871 | 877 | } |
872 | 878 |
|
| 879 | + // ===== CHUNK ===== |
| 880 | + static class Chunk implements IChunk { |
| 881 | + final Object[] _keys; |
| 882 | + final int _idx, _end; |
| 883 | + final boolean _asc; |
| 884 | + |
| 885 | + Chunk(Seq seq) { |
| 886 | + _asc = seq._asc; |
| 887 | + _idx = seq._idx; |
| 888 | + _keys = seq._node._keys; |
| 889 | + if (_asc) { |
| 890 | + int end = seq._node._len - 1; |
| 891 | + if (seq._keyTo != null) |
| 892 | + while (end > _idx && seq._cmp.compare(_keys[end], seq._keyTo) > 0) |
| 893 | + --end; |
| 894 | + _end = end; |
| 895 | + } else { |
| 896 | + int end = 0; |
| 897 | + if (seq._keyTo != null) |
| 898 | + while (end < _idx && seq._cmp.compare(_keys[end], seq._keyTo) < 0) |
| 899 | + ++end; |
| 900 | + _end = end; |
| 901 | + } |
| 902 | + } |
| 903 | + |
| 904 | + Chunk(Object[] keys, int idx, int end, boolean asc) { |
| 905 | + _keys = keys; |
| 906 | + _idx = idx; |
| 907 | + _end = end; |
| 908 | + _asc = asc; |
| 909 | + } |
| 910 | + |
| 911 | + public IChunk dropFirst() { |
| 912 | + if (_idx == _end) |
| 913 | + throw new IllegalStateException("dropFirst of empty chunk"); |
| 914 | + return new Chunk(_keys, _asc ? _idx+1 : _idx-1, _end, _asc); |
| 915 | + } |
| 916 | + |
| 917 | + public Object reduce(IFn f, Object start) { |
| 918 | + Object ret = f.invoke(start, _keys[_idx]); |
| 919 | + if (ret instanceof Reduced) |
| 920 | + return ((Reduced) ret).deref(); |
| 921 | + if (_asc) |
| 922 | + for (int x = _idx + 1; x <= _end; ++x) { |
| 923 | + ret = f.invoke(ret, _keys[x]); |
| 924 | + if (ret instanceof Reduced) |
| 925 | + return ((Reduced) ret).deref(); |
| 926 | + } |
| 927 | + else // !_asc |
| 928 | + for (int x = _idx - 1; x >= _end; --x) { |
| 929 | + ret = f.invoke(ret, _keys[x]); |
| 930 | + if (ret instanceof Reduced) |
| 931 | + return ((Reduced) ret).deref(); |
| 932 | + } |
| 933 | + return ret; |
| 934 | + } |
| 935 | + |
| 936 | + public Object nth(int i) { |
| 937 | + assert (i >= 0 && i < count()); |
| 938 | + return _asc ? _keys[_idx + i] : _keys[_idx - i]; |
| 939 | + } |
| 940 | + |
| 941 | + public Object nth(int i, Object notFound) { |
| 942 | + if (i >= 0 && i < count()) |
| 943 | + return nth(i); |
| 944 | + return notFound; |
| 945 | + } |
| 946 | + |
| 947 | + public int count() { |
| 948 | + if (_asc) return _end - _idx + 1; |
| 949 | + else return _idx - _end + 1; |
| 950 | + } |
| 951 | + } |
| 952 | + |
| 953 | + |
873 | 954 | // ===== SEQ ===== |
874 | 955 |
|
875 | | - class Seq extends ASeq implements IReduce, Reversible { |
| 956 | + class Seq extends ASeq implements IReduce, Reversible, IChunkedSeq { |
876 | 957 | Seq _parent; |
877 | 958 | Leaf _node; |
878 | 959 | int _idx; |
@@ -975,11 +1056,25 @@ public Object reduce(IFn f, Object start) { |
975 | 1056 | // Iterable |
976 | 1057 | public Iterator iterator() { return new JavaIter(clone()); } |
977 | 1058 |
|
978 | | - // clojure.lang.IChunkedSeq |
979 | | - // (chunkedFirst [this] (iter-chunk this)) |
980 | | - // (chunkedNext [this] (iter-chunked-next this)) |
981 | | - // (chunkedMore [this] (or (.chunkedNext this) ())) |
| 1059 | + // IChunkedSeq |
| 1060 | + public Chunk chunkedFirst() { return new Chunk(this); } |
| 1061 | + |
| 1062 | + public Seq chunkedNext() { |
| 1063 | + if (_parent == null) return null; |
| 1064 | + Seq nextParent = _parent.next(); |
| 1065 | + if (nextParent == null) return null; |
| 1066 | + Leaf node = nextParent.child(); |
| 1067 | + Seq seq = new Seq(meta(), nextParent, node, _asc ? 0 : node._len - 1, _keyTo, _cmp, _asc); |
| 1068 | + return seq.over() ? null : seq; |
| 1069 | + } |
| 1070 | + |
| 1071 | + public ISeq chunkedMore() { |
| 1072 | + Seq seq = chunkedNext(); |
| 1073 | + if (seq == null) return PersistentList.EMPTY; |
| 1074 | + return seq; |
| 1075 | + } |
982 | 1076 |
|
| 1077 | + // Reversible |
983 | 1078 | boolean atBeginning() { |
984 | 1079 | return _idx == 0 && (_parent == null || _parent.atBeginning()); |
985 | 1080 | } |
|
0 commit comments