[#458] add clojure.data namespace (fix reflection warnings)

This commit is contained in:
Michiel Borkent 2020-05-31 23:12:28 +02:00
parent c7b1d62b69
commit cd6b76711d
3 changed files with 153 additions and 9 deletions

View file

@ -1,10 +1,144 @@
(ns babashka.impl.clojure.data
{:no-doc true}
(:require [clojure.data :as data]
[sci.impl.namespaces :refer [copy-var]]
[sci.impl.vars :as vars]))
; Copyright (c) Rich Hickey. All rights reserved.
; The use and distribution terms for this software are covered by the
; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
; which can be found in the file epl-v10.html at the root of this distribution.
; By using this software in any fashion, you are agreeing to be bound by
; the terms of this license.
; You must not remove this notice, or any other, from this software.
(def data-ns (vars/->SciNamespace 'clojure.data nil))
(ns
^{:author "Stuart Halloway",
:doc "Non-core data functions."}
babashka.impl.clojure.data
(:require [clojure.set :as set]))
(def data-namespace
{'diff (copy-var data/diff data-ns)})
(set! *warn-on-reflection* true)
(declare diff)
(defn- atom-diff
"Internal helper for diff."
[a b]
(if (= a b) [nil nil a] [a b nil]))
;; for big things a sparse vector class would be better
(defn- vectorize
"Convert an associative-by-numeric-index collection into
an equivalent vector, with nil for any missing keys"
[m]
(when (seq m)
(reduce
(fn [result [k v]] (assoc result k v))
(vec (repeat (apply max (keys m)) nil))
m)))
(defn- diff-associative-key
"Diff associative things a and b, comparing only the key k."
[a b k]
(let [va (get a k)
vb (get b k)
[a* b* ab] (diff va vb)
in-a (contains? a k)
in-b (contains? b k)
same (and in-a in-b
(or (not (nil? ab))
(and (nil? va) (nil? vb))))]
[(when (and in-a (or (not (nil? a*)) (not same))) {k a*})
(when (and in-b (or (not (nil? b*)) (not same))) {k b*})
(when same {k ab})
]))
(defn- diff-associative
"Diff associative things a and b, comparing only keys in ks."
[a b ks]
(reduce
(fn [diff1 diff2]
(doall (map merge diff1 diff2)))
[nil nil nil]
(map
(partial diff-associative-key a b)
ks)))
(defn- diff-sequential
[a b]
(vec (map vectorize (diff-associative
(if (vector? a) a (vec a))
(if (vector? b) b (vec b))
(range (max (count a) (count b)))))))
(defprotocol ^{:added "1.3"} EqualityPartition
"Implementation detail. Subject to change."
(^{:added "1.3"} equality-partition [x] "Implementation detail. Subject to change."))
(defprotocol ^{:added "1.3"} Diff
"Implementation detail. Subject to change."
(^{:added "1.3"} diff-similar [a b] "Implementation detail. Subject to change."))
(extend nil
Diff
{:diff-similar atom-diff})
(extend Object
Diff
{:diff-similar (fn [^Object a ^Object b]
((if (.. a getClass isArray) diff-sequential atom-diff) a b))}
EqualityPartition
{:equality-partition
(fn [^Object x]
(if (.. x getClass isArray) :sequential :atom))})
(extend-protocol EqualityPartition
nil
(equality-partition [x] :atom)
java.util.Set
(equality-partition [x] :set)
java.util.List
(equality-partition [x] :sequential)
java.util.Map
(equality-partition [x] :map))
(defn- as-set-value
[s]
(if (set? s) s (into #{} s)))
(extend-protocol Diff
java.util.Set
(diff-similar
[a b]
(let [aval (as-set-value a)
bval (as-set-value b)]
[(not-empty (set/difference aval bval))
(not-empty (set/difference bval aval))
(not-empty (set/intersection aval bval))]))
java.util.List
(diff-similar [a b]
(diff-sequential a b))
java.util.Map
(diff-similar [a b]
(diff-associative a b (set/union (keys a) (keys b)))))
(defn diff
"Recursively compares a and b, returning a tuple of
[things-only-in-a things-only-in-b things-in-both].
Comparison rules:
* For equal a and b, return [nil nil a].
* Maps are subdiffed where keys match and values differ.
* Sets are never subdiffed.
* All sequential things are treated as associative collections
by their indexes, with results returned as vectors.
* Everything else (including strings!) is treated as
an atom and compared for equality."
{:added "1.3"}
[a b]
(if (= a b)
[nil nil a]
(if (= (equality-partition a) (equality-partition b))
(diff-similar a b)
(atom-diff a b))))

View file

@ -0,0 +1,10 @@
(ns babashka.impl.data
{:no-doc true}
(:require [babashka.impl.clojure.data :as data]
[sci.impl.namespaces :refer [copy-var]]
[sci.impl.vars :as vars]))
(def data-ns (vars/->SciNamespace 'clojure.data nil))
(def data-namespace
{'diff (copy-var data/diff data-ns)})

View file

@ -6,7 +6,6 @@
[babashka.impl.classes :as classes]
[babashka.impl.classpath :as cp]
[babashka.impl.clojure.core :as core :refer [core-extras]]
[babashka.impl.clojure.data :as data]
[babashka.impl.clojure.java.io :refer [io-namespace]]
[babashka.impl.clojure.java.shell :refer [shell-namespace]]
[babashka.impl.clojure.main :as clojure-main :refer [demunge]]
@ -15,6 +14,7 @@
[babashka.impl.clojure.zip :refer [zip-namespace]]
[babashka.impl.common :as common]
[babashka.impl.curl :refer [curl-namespace]]
[babashka.impl.data :as data]
[babashka.impl.features :as features]
[babashka.impl.ordered :refer [ordered-map-ns]]
[babashka.impl.pods :as pods]