Skip to content

Commit 68ec7ed

Browse files
committed
added reduce-kv
1 parent 3bd2af4 commit 68ec7ed

7 files changed

+127
-0
lines changed

clojure.iml

+5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
3+
<component name="FacetManager">
4+
<facet type="Clojure" name="Clojure">
5+
<configuration />
6+
</facet>
7+
</component>
38
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_5" inherit-compiler-output="false">
49
<output url="file://$MODULE_DIR$/target/classes" />
510
<output-test url="file://$MODULE_DIR$/target/test-classes" />

src/clj/clojure/core.clj

+38
Original file line numberDiff line numberDiff line change
@@ -6032,6 +6032,44 @@
60326032
(let [s (seq coll)]
60336033
(clojure.core.protocols/internal-reduce s f val))))
60346034

6035+
(extend-protocol clojure.core.protocols/IKVReduce
6036+
;;slow path default
6037+
clojure.lang.IPersistentMap
6038+
(kv-reduce
6039+
[amap f init]
6040+
(reduce (fn [ret [k v]] (f ret k v)) init amap))
6041+
6042+
clojure.lang.PersistentHashMap
6043+
(kv-reduce
6044+
[amap f init]
6045+
(.kvreduce amap f init))
6046+
6047+
clojure.lang.PersistentArrayMap
6048+
(kv-reduce
6049+
[amap f init]
6050+
(.kvreduce amap f init))
6051+
6052+
clojure.lang.PersistentTreeMap
6053+
(kv-reduce
6054+
[amap f init]
6055+
(.kvreduce amap f init))
6056+
6057+
clojure.lang.PersistentVector
6058+
(kv-reduce
6059+
[vec f init]
6060+
(.kvreduce vec f init)))
6061+
6062+
(defn reduce-kv
6063+
"Reduces an associative collection. f should be a function of 3
6064+
arguments. Returns the result of applying f to init, the first key
6065+
and the first value in coll, then applying f to that result and the
6066+
2nd key and value, etc. If coll contains no entries, returns init
6067+
and f is not called. Note that reduce-kv is supported on vectors,
6068+
where the keys will be the ordinals."
6069+
{:added "1.4"}
6070+
([f init coll]
6071+
(clojure.core.protocols/kv-reduce coll f init)))
6072+
60356073
(defn into
60366074
"Returns a new coll consisting of to-coll with all of the items of
60376075
from-coll conjoined."

src/clj/clojure/core/protocols.clj

+4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
(ns clojure.core.protocols)
1010

11+
(set! *warn-on-reflection* true)
12+
1113
(defprotocol InternalReduce
1214
"Protocol for concrete seq types that can reduce themselves
1315
faster than first/next recursion. Called by clojure.core/reduce."
@@ -92,3 +94,5 @@
9294

9395
(emit-array-impls int long float double byte char boolean)
9496

97+
(defprotocol IKVReduce
98+
(kv-reduce [amap f init]))

src/jvm/clojure/lang/PersistentArrayMap.java

+7
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,13 @@ public void remove(){
279279

280280
}
281281

282+
public Object kvreduce(IFn f, Object init){
283+
for(int i=0;i < array.length;i+=2){
284+
init = f.invoke(init, array[i], array[i+1]);
285+
}
286+
return init;
287+
}
288+
282289
public ITransientMap asTransient(){
283290
return new TransientArrayMap(array);
284291
}

src/jvm/clojure/lang/PersistentHashMap.java

+45
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,14 @@ public Iterator iterator(){
178178
return new SeqIterator(seq());
179179
}
180180

181+
public Object kvreduce(IFn f, Object init){
182+
init = hasNull?f.invoke(init,null,nullValue):init;
183+
if(root != null){
184+
return root.kvreduce(f,init);
185+
}
186+
return init;
187+
}
188+
181189
public int count(){
182190
return count;
183191
}
@@ -311,6 +319,9 @@ static interface INode extends Serializable {
311319
INode assoc(AtomicReference<Thread> edit, int shift, int hash, Object key, Object val, Box addedLeaf);
312320

313321
INode without(AtomicReference<Thread> edit, int shift, int hash, Object key, Box removedLeaf);
322+
323+
public Object kvreduce(IFn f, Object init);
324+
314325
}
315326

316327
final static class ArrayNode implements INode{
@@ -371,6 +382,16 @@ public ISeq nodeSeq(){
371382
return Seq.create(array);
372383
}
373384

385+
public Object kvreduce(IFn f, Object init){
386+
for(INode node : array)
387+
{
388+
if(node != null)
389+
init = node.kvreduce(f,init);
390+
}
391+
return init;
392+
}
393+
394+
374395
private ArrayNode ensureEditable(AtomicReference<Thread> edit){
375396
if(this.edit == edit)
376397
return this;
@@ -600,6 +621,11 @@ public ISeq nodeSeq(){
600621
return NodeSeq.create(array);
601622
}
602623

624+
public Object kvreduce(IFn f, Object init){
625+
return NodeSeq.kvreduce(array,f,init);
626+
}
627+
628+
603629
private BitmapIndexedNode ensureEditable(AtomicReference<Thread> edit){
604630
if(this.edit == edit)
605631
return this;
@@ -784,6 +810,10 @@ public ISeq nodeSeq(){
784810
return NodeSeq.create(array);
785811
}
786812

813+
public Object kvreduce(IFn f, Object init){
814+
return NodeSeq.kvreduce(array,f,init);
815+
}
816+
787817
public int findIndex(Object key){
788818
for(int i = 0; i < 2*count; i+=2)
789819
{
@@ -1017,6 +1047,21 @@ static ISeq create(Object[] array) {
10171047
return create(array, 0, null);
10181048
}
10191049

1050+
static public Object kvreduce(Object[] array, IFn f, Object init){
1051+
for(int i=0;i<array.length;i+=2)
1052+
{
1053+
if(array[i] != null)
1054+
init = f.invoke(init, array[i], array[i+1]);
1055+
else
1056+
{
1057+
INode node = (INode) array[i+1];
1058+
if(node != null)
1059+
init = node.kvreduce(f,init);
1060+
}
1061+
}
1062+
return init;
1063+
}
1064+
10201065
private static ISeq create(Object[] array, int i, ISeq s) {
10211066
if(s != null)
10221067
return new NodeSeq(null, array, i, s);

src/jvm/clojure/lang/PersistentTreeMap.java

+17
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,13 @@ public NodeIterator iterator(){
205205
return new NodeIterator(tree, true);
206206
}
207207

208+
public Object kvreduce(IFn f, Object init){
209+
if(tree != null)
210+
return tree.kvreduce(f,init);
211+
return init;
212+
}
213+
214+
208215
public NodeIterator reverseIterator(){
209216
return new NodeIterator(tree, false);
210217
}
@@ -529,6 +536,16 @@ Node balanceRight(Node parent){
529536

530537
abstract Node replace(Object key, Object val, Node left, Node right);
531538

539+
public Object kvreduce(IFn f, Object init){
540+
init = f.invoke(init, key(), val());
541+
if(left() != null)
542+
init = left().kvreduce(f, init);
543+
if(right() != null)
544+
init = right().kvreduce(f, init);
545+
return init;
546+
}
547+
548+
532549
}
533550

534551
static class Black extends Node{

src/jvm/clojure/lang/PersistentVector.java

+11
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,17 @@ public ISeq seq(){
232232
return chunkedSeq();
233233
}
234234

235+
public Object kvreduce(IFn f, Object init){
236+
int step = 0;
237+
for(int i=0;i<cnt;i+=step){
238+
Object[] array = arrayFor(i);
239+
for(int j =0;j<array.length;++j)
240+
init = f.invoke(init,j+i,array[j]);
241+
step = array.length;
242+
}
243+
return init;
244+
}
245+
235246
static public final class ChunkedSeq extends ASeq implements IChunkedSeq{
236247

237248
public final PersistentVector vec;

0 commit comments

Comments
 (0)