ObjMap

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

(ObjMap. meta strkeys strobj __hash)

Source code @ clojurescript:src/main/cljs/cljs/core.cljs
(deftype ObjMap [meta strkeys strobj ^:mutable __hash]
  Object
  (toString [coll]
    (pr-str* coll))
  (keys [coll]
    (es6-iterator
      (prim-seq
        (.map (.sort strkeys obj-map-compare-keys)
          obj-map-key->keyword))))
  (entries [coll]
    (es6-entries-iterator (-seq coll)))
  (values [coll]
    (es6-iterator
      (prim-seq
        (.map (.sort strkeys obj-map-compare-keys)
          #(unchecked-get strobj %)))))
  (has [coll k]
    (contains? coll k))
  (get [coll k not-found]
    (-lookup coll k not-found))
  (forEach [coll f]
    (.forEach (.sort strkeys obj-map-compare-keys)
      #(f (unchecked-get strobj %) (obj-map-key->keyword %))))

  IWithMeta
  (-with-meta [coll meta] (ObjMap. meta strkeys strobj __hash))

  IMeta
  (-meta [coll] meta)

  ICloneable
  (-clone [coll] (ObjMap. meta strkeys strobj __hash))

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

  IEmptyableCollection
  (-empty [coll] (-with-meta (. ObjMap -EMPTY) 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 strkeys))
      (prim-seq
        (.map (.sort strkeys obj-map-compare-keys)
          #(MapEntry. (obj-map-key->keyword %) (unchecked-get strobj %) nil)))))

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

  ILookup
  (-lookup [coll k] (-lookup coll k nil))
  (-lookup [coll k not-found]
    (let [k (if-not (keyword? k) k (keyword->obj-map-key k))]
      (if (and (string? k)
               (not (nil? (scan-array 1 k strkeys))))
        (unchecked-get strobj k)
        not-found)))

  IAssociative
  (-assoc [coll k v]
    (let [k (if-not (keyword? k) k (keyword->obj-map-key k))]
      (if (string? k)
        (if-not (nil? (scan-array 1 k strkeys))
          (if (identical? v (gobject/get strobj k))
            coll
            ; overwrite
            (let [new-strobj (obj-clone strobj strkeys)]
              (gobject/set new-strobj k v)
              (ObjMap. meta strkeys new-strobj nil))) 
          ; append
          (let [new-strobj (obj-clone strobj strkeys) 
                new-keys (aclone strkeys)]
            (gobject/set new-strobj k v)
            (.push new-keys k)
            (ObjMap. meta new-keys new-strobj nil)))
        ; non-string key. game over.
        (-with-meta
          (-kv-reduce coll
            (fn [ret k v]
              (-assoc ret k v))
            (hash-map-lite k v))
          meta))))
  (-contains-key? [coll k]
    (let [k (if-not (keyword? k) k (keyword->obj-map-key k))]
      (if (and (string? k)
               (not (nil? (scan-array 1 k strkeys))))
        true
        false)))

  IFind
  (-find [coll k]
    (let [k' (if-not (keyword? k) k (keyword->obj-map-key k))]
      (when (and (string? k')
                 (not (nil? (scan-array 1 k' strkeys))))
        (MapEntry. k (unchecked-get strobj k') nil))))

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

  IIterable
  (-iterator [coll]
    (ObjMapIterator. strkeys strobj 0))

  IReduce
  (-reduce [coll f]
    (iter-reduce coll f))
  (-reduce [coll f start]
    (iter-reduce coll f start))

  IMap
  (-dissoc [coll k]
    (let [k (if-not (keyword? k) k (keyword->obj-map-key k))]
      (if (and (string? k)
               (not (nil? (scan-array 1 k strkeys))))
        (let [new-keys (aclone strkeys)
              new-strobj (obj-clone strobj strkeys)]
          (.splice new-keys (scan-array 1 k new-keys) 1)
          (js-delete new-strobj k)
          (ObjMap. meta new-keys new-strobj 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]
    coll)

  ITransientCollection
  (-conj! [coll val]
    (-conj coll val))
  (-persistent! [coll]
    coll)

  ITransientAssociative
  (-assoc! [coll key val]
    (-assoc coll key val))

  ITransientMap
  (-dissoc! [coll key]
    (-dissoc coll key))

  IPrintWithWriter
  (-pr-writer [coll writer opts]
    (print-map coll pr-writer writer opts)))