diff --git a/doc/intro.md b/doc/intro.md
index 92e2036..26a5f80 100644
--- a/doc/intro.md
+++ b/doc/intro.md
@@ -7,7 +7,7 @@ Arbitrary numbers of dimensions are supported, up to limits imposed by the JVM s
Available from Clojars: [](https://clojars.org/sparse-array)
Tests currently [](https://circleci.com/gh/simon-brooke/sparse-array)
-## Conventions:
+## Conventions
### Sparse arrays
diff --git a/docs/cloverage/index.html b/docs/cloverage/index.html
index b1718c8..239820d 100644
--- a/docs/cloverage/index.html
+++ b/docs/cloverage/index.html
@@ -29,15 +29,15 @@
style="width:11.45374449339207%;
float:left;"> 26
88.55 % |
-337 | 23 | 227 |
+337 | 22 | 227 |
sparse-array.extract | 163 166 10 |
-94.22 % |
+94.32 % |
41 4 |
91.30 % |
-68 | 5 | 46 |
+71 | 5 | 46 |
Totals: |
|
-86.68 % |
+86.72 % |
|
89.01 % |
diff --git a/docs/cloverage/sparse_array/core.clj.html b/docs/cloverage/sparse_array/core.clj.html
index 63fb3b7..6b5ac07 100644
--- a/docs/cloverage/sparse_array/core.clj.html
+++ b/docs/cloverage/sparse_array/core.clj.html
@@ -5,529 +5,529 @@
- 001 (ns sparse-array.core)
+ 001 (ns sparse-array.core
+
+
+ 002 "Operations on sparse arrays.")
- 002
+ 003
- 003 (declare put get)
+ 004 (declare put get)
- 004
+ 005
- 005 (def ^:dynamic *safe-sparse-operations*
+ 006 (def ^:dynamic *safe-sparse-operations*
- 006 "Whether spase array operations should be conducted safely, with careful
+ 007 "Whether spase array operations should be conducted safely, with careful
- 007 checking of data conventions and exceptions thrown if expectations are not
+ 008 checking of data conventions and exceptions thrown if expectations are not
- 008 met. Normally `false`."
+ 009 met. Normally `false`."
- 009 false)
+ 010 false)
- 010
+ 011
- 011 (defn- unsafe-sparse-operations?
+ 012 (defn- unsafe-sparse-operations?
- 012 "returns `true` if `*safe-sparse-operations*` is `false`, and vice versa."
+ 013 "returns `true` if `*safe-sparse-operations*` is `false`, and vice versa."
- 013 []
+ 014 []
- 014 (not (true? *safe-sparse-operations*)))
+ 015 (not (true? *safe-sparse-operations*)))
- 015
+ 016
- 016 (defn make-sparse-array
+ 017 (defn make-sparse-array
- 017 "Make a sparse array with these `dimensions`. Every member of `dimensions`
+ 018 "Make a sparse array with these `dimensions`. Every member of `dimensions`
- 018 must be a keyword; otherwise, `nil` will be returned."
+ 019 must be a keyword; otherwise, `nil` will be returned."
- 019 [& dimensions]
+ 020 [& dimensions]
- 020 (when
+ 021 (when
- 021 (and (pos? (count dimensions))
+ 022 (and (pos? (count dimensions))
- 022 (every? keyword? dimensions))
+ 023 (every? keyword? dimensions))
- 023 {:dimensions (count dimensions)
+ 024 {:dimensions (count dimensions)
- 024 :coord (first dimensions)
+ 025 :coord (first dimensions)
- 025 :content (if
+ 026 :content (if
- 026 (empty? (rest dimensions))
+ 027 (empty? (rest dimensions))
- 027 :data
+ 028 :data
- 028 (rest dimensions))}))
+ 029 (rest dimensions))}))
- 029
+ 030
- 030 (defn- safe-test-or-throw
+ 031 (defn- safe-test-or-throw
- 031 "If `v` is truthy or `*safe-sparse-operations*` is false, return `v`;
+ 032 "If `v` is truthy or `*safe-sparse-operations*` is false, return `v`;
- 032 otherwise, throw an `ExceptionInfo` with this `message` and the map `m`."
+ 033 otherwise, throw an `ExceptionInfo` with this `message` and the map `m`."
- 033 [v message m]
+ 034 [v message m]
- 034 (if-not
+ 035 (if-not
- 035 v
+ 036 v
- 036 (if
+ 037 (if
- 037 *safe-sparse-operations*
+ 038 *safe-sparse-operations*
- 038 (throw (ex-info message m))
+ 039 (throw (ex-info message m))
- 039 v)
+ 040 v)
- 040 v))
+ 041 v))
- 041
+ 042
- 042 (defn sparse-array?
+ 043 (defn sparse-array?
- 043 "`true` if `x` is a sparse array conforming to the conventions established
+ 044 "`true` if `x` is a sparse array conforming to the conventions established
- 044 by this library, else `false`."
+ 045 by this library, else `false`."
- 045 ;; TODO: sparse-array? should not throw exceptions even when
+ 046 ;; TODO: sparse-array? should not throw exceptions even when
- 046 ;; *safe-sparse-operations* is true, since we may use to test
+ 047 ;; *safe-sparse-operations* is true, since we may use to test
- 047 ;; whether an object is a sparse array. The place to throw the exceptions
+ 048 ;; whether an object is a sparse array. The place to throw the exceptions
- 048 ;; (if required) is after it has failed.
+ 049 ;; (if required) is after it has failed.
- 049 ([x]
+ 050 ([x]
- 050 (apply
+ 051 (apply
- 051 sparse-array?
+ 052 sparse-array?
- 052 (cons
+ 053 (cons
- 053 x
+ 054 x
- 054 (cons
+ 055 (cons
- 055 (:coord x)
+ 056 (:coord x)
- 056 (when
+ 057 (when
- 057 (coll? (:content x))
+ 058 (coll? (:content x))
- 058 (:content x))))))
+ 059 (:content x))))))
- 059 ([x & axes]
+ 060 ([x & axes]
- 060 (and
+ 061 (and
- 061 (safe-test-or-throw
+ 062 (safe-test-or-throw
- 062 (map? x)
+ 063 (map? x)
- 063 "Array must be a map" {:array x})
+ 064 "Array must be a map" {:array x})
- 064 (safe-test-or-throw
+ 065 (safe-test-or-throw
- 065 (and (integer? (:dimensions x)) (pos? (:dimensions x)))
+ 066 (and (integer? (:dimensions x)) (pos? (:dimensions x)))
- 066 (str "The value of `:dimensions` must be a positive integer, not " (:dimensions x))
+ 067 (str "The value of `:dimensions` must be a positive integer, not " (:dimensions x))
- 067 {:array x})
+ 068 {:array x})
- 068 (safe-test-or-throw
+ 069 (safe-test-or-throw
- 069 (keyword? (:coord x))
+ 070 (keyword? (:coord x))
- 070 (str "The value of `:coord` must be a keyword, not " (:coord x))
+ 071 (str "The value of `:coord` must be a keyword, not " (:coord x))
- 071 {:array x})
+ 072 {:array x})
- 072 (safe-test-or-throw
+ 073 (safe-test-or-throw
- 073 (= (:coord x) (first axes))
+ 074 (= (:coord x) (first axes))
- 074 (str "The value of `:coord` must be " (first axes) ", not " (:coord x))
+ 075 (str "The value of `:coord` must be " (first axes) ", not " (:coord x))
- 075 {:array x})
+ 076 {:array x})
- 076 (if
+ 077 (if
- 077 (empty? (rest axes))
+ 078 (empty? (rest axes))
- 078 (safe-test-or-throw
+ 079 (safe-test-or-throw
- 079 (= (:content x) :data)
+ 080 (= (:content x) :data)
- 080 "If there are no further axes the value of `:content` must be `:data`"
+ 081 "If there are no further axes the value of `:content` must be `:data`"
- 081 {:array x})
+ 082 {:array x})
- 082 (and
+ 083 (and
- 083 (= (:content x) (rest axes))
+ 084 (= (:content x) (rest axes))
- 084 (every?
+ 085 (every?
- 085 sparse-array?
+ 086 sparse-array?
- 086 (map #(x %) (filter integer? (keys x)))))))))
+ 087 (map #(x %) (filter integer? (keys x)))))))))
- 087
+ 088
- 088 (defn- unsafe-put
+ 089 (defn- unsafe-put
- 089 [array value coordinates]
+ 090 [array value coordinates]
- 090 (cond
+ 091 (cond
- 091 (every?
+ 092 (every?
- 092 #(and (integer? %) (or (zero? %) (pos? %)))
+ 093 #(and (integer? %) (or (zero? %) (pos? %)))
- 093 coordinates)
+ 094 coordinates)
- 094 (assoc
+ 095 (assoc
- 095 array
+ 096 array
- 096 (first coordinates)
+ 097 (first coordinates)
- 097 (if
+ 098 (if
- 098 (= :data (:content array))
+ 099 (= :data (:content array))
- 099 value
+ 100 value
- 100 (apply
+ 101 (apply
- 101 put
+ 102 put
- 102 (cons
+ 103 (cons
- 103 (or
+ 104 (or
- 104 (array (first coordinates))
+ 105 (array (first coordinates))
- 105 (apply make-sparse-array (:content array)))
+ 106 (apply make-sparse-array (:content array)))
- 106 (cons value (rest coordinates))))))))
+ 107 (cons value (rest coordinates))))))))
- 107
+ 108
- 108 (defn put
+ 109 (defn put
- 109 "Return a sparse array like this `array` but with this `value` at these
+ 110 "Return a sparse array like this `array` but with this `value` at these
- 110 `coordinates`. Returns `nil` if any coordinate is invalid."
+ 111 `coordinates`. Returns `nil` if any coordinate is invalid."
- 111 [array value & coordinates]
+ 112 [array value & coordinates]
- 112 (cond
+ 113 (cond
- 113 (nil? value)
+ 114 (nil? value)
- 114 nil
+ 115 nil
- 115 (unsafe-sparse-operations?)
+ 116 (unsafe-sparse-operations?)
- 116 (unsafe-put array value coordinates)
+ 117 (unsafe-put array value coordinates)
- 117 (not (sparse-array? array))
+ 118 (not (sparse-array? array))
- 118 (throw (ex-info "Sparse array expected" {:array array}))
+ 119 (throw (ex-info "Sparse array expected" {:array array}))
- 119 (not= (:dimensions array) (count coordinates))
+ 120 (not= (:dimensions array) (count coordinates))
- 120 (throw
+ 121 (throw
- 121 (ex-info
+ 122 (ex-info
- 122 (str "Expected " (:dimensions array) " coordinates; found " (count coordinates))
+ 123 (str "Expected " (:dimensions array) " coordinates; found " (count coordinates))
- 123 {:array array
+ 124 {:array array
- 124 :coordinates coordinates}))
+ 125 :coordinates coordinates}))
- 125 (not
+ 126 (not
- 126 (every?
+ 127 (every?
- 127 #(and (integer? %) (or (zero? %) (pos? %)))
+ 128 #(and (integer? %) (or (zero? %) (pos? %)))
- 128 coordinates))
+ 129 coordinates))
- 129 (throw
+ 130 (throw
- 130 (ex-info
+ 131 (ex-info
- 131 "Coordinates must be zero or positive integers"
+ 132 "Coordinates must be zero or positive integers"
- 132 {:array array
+ 133 {:array array
- 133 :coordinates coordinates
+ 134 :coordinates coordinates
- 134 :invalid (remove #(and (pos? %) (integer? %)) coordinates)}))
+ 135 :invalid (remove #(and (pos? %) (integer? %)) coordinates)}))
- 135 :else
+ 136 :else
- 136 (unsafe-put array value coordinates)))
+ 137 (unsafe-put array value coordinates)))
- 137
+ 138
- 138 (defn- unsafe-get
+ 139 (defn- unsafe-get
- 139 ;; TODO: I am CERTAIN there is a more elegant solution to this.
+ 140 ;; TODO: I am CERTAIN there is a more elegant solution to this.
- 140 [array coordinates]
+ 141 [array coordinates]
- 141 (let [v (array (first coordinates))]
+ 142 (let [v (array (first coordinates))]
- 142 (cond
+ 143 (cond
- 143 (= :data (:content array))
+ 144 (= :data (:content array))
- 144 v
+ 145 v
- 145 (nil? v)
+ 146 (nil? v)
- 146 nil
+ 147 nil
- 147 :else
+ 148 :else
- 148 (apply get (cons v (rest coordinates))))))
+ 149 (apply get (cons v (rest coordinates))))))
- 149
+ 150
- 150 (defn get
+ 151 (defn get
- 151 "Return the value in this sparse `array` at these `coordinates`."
+ 152 "Return the value in this sparse `array` at these `coordinates`."
- 152 [array & coordinates]
+ 153 [array & coordinates]
- 153 (cond
+ 154 (cond
- 154 (unsafe-sparse-operations?)
+ 155 (unsafe-sparse-operations?)
- 155 (unsafe-get array coordinates)
+ 156 (unsafe-get array coordinates)
- 156 (not (sparse-array? array))
+ 157 (not (sparse-array? array))
- 157 (throw (ex-info "Sparse array expected" {:array array}))
+ 158 (throw (ex-info "Sparse array expected" {:array array}))
- 158 (not (every?
+ 159 (not (every?
- 159 #(and (integer? %) (or (zero? %) (pos? %)))
+ 160 #(and (integer? %) (or (zero? %) (pos? %)))
- 160 coordinates))
+ 161 coordinates))
- 161 (throw
+ 162 (throw
- 162 (ex-info
+ 163 (ex-info
- 163 "Coordinates must be zero or positive integers"
+ 164 "Coordinates must be zero or positive integers"
- 164 {:array array
+ 165 {:array array
- 165 :coordinates coordinates
+ 166 :coordinates coordinates
- 166 :invalid (remove #(and (pos? %) (integer? %)) coordinates)}))
+ 167 :invalid (remove #(and (pos? %) (integer? %)) coordinates)}))
- 167 (not (= (:dimensions array) (count coordinates)))
+ 168 (not (= (:dimensions array) (count coordinates)))
- 168 (throw
+ 169 (throw
- 169 (ex-info
+ 170 (ex-info
- 170 (str "Expected " (:dimensions array) " coordinates; found " (count coordinates))
+ 171 (str "Expected " (:dimensions array) " coordinates; found " (count coordinates))
- 171 {:array array
+ 172 {:array array
- 172 :coordinates coordinates}))
+ 173 :coordinates coordinates}))
- 173 :else
+ 174 :else
- 174 (unsafe-get array coordinates)))
-
-
- 175
+ 175 (unsafe-get array coordinates)))
176
diff --git a/docs/cloverage/sparse_array/extract.clj.html b/docs/cloverage/sparse_array/extract.clj.html
index 900a25e..1b5152a 100644
--- a/docs/cloverage/sparse_array/extract.clj.html
+++ b/docs/cloverage/sparse_array/extract.clj.html
@@ -8,205 +8,214 @@
001 (ns sparse-array.extract
- 002 (:require [sparse-array.core :refer :all]))
+ 002 "Extracting interesting data from sparse arrays."
+
+
+ 003 (:require [sparse-array.core :refer [*safe-sparse-operations*
+
+
+ 004 dense-array? dense-dimensions
+
+
+ 005 make-sparse-array sparse-array?]]))
- 003
+ 006
- 004 ;;; The whole point of working with sparse arrays is to work with interesting
+ 007 ;;; The whole point of working with sparse arrays is to work with interesting
- 005 ;;; subsets of arrays most of which are uninteresting. To extract an
+ 008 ;;; subsets of arrays most of which are uninteresting. To extract an
- 006 ;;; interesting subset from an array, we're going to need an extract function.
+ 009 ;;; interesting subset from an array, we're going to need an extract function.
- 007
+ 010
- 008 (defn- extract-from-sparse
+ 011 (defn- extract-from-sparse
- 009 "Return a subset of this sparse `array` comprising all those cells for which
+ 012 "Return a subset of this sparse `array` comprising all those cells for which
- 010 this `function` returns a 'truthy' value."
+ 013 this `function` returns a 'truthy' value."
- 011 [array function]
+ 014 [array function]
- 012 (reduce
+ 015 (reduce
- 013 merge
+ 016 merge
- 014 (apply
+ 017 (apply
- 015 make-sparse-array
+ 018 make-sparse-array
- 016 (cons
+ 019 (cons
- 017 (:coord array)
+ 020 (:coord array)
-
- 018 (if (coll? (:content array)) (:content array))))
+
+ 021 (when (coll? (:content array)) (:content array))))
- 019 (map
+ 022 (map
- 020 #(if
+ 023 #(if
- 021 (= :data (:content array))
+ 024 (= :data (:content array))
-
- 022 (if (function (array %)) {% (array %)})
+
+ 025 (when (function (array %)) {% (array %)})
- 023 (let [v (extract-from-sparse (array %) function)]
+ 026 (let [v (extract-from-sparse (array %) function)]
- 024 (if
+ 027 (if
- 025 (empty?
+ 028 (empty?
- 026 (filter integer? (keys v)))
+ 029 (filter integer? (keys v)))
- 027 nil
+ 030 nil
- 028 {% v})))
+ 031 {% v})))
- 029 (filter integer? (keys array)))))
+ 032 (filter integer? (keys array)))))
- 030
+ 033
- 031 (defn extract-from-dense
+ 034 (defn extract-from-dense
- 032 "Return a subset of this dense `array` comprising all those cells for which
+ 035 "Return a subset of this dense `array` comprising all those cells for which
- 033 this `function` returns a 'truthy' value. Use these `axes` if provided."
+ 036 this `function` returns a 'truthy' value. Use these `axes` if provided."
- 034 ([array function]
+ 037 ([array function]
- 035 (extract-from-dense array function (map #(keyword (str "i" %)) (range))))
+ 038 (extract-from-dense array function (map #(keyword (str "i" %)) (range))))
- 036 ([array function axes]
+ 039 ([array function axes]
- 037 (let
+ 040 (let
- 038 [dimensions (dense-dimensions array)]
+ 041 [dimensions (dense-dimensions array)]
- 039 (reduce
+ 042 (reduce
- 040 merge
+ 043 merge
- 041 (apply make-sparse-array (take dimensions axes))
+ 044 (apply make-sparse-array (take dimensions axes))
- 042 (if
+ 045 (if
- 043 (= dimensions 1)
+ 046 (= dimensions 1)
- 044 (map
+ 047 (map
-
- 045 (fn [i v] (if (function v) (hash-map i v)))
+
+ 048 (fn [i v] (when (function v) (hash-map i v)))
- 046 (range)
+ 049 (range)
- 047 array)
+ 050 array)
- 048 (map
+ 051 (map
- 049 (fn [i v] (if (empty? (filter integer? (keys v))) nil (hash-map i v)))
+ 052 (fn [i v] (if (empty? (filter integer? (keys v))) nil (hash-map i v)))
- 050 (range)
+ 053 (range)
- 051 (map #(extract-from-dense % function (rest axes)) array)))))))
+ 054 (map #(extract-from-dense % function (rest axes)) array)))))))
- 052
+ 055
- 053 (defn extract
+ 056 (defn extract
- 054 "Return a sparse subset of this `array` - which may be either sparse or
+ 057 "Return a sparse subset of this `array` - which may be either sparse or
- 055 dense - comprising all those cells for which this `function` returns a
+ 058 dense - comprising all those cells for which this `function` returns a
- 056 'truthy' value."
+ 059 'truthy' value."
- 057 [array function]
+ 060 [array function]
- 058 (cond
+ 061 (cond
- 059 (sparse-array? array)
+ 062 (sparse-array? array)
- 060 (extract-from-sparse array function)
+ 063 (extract-from-sparse array function)
- 061 (dense-array? array)
+ 064 (dense-array? array)
- 062 (extract-from-dense array function)
+ 065 (extract-from-dense array function)
- 063 *safe-sparse-operations*
+ 066 *safe-sparse-operations*
- 064 (throw
+ 067 (throw
- 065 (ex-info
+ 068 (ex-info
- 066 "Argument passed as `array` is neither sparse nor dense."
+ 069 "Argument passed as `array` is neither sparse nor dense."
- 067 {:array array}))))
+ 070 {:array array}))))
- 068
+ 071