Move SSD cell sorting to typed Kotlin

ober

6cda393e696d39d7df72517b9e414fa87c383058

diff --git a/templates/ssd-review.ss b/templates/ssd-review.ss
index ce94646..b9dc3e5 100644
--- a/templates/ssd-review.ss
+++ b/templates/ssd-review.ss
@@ -184,7 +184,8 @@
                 ssdCellCx ssdCellCy ssdCellRect
                 rectOverlapArea rectCenterInside iou adjacent
                 maxFloat32 minFloat32
-                bboxForCells mergeDuplicateCellsSorted)
+                bboxForCells ssdCellsSortedByYThenX
+                mergeDuplicateCellsSorted)
         (type Float32)
         (type FloatArray)
         (type Int32)
@@ -354,6 +355,42 @@
         (def (preferReplacementCell (existing : SsdCell) (candidate : SsdCell)) : Bool
           (and (not (equal? (SsdCell-detector existing) "android-color"))
                (equal? (SsdCell-detector candidate) "android-color")))
+        (def (ssdCellBeforeByYThenX? (candidate : SsdCell) (existing : SsdCell)) : Bool
+          (or (< (SsdCell-y candidate) (SsdCell-y existing))
+              (and (not (< (SsdCell-y existing) (SsdCell-y candidate)))
+                   (< (SsdCell-x candidate) (SsdCell-x existing)))))
+        (def (ssdCellSortedInsertIndex (sorted : (MutableList SsdCell))
+                                       (cell : SsdCell)) : Int32
+          (for/fold ((found (int32 -1)))
+                    ((i (in-range (int32 0) (list-size sorted))))
+            (if (>= found (int32 0))
+              found
+              (if (ssdCellBeforeByYThenX? cell (list-ref sorted i))
+                i
+                found))))
+        (def (ssdCellsInsertSorted (sorted : (MutableList SsdCell))
+                                   (cell : SsdCell)) : (MutableList SsdCell)
+          (let ((insertAt (ssdCellSortedInsertIndex sorted cell)))
+            (if (< insertAt (int32 0))
+              (begin
+                (mutable-list-add! sorted cell)
+                sorted)
+              (let ((out (mutable-list-empty SsdCell)))
+                (begin
+                  (for/fold ((ignored (int32 0)))
+                            ((i (in-range (int32 0) (list-size sorted))))
+                    (begin
+                      (if (= i insertAt)
+                        (begin
+                          (mutable-list-add! out cell)
+                          (mutable-list-add! out (list-ref sorted i)))
+                        (mutable-list-add! out (list-ref sorted i)))
+                      ignored))
+                  out)))))
+        (def (ssdCellsSortedByYThenX (cells : (List SsdCell))) : (MutableList SsdCell)
+          (for/fold ((sorted (mutable-list-empty SsdCell)))
+                    ((i (in-range (int32 0) (list-size cells))))
+            (ssdCellsInsertSorted sorted (list-ref cells i))))
         (def (renumberCells (cells : (MutableList SsdCell))) : (MutableList SsdCell)
           (let ((out (mutable-list-empty SsdCell)))
             (begin
@@ -5277,7 +5314,7 @@
        "    }"
        ""
        "    private fun mergeDuplicateCells(cells: List<SsdCell>): MutableList<SsdCell> ="
-       "        mergeDuplicateCellsSorted(cells.sortedWith(compareBy<SsdCell> { it.y }.thenBy { it.x }))"
+       "        mergeDuplicateCellsSorted(ssdCellsSortedByYThenX(cells))"
        ""
        "}"
        ))