The !-means-mutates convention distinguished nothing — there is no immutable counterpart to contrast with — so every mutating name drops the mark: sort, sort-by, sort-bytes, swap, reverse, append, append-i64, append-f64, encode-rune, split-next, map-remove, map-next, and the test helpers beside them. Two could not simply shed it: map! is map-in-place, because map is the into transform's word and means the non-mutating thing; put! is put-at, because put is the Map builtin. The ?-means-asks convention stays. Dated records keep the old spellings; watch.clj's reset-spies! and the other Clojure names are not ours to rename.
83 lines
3.3 KiB
Plaintext
83 lines
3.3 KiB
Plaintext
;;;; The prelude's in-place slice algorithms.
|
|
;;;;
|
|
;;;; Every input here is chosen so that a wrong implementation passes nothing.
|
|
;;;; The sort input is unsorted, has duplicates, has negatives and has an odd
|
|
;;;; length, so a comparison with the wrong sense, an off-by-one that drops the
|
|
;;;; last element, and a swap that loses an equal key all show up. The second
|
|
;;;; sort is reverse-sorted, which is the worst case for insertion sort and the
|
|
;;;; case a no-op comparison would pass. The third sorts a *subslice* and then
|
|
;;;; prints the whole owning array: a slice is ptr+len into its owner, so the
|
|
;;;; five elements inside the range must be sorted and the three outside it
|
|
;;;; must be untouched. That last one is the property that dies silently if a
|
|
;;;; slice parameter ever starts being copied.
|
|
|
|
(defvar xs [7 i32])
|
|
(defvar ys [5 i32])
|
|
(defvar zs [8 i32])
|
|
|
|
(defn show [s [i32]] ()
|
|
(dotimes [i (len s)]
|
|
(when (> i 0) (print " "))
|
|
(print (at s i)))
|
|
(println ""))
|
|
|
|
(defn load-xs [] ()
|
|
(set (at xs 0) 5)
|
|
(set (at xs 1) -3)
|
|
(set (at xs 2) 5)
|
|
(set (at xs 3) 0)
|
|
(set (at xs 4) 12)
|
|
(set (at xs 5) -3)
|
|
(set (at xs 6) 7))
|
|
|
|
(defn main [] i32
|
|
(load-xs)
|
|
(show (slice xs 0 (len xs))) ; 5 -3 5 0 12 -3 7
|
|
|
|
;; Reading the whole slice, before anything reorders it.
|
|
(print (sum-i32 (slice xs 0 (len xs)))) (println "") ; 23
|
|
(print (match (min-of (slice xs 0 (len xs))) (Some v) v None 99))
|
|
(println "") ; -3
|
|
(print (match (max-of (slice xs 0 (len xs))) (Some v) v None 99))
|
|
(println "") ; 12
|
|
;; First index, not the last: 5 appears at 0 and at 2.
|
|
(print (match (index-of (slice xs 0 (len xs)) 5) (Some v) v None -1))
|
|
(println "") ; 0
|
|
(print (match (index-of (slice xs 0 (len xs)) 4) (Some v) v None -1))
|
|
(println "") ; -1
|
|
;; An empty slice has no least element, and None is the answer.
|
|
(print (match (min-of (slice xs 3 3)) (Some v) v None 99))
|
|
(println "") ; 99
|
|
|
|
;; Reverse of an odd-length slice: the middle element stays put.
|
|
(reverse (slice xs 0 (len xs)))
|
|
(show (slice xs 0 (len xs))) ; 7 -3 12 0 5 -3 5
|
|
;; And of a two-element one, the smallest case that can actually move.
|
|
(reverse (slice xs 0 2))
|
|
(show (slice xs 0 (len xs))) ; -3 7 12 0 5 -3 5
|
|
|
|
(load-xs)
|
|
(sort (slice xs 0 (len xs)))
|
|
(show (slice xs 0 (len xs))) ; -3 -3 0 5 5 7 12
|
|
|
|
;; Reverse-sorted: the case a comparison that never fires would pass.
|
|
(set (at ys 0) 5) (set (at ys 1) 4) (set (at ys 2) 3)
|
|
(set (at ys 3) 2) (set (at ys 4) 1)
|
|
(sort (slice ys 0 (len ys)))
|
|
(show (slice ys 0 (len ys))) ; 1 2 3 4 5
|
|
|
|
;; A subslice, with the elements on both sides left alone.
|
|
(set (at zs 0) 100) (set (at zs 1) 9) (set (at zs 2) -1)
|
|
(set (at zs 3) 9) (set (at zs 4) 4) (set (at zs 5) 0)
|
|
(set (at zs 6) 200) (set (at zs 7) 300)
|
|
(sort (slice zs 1 6))
|
|
(show (slice zs 0 (len zs))) ; 100 -1 0 4 9 9 200 300
|
|
|
|
;; Degenerate lengths must do nothing rather than run off an end.
|
|
(sort (slice zs 0 0))
|
|
(reverse (slice zs 0 0))
|
|
(sort (slice zs 2 3))
|
|
(reverse (slice zs 2 3))
|
|
(show (slice zs 0 (len zs))) ; 100 -1 0 4 9 9 200 300
|
|
0)
|