From 7beb142569897b143741fbc0c98204cc6e8308cc Mon Sep 17 00:00:00 2001
From: Alan Malloy <alan@malloys.org>
Date: Fri, 10 Aug 2012 12:45:43 -0700
Subject: [PATCH 1/3] Fix order of PersistentTreeMap's kvreduce

We need an in-order traversal to make stuff happen in sorted order. So
rather than self/left/right, we do left/self/right.
---
 src/jvm/clojure/lang/PersistentTreeMap.java |    8 ++++----
 1 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/jvm/clojure/lang/PersistentTreeMap.java b/src/jvm/clojure/lang/PersistentTreeMap.java
index f1a60ed..21e1b3c 100644
--- a/src/jvm/clojure/lang/PersistentTreeMap.java
+++ b/src/jvm/clojure/lang/PersistentTreeMap.java
@@ -537,15 +537,15 @@ static abstract class Node extends AMapEntry{
 	abstract Node replace(Object key, Object val, Node left, Node right);
 
     public Object kvreduce(IFn f, Object init){
-        init = f.invoke(init, key(), val());
-	    if(RT.isReduced(init))
-		    return ((IDeref)init).deref();
-
 	    if(left() != null){
             init = left().kvreduce(f, init);
 	        if(RT.isReduced(init))
 		        return ((IDeref)init).deref();
 	        }
+	    init = f.invoke(init, key(), val());
+	    if(RT.isReduced(init))
+		    return ((IDeref)init).deref();
+
 	    if(right() != null){
             init = right().kvreduce(f, init);
 	        if(RT.isReduced(init))
-- 
1.7.4.1


From 701fea43da5f490e8541fa860509ebb273732e23 Mon Sep 17 00:00:00 2001
From: Alan Malloy <alan@malloys.org>
Date: Fri, 10 Aug 2012 12:54:44 -0700
Subject: [PATCH 2/3] Fix handling of Reduced values in PersistentTreeMap/kvreduce

It was dereferencing them and passing them up the chain; but that meant
that parent nodes didn't know the reduction had completed, so the
reduction might continue along other paths down the tree.
---
 src/jvm/clojure/lang/PersistentTreeMap.java |   10 +++++-----
 1 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/jvm/clojure/lang/PersistentTreeMap.java b/src/jvm/clojure/lang/PersistentTreeMap.java
index 21e1b3c..bf1e611 100644
--- a/src/jvm/clojure/lang/PersistentTreeMap.java
+++ b/src/jvm/clojure/lang/PersistentTreeMap.java
@@ -207,7 +207,9 @@ public NodeIterator iterator(){
 
 public Object kvreduce(IFn f, Object init){
     if(tree != null)
-        return tree.kvreduce(f,init);
+        init = tree.kvreduce(f,init);
+    if(RT.isReduced(init))
+        init = ((IDeref)init).deref();
     return init;
 }
 
@@ -540,16 +542,14 @@ static abstract class Node extends AMapEntry{
 	    if(left() != null){
             init = left().kvreduce(f, init);
 	        if(RT.isReduced(init))
-		        return ((IDeref)init).deref();
+		        return init;
 	        }
 	    init = f.invoke(init, key(), val());
 	    if(RT.isReduced(init))
-		    return ((IDeref)init).deref();
+		    return init;
 
 	    if(right() != null){
             init = right().kvreduce(f, init);
-	        if(RT.isReduced(init))
-		        return ((IDeref)init).deref();
 	        }
 	    return init;
     }
-- 
1.7.4.1


From 7780d5ad960be41276de9215ab2e108c30d7d1cc Mon Sep 17 00:00:00 2001
From: Alan Malloy <alan@malloys.org>
Date: Fri, 10 Aug 2012 13:02:13 -0700
Subject: [PATCH 3/3] Add tests for sorted-map reduction problems

---
 test/clojure/test_clojure/reducers.clj |   11 +++++++++++
 1 files changed, 11 insertions(+), 0 deletions(-)

diff --git a/test/clojure/test_clojure/reducers.clj b/test/clojure/test_clojure/reducers.clj
index 1123c36..bd9d3e7 100644
--- a/test/clojure/test_clojure/reducers.clj
+++ b/test/clojure/test_clojure/reducers.clj
@@ -39,3 +39,14 @@
 (defequivtest test-filter
   [filter r/filter #(into [] %)]
   [even? odd? #(< 200 %) identity])
+
+
+(deftest test-sorted-maps
+  (let [m (into (sorted-map)
+                '{1 a, 2 b, 3 c, 4 d})]
+    (is (= "1a2b3c4d" (reduce-kv str "" m))
+        "Sorted maps should reduce-kv in sorted order")
+    (is (= 1 (reduce-kv (fn [acc k v]
+                          (reduced (+ acc k)))
+                        0 m))
+        "Sorted maps should stop reduction when asked")))
-- 
1.7.4.1

