Skip to content

Commit

Permalink
Merge pull request #147 from twolionsco/master
Browse files Browse the repository at this point in the history
fix: replace lazymap dependency for one in tree
  • Loading branch information
w01fe authored Dec 21, 2022
2 parents e75142a + 0a234ee commit e6f99d8
Show file tree
Hide file tree
Showing 5 changed files with 252 additions and 6 deletions.
3 changes: 1 addition & 2 deletions deps.edn
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
{:paths ["src"]
:deps {prismatic/schema {:mvn/version "1.2.0"}
de.kotka/lazymap {:mvn/version "3.1.0"}}}
:deps {prismatic/schema {:mvn/version "1.2.0"}}}
3 changes: 1 addition & 2 deletions project.clj
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
:url "http://www.eclipse.org/legal/epl-v10.html"
:distribution :repo}

:dependencies [[prismatic/schema "1.2.0"]
[de.kotka/lazymap "3.1.0" :exclusions [org.clojure/clojure]]]
:dependencies [[prismatic/schema "1.2.0"]]

:profiles {:dev {:dependencies [[org.clojure/clojure "1.10.3"]
[org.clojure/clojurescript "1.10.891"]
Expand Down
2 changes: 1 addition & 1 deletion src/plumbing/graph.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
For more details and examples of Graphs, see test/plumbing/graph_examples_test.cljx."
(:refer-clojure :exclude [compile])
(:require
#?(:clj [lazymap.core :as lazymap])
#?(:clj [plumbing.lazymap :as lazymap])
[schema.core :as s]
#?(:clj [schema.macros :as schema-macros])
[plumbing.fnk.schema :as schema #?@(:cljs [:include-macros true])]
Expand Down
248 changes: 248 additions & 0 deletions src/plumbing/lazymap.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
;-
; Copyright 2008-2011 (c) Meikel Brandmeyer.
; All rights reserved.
;
; Permission is hereby granted, free of charge, to any person obtaining a copy
; of this software and associated documentation files (the "Software"), to deal
; in the Software without restriction, including without limitation the rights
; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
; copies of the Software, and to permit persons to whom the Software is
; furnished to do so, subject to the following conditions:
;
; The above copyright notice and this permission notice shall be included in
; all copies or substantial portions of the Software.
;
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
; THE SOFTWARE.

;; Retreived from https://bitbucket.org/kotarak/lazymap/raw/5a2437e70a91/src/main/clojure/lazymap/core.clj
;; by JW on 11/17/2011, and slightly modified to fix a bug in .entryAt and add a safety check.
;; Also replaced 'force' with 'deref' so this can be used with futures (with marginal utility).
;; (our pull request with these changes has been been ignored, so we've just included
;; this fixed file in plumbing for the time being).

;; Known Issues: LazyMapEntries are not equal to persistent vectors like ordinary map entries.


(ns plumbing.lazymap
"Lazymap is to maps what lazy-seq is to lists. It allows to store values
with evaluating them. This is only done in case the value is really accessed.
Lazymap works with any map type (hash-map, sorted-map, struct-map) and may
be used as a drop-in replacement everywhere where a normal map type may be
used.
Available macros:
lazy-hash-map, lazy-sorted-map, lazy-struct-map, lazy-struct, lazy-assoc
and their * counterpart functions."
(:import
clojure.lang.IObj
clojure.lang.IFn
clojure.lang.ILookup
clojure.lang.IMapEntry
clojure.lang.IPersistentMap
clojure.lang.IPersistentVector
clojure.lang.ASeq
clojure.lang.ISeq
clojure.lang.Seqable
clojure.lang.SeqIterator))

(defprotocol ILazyMapEntry
"ILazyMapEntry describes the behaviour of a lazy MapEntry. It provides
an additional method (over IMapEntry), which returns the raw delay object
and not the forced value."
(get-key [lazy-map-entry] "Return the key of the map entry.")
(get-raw-value [lazy-map-entry] "Return the underlying delay object."))

; Extend the IMapEntry interface to act also like ILazyMapEntry.
; For a IMapEntry get-raw-value just returns the given value as
; wrapped in a delay. Similar a vector of two elements might be
; used in place of a IMapEntry.
(extend-protocol ILazyMapEntry
IMapEntry
(get-key [#^IMapEntry this] (.getKey this))
(get-raw-value [#^IMapEntry this] (let [v (.getValue this)] (delay v)))
IPersistentVector
(get-key [this]
(when-not (= (count this) 2)
(throw (IllegalArgumentException.
"Vector used as IMapEntry must be a pair")))
(this 0))
(get-raw-value
[this]
(when-not (= (count this) 2)
(throw (IllegalArgumentException.
"Vector used as IMapEntry must be a pair")))
(let [v (this 1)]
(delay v))))

(defprotocol ILazyPersistentMap
"ILazyPersistentMap extends IPersistentMap with a method to allow
transportation of the underlying delay objects."
(delay-assoc [lazy-map key delay] "Associates the given delay in the map."))

(deftype LazyMapEntry [k v]
ILazyMapEntry
(get-key [_] k)
(get-raw-value [_] v)
IMapEntry
(key [_] k)
(getKey [_] k)
(val [_] (deref v))
(getValue [_] (deref v))
Object
(toString [_] (str \[ (pr-str k) \space (pr-str (deref v)) \])))

(defmethod print-method LazyMapEntry
[this #^java.io.Writer w]
(.write w (str this)))

(defn create-lazy-map-seq
([inner-seq]
(create-lazy-map-seq inner-seq nil))
([inner-seq metadata]
(proxy [ASeq] [metadata]
; ISeq
(first []
(let [first-val (first inner-seq)]
(LazyMapEntry. (key first-val) (val first-val))))
(next []
(when-let [inner-rest (next inner-seq)]
(create-lazy-map-seq inner-rest metadata)))
(more [] (lazy-seq (next this))))))

(declare create-lazy-map)

(deftype LazyPersistentMap
[base metadata]
ILazyPersistentMap
(delay-assoc [this k v] (create-lazy-map (assoc base k v) metadata))
IPersistentMap
(assoc [this k v] (create-lazy-map (assoc base k (delay v)) metadata))
(assocEx
[this k v]
(when (contains? base k)
(throw (Exception. (str "Key already present in map: " k))))
(.assoc this k v))
(without [this k] (create-lazy-map (dissoc base k) metadata))
; Associative
(containsKey [this k] (contains? base k))
(entryAt [this k] (when-let [v (base k)] (LazyMapEntry. k v)))
; IPersistentCollection
(count [this] (count base))
(cons
[this o]
(if (satisfies? ILazyMapEntry o)
(delay-assoc this (get-key o) (get-raw-value o))
(into this o)))
(empty [this] (create-lazy-map (empty base) nil))
ILookup
(valAt [this k] (.valAt this k nil))
(valAt
[this k not-found]
(if (contains? base k)
(-> base (get k) deref)
not-found))
IFn
(invoke [this k] (.valAt this k nil))
(invoke [this k not-found] (.valAt this k not-found))
(applyTo
[this args]
(let [[k v & rest-args :as args] (seq args)]
(when (or (not args) rest-args)
(throw (Exception. "lazy map must be called with one or two arguments")))
(.valAt this k v)))
Seqable
(seq
[this]
(when-let [inner-seq (seq base)]
(create-lazy-map-seq inner-seq)))
IObj
(withMeta [this new-metadata] (create-lazy-map base new-metadata))
; IMeta
(meta [this] metadata)
Iterable
(iterator [this] (-> this .seq SeqIterator.)))

(defn create-lazy-map
([base]
(create-lazy-map base nil))
([base metadata]
(LazyPersistentMap. base metadata)))

(defn- quote-values
[kvs]
(assert (even? (count kvs)))
(mapcat (fn [[k v]] [k `(delay ~v)]) (partition 2 kvs)))

(defn lazy-assoc*
"lazy-assoc* is like lazy-assoc but a function and takes values as delays
instead of expanding into a delay of val."
[m & kvs]
(assert (even? (count kvs)))
(reduce (fn [m [k v]] (delay-assoc m k v)) m (partition 2 kvs)))

(defmacro lazy-assoc
"lazy-assoc associates new values to the given keys in the given lazy map.
The values are not evaluated, before their first retrieval. They are
evaluated at most once."
[m & kvs]
`(lazy-assoc* ~m ~@(quote-values kvs)))

(defn lazy-hash-map*
"lazy-hash-map* is the same as lazy-hash-map except that its a function
and it takes a seq of keys-delayed-value pairs."
[& kvs]
(create-lazy-map (apply hash-map kvs)))

(defmacro lazy-hash-map
"lazy-hash-map creates a map. The values are not evaluated before their
first retrieval. Each value is evaluated at most once. The underlying map
is a hash map."
[& kvs]
`(lazy-hash-map* ~@(quote-values kvs)))

(defn lazy-sorted-map*
"lazy-sorted-map* is the same as lazy-sorted-map except that its a
function and it takes a seq of keys-delayed-value pairs."
[& kvs]
(create-lazy-map (apply sorted-map kvs)))

(defmacro lazy-sorted-map
"lazy-sorted-map creates a map. The values are not evaluated before their
first retrieval. Each value is evaluated at most once. The underlying map
is a sorted map."
[& kvs]
`(lazy-sorted-map* ~@(quote-values kvs)))

(defn lazy-struct-map*
"lazy-struct-map* is the same as lazy-struct-map except that its a
function and it takes a seq of keys-delayed-value pairs together with the
struct basis."
[s & kvs]
(create-lazy-map (apply struct-map s kvs)))

(defmacro lazy-struct-map
"lazy-struct-map creates a map. The values are not evaluated before their
first retrieval. Each value is evaluated at most once. The underlying map
is a struct map according to the provided structure s."
[s & kvs]
`(lazy-struct-map* ~s ~@(quote-values kvs)))

(defn lazy-struct*
"lazy-struct* is the same as lazy-struct except that its a function and
it takes a seq of delayed value together with the struct basis."
[s & vs]
(create-lazy-map (apply struct s vs)))

(defmacro lazy-struct
"lazy-struct creates a map. The values are not evaluated before their
first retrieval. Each value is evaluated at most once. The underlying map
is a struct map according to the provided structure s. As with Clojure's
struct the values have to appear in the order of the keys in the structure."
[s & vs]
(let [vs (map (fn [v] `(delay ~v)) vs)]
`(lazy-struct* ~s ~@vs)))
2 changes: 1 addition & 1 deletion test/plumbing/lazymap_test.clj
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
(ns plumbing.lazymap-test
(:use plumbing.core clojure.test lazymap.core))
(:use plumbing.core clojure.test plumbing.lazymap))

(deftest lazy-map-entry-extend-test
(is (= :a (get-key [:a 2])))
Expand Down

0 comments on commit e6f99d8

Please sign in to comment.