Skip to content

Instantly share code, notes, and snippets.

@grinnbearit
Created September 15, 2010 09:08
Show Gist options
  • Save grinnbearit/580454 to your computer and use it in GitHub Desktop.
Save grinnbearit/580454 to your computer and use it in GitHub Desktop.
;;; Internally defining MultiMap fails on compilation with the error
;;;
;;; error: java.lang.VerifyError: (class: multi-map/PersistentMultiMap, method: equiv signature:
;;; (Ljava/lang/Object;)Z) Expecting to find integer on stack (multi_map.clj:0)
;;;
(ns multi-map
(:refer-clojure :exclude [count assoc empty cons seq])
(:require [clojure.set :as set])
(:import clojure.lang.MapEntry java.util.Map))
(declare mm-str mm-get mm-count mm-assoc mm-empty mm-conj mm-equiv mm-contains? mm-entryAt mm-seq mm-dissoc mm-empty?
mm-seq-pairs mm-conj-swap mm-assoc-swap mm-dissoc-one mm-containsValue mm-keys mm-vals mm-entrySet)
(defprotocol MultiMap
(count [this])
(assoc [this key val])
(empty [this])
(cons [this e])
(equiv [this o])
(containsKey [this key])
(entryAt [this key])
(seq [this])
(without [this key])
(seq-pairs [this])
(conj-swap [this key-coll] [this key-coll & key-colls])
(assoc-swap [this key coll] [this key coll & key-colls])
(dissoc-one [this key val] [this key val & kvs]))
(deftype PersistentMultiMap [key->vals __meta]
Object
(toString [this] (mm-str this))
clojure.lang.ILookup
(valAt [this key] (mm-get this key))
(valAt [this key not-found] (mm-get this key not-found))
clojure.lang.IPersistentMap
(count [this] (mm-count this))
(assoc [this key val] (mm-assoc this key val))
(empty [this] mm-empty)
(cons [this e] (mm-conj this e))
(equiv [this o] (mm-equiv this o))
(containsKey [this key] (mm-contains? this key))
(entryAt [this key] (mm-entryAt this key))
(seq [this] (mm-seq this))
(without [this key] (mm-dissoc this key))
java.io.Serializable
Map
(size [this] (mm-count this))
(isEmpty [this] (mm-empty? this))
(containsValue [this v] (mm-containsValue this v))
(get [this k] (mm-get this k))
(put [this k v] (throw (UnsupportedOperationException.)))
(remove [this k] (throw (UnsupportedOperationException.)))
(putAll [this m] (throw (UnsupportedOperationException.)))
(clear [this] (throw (UnsupportedOperationException.)))
(keySet [this] (mm-keys this))
(values [this] (mm-vals this))
(entrySet [this] (mm-entrySet this))
MultiMap
(seq-pairs [this] (mm-seq-pairs this))
(conj-swap [this key-coll] (mm-conj-swap this key-coll))
(conj-swap [this key-coll & key-colls] (mm-conj-swap this key-coll key-colls))
(assoc-swap [this key coll] (mm-assoc-swap this key coll))
(assoc-swap [this key coll & key-colls] (mm-assoc-swap this key coll key-colls))
(dissoc-one [this key val] (mm-dissoc-one this key val))
(dissoc-one [this key val & kvs] (mm-dissoc-one this key val kvs))
clojure.lang.IFn
(invoke [this k] (mm-get this k))
(invoke [this k not-found] (mm-get this k not-found))
clojure.lang.IObj
(meta [this] __meta)
(withMeta [this m] (PersistentMultiMap. key->vals m)))
(defn- ^:static mm-str [^PersistentMultiMap mm]
(str (.key->vals mm)))
(defn- mm-get
(^:static [^PersistentMultiMap mm key]
(mm-get mm key nil))
(^:static [^PersistentMultiMap mm key not-found]
(get (.key->vals mm) key not-found)))
(defn- mm-count [^PersistentMultiMap mm]
(clojure.core/count (.key->vals mm)))
(defn- mm-assoc [^PersistentMultiMap mm key val]
(let [key->vals (.key->vals mm)]
(if-let [s (get key->vals key nil)]
(PersistentMultiMap. (clojure.core/assoc key->vals key (conj s val)))
(PersistentMultiMap. (clojure.core/assoc key->vals key #{val})))))
(def ^:private mm-empty
(PersistentMultiMap. {} {}))
(defn- ^:static mm-conj [^PersistentMultiMap mm [key val]]
(mm-assoc mm key val))
(defn- ^:static mm-equiv [^PersistentMultiMap mm o]
(= (.key->vals mm) o))
(defn- ^:static mm-contains? [^PersistentMultiMap mm key]
(contains? (.key->vals mm) key))
(defn- ^:static mm-entryAt [^PersistentMultiMap mm key]
(if-let [v (mm-get mm key)]
(MapEntry. key v)
nil))
(defn- ^:static mm-seq [^PersistentMultiMap mm]
(clojure.core/seq (.key->vals mm)))
(defn- ^:static mm-dissoc [^PersistentMultiMap mm key]
(let [key->vals (.key->vals mm)]
(PersistentMultiMap. (dissoc key->vals key))))
(defn- ^:static mm-empty? [^PersistentMultiMap mm key]
(empty? (.key->vals mm)))
(defn- ^:static mm-containsValue [^PersistentMultiMap mm v]
(some #{v} (apply concat (vals (.key->vals mm)))))
(defn- ^:static mm-keys [^PersistentMultiMap mm]
(keys (.key->vals mm)))
(defn- ^:static mm-vals [^PersistentMultiMap mm]
(apply set/union (vals (.key->vals mm))))
(defn- ^:static mm-entrySet [^PersistentMultiMap mm]
(set (.key->vals mm)))
(defn- ^:static mm-seq-pairs [^PersistentMultiMap mm]
(mapcat (fn [[k s]] (map #(MapEntry. k %) s))
(clojure.core/seq (.key->vals mm))))
(defn- mm-conj-swap
(^:static [^PersistentMultiMap mm kvs]
(conj (.key->vals mm) kvs))
(^:static [^PersistentMultiMap mm kvs & kvss]
(apply conj (.key->vals mm) kvs kvss)))
(defn- mm-assoc-swap
(^:static [^PersistentMultiMap mm [key coll]]
(clojure.core/assoc (.key->vals mm) key (set coll)))
(^:static [^PersistentMultiMap mm key coll & key-colls]
(apply clojure.core/assoc (.key->vals mm) key (set coll)
(map (fn [[k c]] (MapEntry. k (set c))) (partition 2 key-colls)))))
(defn multi-map [& keyvals]
(into mm-empty (partition 2 keyvals)))
;;; extend-type works fine
;;;
(ns multi-map
(:refer-clojure :exclude [count assoc empty cons seq])
(:require [clojure.set :as set])
(:import clojure.lang.MapEntry java.util.Map))
(declare mm-str mm-get mm-count mm-assoc mm-empty mm-conj mm-equiv mm-contains? mm-entryAt mm-seq mm-dissoc mm-empty?
mm-seq-pairs mm-conj-swap mm-assoc-swap mm-dissoc-one mm-containsValue mm-keys mm-vals mm-entrySet)
(defprotocol MultiMap
(count [this])
(assoc [this key val])
(empty [this])
(cons [this e])
(equiv [this o])
(containsKey [this key])
(entryAt [this key])
(seq [this])
(without [this key])
(seq-pairs [this])
(conj-swap [this key-coll] [this key-coll & key-colls])
(assoc-swap [this key coll] [this key coll & key-colls])
(dissoc-one [this key val] [this key val & kvs]))
(deftype PersistentMultiMap [key->vals __meta]
Object
(toString [this] (mm-str this))
clojure.lang.ILookup
(valAt [this key] (mm-get this key))
(valAt [this key not-found] (mm-get this key not-found))
clojure.lang.IPersistentMap
(count [this] (mm-count this))
(assoc [this key val] (mm-assoc this key val))
(empty [this] mm-empty)
(cons [this e] (mm-conj this e))
(equiv [this o] (mm-equiv this o))
(containsKey [this key] (mm-contains? this key))
(entryAt [this key] (mm-entryAt this key))
(seq [this] (mm-seq this))
(without [this key] (mm-dissoc this key))
java.io.Serializable
Map
(size [this] (mm-count this))
(isEmpty [this] (mm-empty? this))
(containsValue [this v] (mm-containsValue this v))
(get [this k] (mm-get this k))
(put [this k v] (throw (UnsupportedOperationException.)))
(remove [this k] (throw (UnsupportedOperationException.)))
(putAll [this m] (throw (UnsupportedOperationException.)))
(clear [this] (throw (UnsupportedOperationException.)))
(keySet [this] (mm-keys this))
(values [this] (mm-vals this))
(entrySet [this] (mm-entrySet this))
clojure.lang.IFn
(invoke [this k] (mm-get this k))
(invoke [this k not-found] (mm-get this k not-found))
clojure.lang.IObj
(meta [this] __meta)
(withMeta [this m] (PersistentMultiMap. key->vals m)))
(extend-type PersistentMultiMap
MultiMap
(seq-pairs [this] (mm-seq-pairs this))
(conj-swap [this key-coll] (mm-conj-swap this key-coll))
(conj-swap [this key-coll & key-colls] (mm-conj-swap this key-coll key-colls))
(assoc-swap [this key coll] (mm-assoc-swap this key coll))
(assoc-swap [this key coll & key-colls] (mm-assoc-swap this key coll key-colls ))
(dissoc-one [this key val] (mm-dissoc-one this key val))
(dissoc-one [this key val & kvs] (mm-dissoc-one this key val kvs)))
(defn- ^:static mm-str [^PersistentMultiMap mm]
(str (.key->vals mm)))
(defn- mm-get
(^:static [^PersistentMultiMap mm key]
(mm-get mm key nil))
(^:static [^PersistentMultiMap mm key not-found]
(get (.key->vals mm) key not-found)))
(defn- mm-count [^PersistentMultiMap mm]
(clojure.core/count (.key->vals mm)))
(defn- mm-assoc [^PersistentMultiMap mm key val]
(let [key->vals (.key->vals mm)]
(if-let [s (get key->vals key nil)]
(PersistentMultiMap. (clojure.core/assoc key->vals key (conj s val)))
(PersistentMultiMap. (clojure.core/assoc key->vals key #{val})))))
(def ^:private mm-empty
(PersistentMultiMap. {} {}))
(defn- ^:static mm-conj [^PersistentMultiMap mm [key val]]
(mm-assoc mm key val))
(defn- ^:static mm-equiv [^PersistentMultiMap mm o]
(= (.key->vals mm) o))
(defn- ^:static mm-contains? [^PersistentMultiMap mm key]
(contains? (.key->vals mm) key))
(defn- ^:static mm-entryAt [^PersistentMultiMap mm key]
(if-let [v (mm-get mm key)]
(MapEntry. key v)
nil))
(defn- ^:static mm-seq [^PersistentMultiMap mm]
(clojure.core/seq (.key->vals mm)))
(defn- ^:static mm-dissoc [^PersistentMultiMap mm key]
(let [key->vals (.key->vals mm)]
(PersistentMultiMap. (dissoc key->vals key))))
(defn- ^:static mm-empty? [^PersistentMultiMap mm key]
(empty? (.key->vals mm)))
(defn- ^:static mm-containsValue [^PersistentMultiMap mm v]
(some #{v} (apply concat (vals (.key->vals mm)))))
(defn- ^:static mm-keys [^PersistentMultiMap mm]
(keys (.key->vals mm)))
(defn- ^:static mm-vals [^PersistentMultiMap mm]
(apply set/union (vals (.key->vals mm))))
(defn- ^:static mm-entrySet [^PersistentMultiMap mm]
(set (.key->vals mm)))
(defn- ^:static mm-seq-pairs [^PersistentMultiMap mm]
(mapcat (fn [[k s]] (map #(MapEntry. k %) s))
(clojure.core/seq (.key->vals mm))))
(defn- mm-conj-swap
(^:static [^PersistentMultiMap mm kvs]
(conj (.key->vals mm) kvs))
(^:static [^PersistentMultiMap mm kvs & kvss]
(apply conj (.key->vals mm) kvs kvss)))
(defn- mm-assoc-swap
(^:static [^PersistentMultiMap mm [key coll]]
(clojure.core/assoc (.key->vals mm) key (set coll)))
(^:static [^PersistentMultiMap mm key coll & key-colls]
(apply clojure.core/assoc (.key->vals mm) key (set coll)
(map (fn [[k c]] (MapEntry. k (set c))) (partition 2 key-colls)))))
(defn multi-map [& keyvals]
(into mm-empty (partition 2 keyvals)))
;;; Internally defining the MultiMap protocol works fine when there is no method clash
;;;
(ns multi-map
(:refer-clojure :exclude [count assoc empty cons seq])
(:require [clojure.set :as set])
(:import clojure.lang.MapEntry java.util.Map))
(declare mm-str mm-get mm-count mm-assoc mm-empty mm-conj mm-equiv mm-contains? mm-entryAt mm-seq mm-dissoc mm-empty?
mm-seq-pairs mm-conj-swap mm-assoc-swap mm-dissoc-one mm-containsValue mm-keys mm-vals mm-entrySet)
(defprotocol MultiMap
(seq-pairs [this])
(conj-swap [this key-coll] [this key-coll & key-colls])
(assoc-swap [this key coll] [this key coll & key-colls])
(dissoc-one [this key val] [this key val & kvs]))
(deftype PersistentMultiMap [key->vals __meta]
Object
(toString [this] (mm-str this))
clojure.lang.ILookup
(valAt [this key] (mm-get this key))
(valAt [this key not-found] (mm-get this key not-found))
clojure.lang.IPersistentMap
(count [this] (mm-count this))
(assoc [this key val] (mm-assoc this key val))
(empty [this] mm-empty)
(cons [this e] (mm-conj this e))
(equiv [this o] (mm-equiv this o))
(containsKey [this key] (mm-contains? this key))
(entryAt [this key] (mm-entryAt this key))
(seq [this] (mm-seq this))
(without [this key] (mm-dissoc this key))
java.io.Serializable
Map
(size [this] (mm-count this))
(isEmpty [this] (mm-empty? this))
(containsValue [this v] (mm-containsValue this v))
(get [this k] (mm-get this k))
(put [this k v] (throw (UnsupportedOperationException.)))
(remove [this k] (throw (UnsupportedOperationException.)))
(putAll [this m] (throw (UnsupportedOperationException.)))
(clear [this] (throw (UnsupportedOperationException.)))
(keySet [this] (mm-keys this))
(values [this] (mm-vals this))
(entrySet [this] (mm-entrySet this))
MultiMap
(seq-pairs [this] (mm-seq-pairs this))
(conj-swap [this key-coll] (mm-conj-swap this key-coll))
(conj-swap [this key-coll & key-colls] (mm-conj-swap this key-coll key-colls))
(assoc-swap [this key coll] (mm-assoc-swap this key coll))
(assoc-swap [this key coll & key-colls] (mm-assoc-swap this key coll key-colls))
(dissoc-one [this key val] (mm-dissoc-one this key val))
(dissoc-one [this key val & kvs] (mm-dissoc-one this key val kvs))
clojure.lang.IFn
(invoke [this k] (mm-get this k))
(invoke [this k not-found] (mm-get this k not-found))
clojure.lang.IObj
(meta [this] __meta)
(withMeta [this m] (PersistentMultiMap. key->vals m)))
(defn- ^:static mm-str [^PersistentMultiMap mm]
(str (.key->vals mm)))
(defn- mm-get
(^:static [^PersistentMultiMap mm key]
(mm-get mm key nil))
(^:static [^PersistentMultiMap mm key not-found]
(get (.key->vals mm) key not-found)))
(defn- mm-count [^PersistentMultiMap mm]
(clojure.core/count (.key->vals mm)))
(defn- mm-assoc [^PersistentMultiMap mm key val]
(let [key->vals (.key->vals mm)]
(if-let [s (get key->vals key nil)]
(PersistentMultiMap. (clojure.core/assoc key->vals key (conj s val)))
(PersistentMultiMap. (clojure.core/assoc key->vals key #{val})))))
(def ^:private mm-empty
(PersistentMultiMap. {} {}))
(defn- ^:static mm-conj [^PersistentMultiMap mm [key val]]
(mm-assoc mm key val))
(defn- ^:static mm-equiv [^PersistentMultiMap mm o]
(= (.key->vals mm) o))
(defn- ^:static mm-contains? [^PersistentMultiMap mm key]
(contains? (.key->vals mm) key))
(defn- ^:static mm-entryAt [^PersistentMultiMap mm key]
(if-let [v (mm-get mm key)]
(MapEntry. key v)
nil))
(defn- ^:static mm-seq [^PersistentMultiMap mm]
(clojure.core/seq (.key->vals mm)))
(defn- ^:static mm-dissoc [^PersistentMultiMap mm key]
(let [key->vals (.key->vals mm)]
(PersistentMultiMap. (dissoc key->vals key))))
(defn- ^:static mm-empty? [^PersistentMultiMap mm key]
(empty? (.key->vals mm)))
(defn- ^:static mm-containsValue [^PersistentMultiMap mm v]
(some #{v} (apply concat (vals (.key->vals mm)))))
(defn- ^:static mm-keys [^PersistentMultiMap mm]
(keys (.key->vals mm)))
(defn- ^:static mm-vals [^PersistentMultiMap mm]
(apply set/union (vals (.key->vals mm))))
(defn- ^:static mm-entrySet [^PersistentMultiMap mm]
(set (.key->vals mm)))
(defn- ^:static mm-seq-pairs [^PersistentMultiMap mm]
(mapcat (fn [[k s]] (map #(MapEntry. k %) s))
(clojure.core/seq (.key->vals mm))))
(defn- mm-conj-swap
(^:static [^PersistentMultiMap mm kvs]
(conj (.key->vals mm) kvs))
(^:static [^PersistentMultiMap mm kvs & kvss]
(apply conj (.key->vals mm) kvs kvss)))
(defn- mm-assoc-swap
(^:static [^PersistentMultiMap mm [key coll]]
(clojure.core/assoc (.key->vals mm) key (set coll)))
(^:static [^PersistentMultiMap mm key coll & key-colls]
(apply clojure.core/assoc (.key->vals mm) key (set coll)
(map (fn [[k c]] (MapEntry. k (set c))) (partition 2 key-colls)))))
(defn multi-map [& keyvals]
(into mm-empty (partition 2 keyvals)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment