ObjMap

typesince v0.0-927Edit
satisfies IAssociative ICollection ICounted IEditableCollection IEmptyableCollection IEquiv IFind IFn IHash IKVReduce ILookup IMap IMeta IPrintWithWriter ISeqable IWithMeta

(ObjMap. meta keys strobj update-count __hash)

Source code @ clojurescript:src/main/cljs/cljs/core.cljs
(deftype ObjMap [meta keys strobj update-count ^:mutable __hash]
  Object
  (toString [coll]
    (pr-str* coll))
  (equiv [this other]
    (-equiv this other))

  IWithMeta
  (-with-meta [coll new-meta]
    (if (identical? new-meta meta)
      coll
      (ObjMap. new-meta keys strobj update-count __hash)))

  IMeta
  (-meta [coll] meta)

  ICollection
  (-conj [coll entry]
    (if (vector? entry)
      (-assoc coll (-nth entry 0) (-nth entry 1))
      (reduce -conj
              coll
              entry)))

  IEmptyableCollection
  (-empty [coll] (-with-meta (.-EMPTY ObjMap) meta))

  IEquiv
  (-equiv [coll other] (equiv-map coll other))

  IHash
  (-hash [coll] (caching-hash coll hash-unordered-coll __hash))

  ISeqable
  (-seq [coll]
    (when (pos? (alength keys))
      (map #(vector % (unchecked-get strobj %))
           (.sort keys obj-map-compare-keys))))

  ICounted
  (-count [coll] (alength keys))

  ILookup
  (-lookup [coll k] (-lookup coll k nil))
  (-lookup [coll k not-found]
    (if (and (string? k)
             (not (nil? (scan-array 1 k keys))))
      (unchecked-get strobj k)
      not-found))

  IAssociative
  (-assoc [coll k v]
    (if (string? k)
        (if (or (> update-count (.-HASHMAP_THRESHOLD ObjMap))
                (>= (alength keys) (.-HASHMAP_THRESHOLD ObjMap)))
          (obj-map->hash-map coll k v)
          (if-not (nil? (scan-array 1 k keys))
            (let [new-strobj (obj-clone strobj keys)]
              (gobject/set new-strobj k v)
              (ObjMap. meta keys new-strobj (inc update-count) nil)) ; overwrite
            (let [new-strobj (obj-clone strobj keys) ; append
                  new-keys (aclone keys)]
              (gobject/set new-strobj k v)
              (.push new-keys k)
              (ObjMap. meta new-keys new-strobj (inc update-count) nil))))
        ;; non-string key. game over.
        (obj-map->hash-map coll k v)))
  (-contains-key? [coll k]
    (if (and (string? k)
             (not (nil? (scan-array 1 k keys))))
      true
      false))

  IFind
  (-find [coll k]
    (when (and (string? k)
            (not (nil? (scan-array 1 k keys))))
      (MapEntry. k (unchecked-get strobj k) nil)))

  IKVReduce
  (-kv-reduce [coll f init]
    (let [len (alength keys)]
      (loop [keys (.sort keys obj-map-compare-keys)
             init init]
        (if (seq keys)
          (let [k (first keys)
                init (f init k (unchecked-get strobj k))]
            (if (reduced? init)
              @init
              (recur (rest keys) init)))
          init))))

  IMap
  (-dissoc [coll k]
    (if (and (string? k)
             (not (nil? (scan-array 1 k keys))))
      (let [new-keys (aclone keys)
            new-strobj (obj-clone strobj keys)]
        (.splice new-keys (scan-array 1 k new-keys) 1)
        (js-delete new-strobj k)
        (ObjMap. meta new-keys new-strobj (inc update-count) nil))
      coll)) ; key not found, return coll unchanged

  IFn
  (-invoke [coll k]
    (-lookup coll k))
  (-invoke [coll k not-found]
    (-lookup coll k not-found))

  IEditableCollection
  (-as-transient [coll]
    (transient (into (hash-map) coll))))