All Downloads are FREE. Search and download functionalities are using the official Maven repository.

clojure.core.rrb_vector.rrbt.cljs Maven / Gradle / Ivy

The newest version!
(ns clojure.core.rrb-vector.rrbt
  (:refer-clojure :exclude [array-for push-tail pop-tail new-path do-assoc])
  (:require [clojure.core.rrb-vector.protocols
             :refer [PSliceableVector -slicev
                     PSpliceableVector -splicev]]
            [clojure.core.rrb-vector.nodes
             :refer [regular? empty-node ranges overflow? last-range
                     regular-ranges first-child last-child remove-leftmost-child
                     replace-leftmost-child replace-rightmost-child
                     fold-tail new-path* index-of-nil]]
            [clojure.core.rrb-vector.trees
             :refer [tail-offset array-for push-tail pop-tail new-path
                     do-assoc]]
            [clojure.core.rrb-vector.transients
             :refer [ensure-editable editable-root editable-tail push-tail!
                     pop-tail! do-assoc!]]))

(def ^:const rrbt-concat-threshold 33)
(def ^:const max-extra-search-steps 2)

(defprotocol AsRRBT
  (-as-rrbt [v]))

;;; chunked seqs: can't reuse cljs.core's without tweaks, since rrb
;;; vectors have a different array-for

(declare rrb-chunked-seq)

(deftype RRBChunkedSeq [vec node i off meta ^:mutable __hash]
  Object
  (toString [coll]
    (pr-str* coll))

  IPrintWithWriter
  (-pr-writer [this writer opts]
    (pr-sequential-writer writer pr-writer "(" " " ")" opts this))

  IWithMeta
  (-with-meta [coll m]
    (rrb-chunked-seq vec node i off m))

  IMeta
  (-meta [coll] meta)

  ISeqable
  (-seq [coll] coll)

  ISequential
  IEquiv
  (-equiv [coll other] (equiv-sequential coll other))

  ASeq
  ISeq
  (-first [coll]
    (aget node off))

  (-rest [coll]
    (if (< (inc off) (alength node))
      (let [s (rrb-chunked-seq vec node i (inc off))]
        (if (nil? s)
          ()
          s))
      (-chunked-rest coll)))

  INext
  (-next [coll]
    (if (< (inc off) (alength node))
      (let [s (rrb-chunked-seq vec node i (inc off))]
        (if (nil? s)
          nil
          s))
      (-chunked-next coll)))

  ICollection
  (-conj [coll o]
    (cons o coll))

  IEmptyableCollection
  (-empty [coll]
    (with-meta cljs.core.List.EMPTY meta))

  IChunkedSeq
  (-chunked-first [coll]
    (array-chunk node off))

  (-chunked-rest [coll]
    (let [l (alength node)
          s (when (< (+ i l) (-count vec))
              (rrb-chunked-seq vec (+ i l) 0))]
      (if (nil? s)
        ()
        s)))

  IChunkedNext
  (-chunked-next [coll]
    (let [l (alength node)
          s (when (< (+ i l) (-count vec))
              (rrb-chunked-seq vec (+ i l) 0))]
      (if (nil? s)
        nil
        s)))

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

  IReduce
  (-reduce [coll f]
    (ci-reduce (cljs.core/subvec vec (+ i off) (count vec)) f))

  (-reduce [coll f start]
    (ci-reduce (cljs.core/subvec vec (+ i off) (count vec)) f start)))

(defn rrb-chunked-seq
  ([vec i off]
     (let [cnt   (.-cnt vec)
           shift (.-shift vec)
           root  (.-root vec)
           tail  (.-tail vec)]
       (RRBChunkedSeq. vec (array-for cnt shift root tail i) i off nil nil)))
  ([vec node i off]
     (RRBChunkedSeq. vec node i off nil nil))
  ([vec node i off meta]
     (RRBChunkedSeq. vec node i off meta nil)))

(defn slice-right [node shift end]
  (if (zero? shift)
    ;; potentially return a short node, although it would be better to
    ;; make sure a regular leaf is always left at the right, with any
    ;; items over the final 32 moved into tail (and then potentially
    ;; back into the tree should the tail become too long...)
    (let [arr     (.-arr node)
          new-arr (make-array end)]
      (array-copy arr 0 new-arr 0 end)
      (->VectorNode nil new-arr))
    (let [reg? (regular? node)
          rngs (if-not reg? (ranges node))
          i    (bit-and (bit-shift-right (dec end) shift) 0x1f)
          i    (if reg?
                 i
                 (loop [j i]
                   (if (<= end (aget rngs j))
                     j
                     (recur (inc j)))))
          child-end (if reg?
                      (let [ce (mod end (bit-shift-left 1 shift))]
                        (if (zero? ce) (bit-shift-left 1 shift) ce))
                      (if (pos? i)
                        (- end (aget rngs (dec i)))
                        end))
          arr       (.-arr node)
          new-child (slice-right (aget arr i) (- shift 5) child-end)
          regular-child? (if (== shift 5)
                           (== 32 (alength (.-arr new-child)))
                           (regular? new-child))
          new-arr   (make-array (if (and reg? regular-child?) 32 33))
          new-child-rng  (if regular-child?
                           (let [m (mod child-end (bit-shift-left 1 shift))]
                             (if (zero? m) (bit-shift-left 1 shift) m))
                           (if (== shift 5)
                             (alength (.-arr new-child))
                             (last-range new-child)))]
      (array-copy arr 0 new-arr 0 i)
      (aset new-arr i new-child)
      (if-not (and reg? regular-child?)
        (let [new-rngs (make-array 33)
              step     (bit-shift-left 1 shift)]
          (if reg?
            (dotimes [j i]
              (aset new-rngs j (* (inc j) step)))
            (dotimes [j i]
              (aset new-rngs j (aget rngs j))))
          (aset new-rngs i (+ (if (pos? i) (aget new-rngs (dec i)) 0)
                              new-child-rng))
          (aset new-rngs 32 (inc i))
          (aset new-arr 32 new-rngs)))
      (->VectorNode nil new-arr))))

(defn slice-left [node shift start end]
  (if (zero? shift)
    ;; potentially return a short node
    (let [arr     (.-arr node)
          new-len (- (alength arr) start)
          new-arr (make-array new-len)]
      (array-copy arr start new-arr 0 new-len)
      (->VectorNode nil new-arr))
    (let [reg? (regular? node)
          arr  (.-arr node)
          rngs (if-not reg? (ranges node))
          i    (bit-and (bit-shift-right start shift) 0x1f)
          i    (if reg?
                 i
                 (loop [j i]
                   (if (< start (aget rngs j))
                     j
                     (recur (inc j)))))
          len  (if reg?
                 (loop [i i]
                   (if (or (== i 32) (nil? (aget arr i)))
                     i
                     (recur (inc i))))
                 (aget rngs 32))
          child-start (if (pos? i)
                        (- start
                           (if reg?
                             (* i (bit-shift-left 1 shift))
                             (aget rngs (dec i))))
                        start)
          child-end   (min (bit-shift-left 1 shift)
                           (if (pos? i)
                             (- end
                                (if reg?
                                  (* i (bit-shift-left 1 shift))
                                  (aget rngs (dec i))))
                             end))
          new-child   (slice-left (aget arr i)
                                  (- shift 5)
                                  child-start
                                  child-end)
          new-len     (- len i)
          new-len     (if (nil? new-child) (dec new-len) new-len)]
      (cond
        (zero? new-len)
        nil

        reg?
        (let [new-arr (make-array 33)
              rngs    (make-array 33)
              rng0    (if (or (nil? new-child)
                              (== shift 5)
                              (regular? new-child))
                        (- (bit-shift-left 1 shift)
                           (bit-and (bit-shift-right start (- shift 5)) 0x1f))
                        (last-range new-child))
              step    (bit-shift-left 1 shift)]
          (loop [j 0
                 r rng0]
            (when (< j new-len)
              (aset rngs j r)
              (recur (inc j) (+ r step))))
          (aset rngs (dec new-len) (- end start))
          (aset rngs 32 new-len)
          (array-copy arr (if (nil? new-child) (inc i) i)
                      new-arr 0
                      new-len)
          (if-not (nil? new-child)
            (aset new-arr 0 new-child))
          (aset new-arr 32 rngs)
          (->VectorNode (.-edit node) new-arr))

        :else
        (let [new-arr  (make-array 33)
              new-rngs (make-array 33)]
          (loop [j 0 i i]
            (when (< j new-len)
              (aset new-rngs j (- (aget rngs i) start))
              (recur (inc j) (inc i))))
          (aset new-rngs 32 new-len)
          (array-copy arr (if (nil? new-child) (inc i) i)
                      new-arr 0
                      new-len)
          (if-not (nil? new-child)
            (aset new-arr 0 new-child))
          (aset new-arr 32 new-rngs)
          (->VectorNode (.-edit node) new-arr))))))

(declare splice-rrbts ->Transient)

(deftype Vector [cnt shift root tail meta ^:mutable __hash]
  Object
  (toString [this]
    (pr-str* this))

  IPrintWithWriter
  (-pr-writer [this writer opts]
    (pr-sequential-writer writer pr-writer "[" " " "]" opts this))

  IWithMeta
  (-with-meta [this meta]
    (Vector. cnt shift root tail meta __hash))

  IMeta
  (-meta [this]
    meta)

  ISequential
  IEquiv
  (-equiv [this that]
    (equiv-sequential this that))

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

  ISeqable
  (-seq [this]
    (cond
      (zero? cnt) nil
      (zero? (tail-offset cnt tail)) (array-seq tail)
      :else (rrb-chunked-seq this 0 0)))

  ICounted
  (-count [_]
    cnt)

  IIndexed
  (-nth [this i]
    (if (and (<= 0 i) (< i cnt))
      (let [tail-off (- cnt (alength tail))]
        (if (<= tail-off i)
          (aget tail (- i tail-off))
          (loop [i i node root shift shift]
            (if (zero? shift)
              (let [arr (.-arr node)]
                (aget arr (bit-and (bit-shift-right i shift) 0x1f)))
              (if (regular? node)
                (let [arr (.-arr node)
                      idx (bit-and (bit-shift-right i shift) 0x1f)]
                  (loop [i     i
                         node  (aget arr idx)
                         shift (- shift 5)]
                    (let [arr (.-arr node)
                          idx (bit-and (bit-shift-right i shift) 0x1f)]
                      (if (zero? shift)
                        (aget arr idx)
                        (recur i (aget arr idx) (- shift 5))))))
                (let [arr  (.-arr node)
                      rngs (ranges node)
                      idx  (loop [j (bit-and (bit-shift-right i shift) 0x1f)]
                             (if (< i (aget rngs j))
                               j
                               (recur (inc j))))
                      i    (if (zero? idx)
                             i
                             (- i (aget rngs (dec idx))))]
                  (recur i (aget arr idx) (- shift 5))))))))
      (vector-index-out-of-bounds i cnt)))

  (-nth [this i not-found]
    (if (and (>= i 0) (< i cnt))
      (-nth this i)
      not-found))

  IMapEntry
  (-key [this]
    (-nth this 0))

  (-val [this]
    (-nth this 1))

  ICollection
  (-conj [this val]
    (if (< (alength tail) 32)
      (let [tail-len (alength tail)
            new-tail (make-array (inc tail-len))]
        (array-copy tail 0 new-tail 0 tail-len)
        (aset new-tail tail-len val)
        (Vector. (inc cnt) shift root new-tail meta nil))
      (let [tail-node (->VectorNode (.-edit root) tail)
            new-tail  (let [new-arr (make-array 1)]
                        (aset new-arr 0 val)
                        new-arr)]
        (if (overflow? root shift cnt)
          (if (regular? root)
            (let [new-arr  (make-array 32)
                  new-root (->VectorNode (.-edit root) new-arr)]
              (doto new-arr
                (aset 0 root)
                (aset 1 (new-path tail (.-edit root) shift tail-node)))
              (Vector. (inc cnt) (+ shift 5) new-root new-tail meta nil))
            (let [new-arr  (make-array 33)
                  new-rngs (make-array 33)
                  new-root (->VectorNode (.-edit root) new-arr)
                  root-total-range (aget (ranges root) 31)]
              (doto new-arr
                (aset 0  root)
                (aset 1  (new-path tail (.-edit root) shift tail-node))
                (aset 32 new-rngs))
              (doto new-rngs
                (aset 0  root-total-range)
                (aset 1  (+ root-total-range 32))
                (aset 32 2))
              (Vector. (inc cnt) (+ shift 5) new-root new-tail meta nil)))
          (Vector. (inc cnt) shift
                   (push-tail shift cnt (.-edit root) root tail-node)
                   new-tail
                   meta
                   nil)))))

  IEmptyableCollection
  (-empty [_]
    (with-meta cljs.core.PersistentVector.EMPTY meta))

  IStack
  (-peek [this]
    (when (pos? cnt)
      (-nth this (dec cnt))))

  (-pop [this]
    (cond
      (zero? cnt)
      (throw (js/Error. "Can't pop empty vector"))

      (== 1 cnt)
      (-with-meta cljs.core.PersistentVector.EMPTY meta)

      (> (alength tail) 1)
      (let [new-tail (make-array (dec (alength tail)))]
        (array-copy tail 0 new-tail 0 (alength new-tail))
        (Vector. (dec cnt) shift root new-tail meta nil))

      :else
      (let [new-tail (array-for cnt shift root tail (- cnt 2))
            root-cnt (tail-offset cnt tail)
            new-root (pop-tail shift root-cnt (.-edit root) root)]
        (cond
          (nil? new-root)
          (Vector. (dec cnt) shift empty-node new-tail meta nil)

          (and (> shift 5)
               (nil? (aget (.-arr new-root) 1)))
          (Vector. (dec cnt)
                   (- shift 5)
                   (aget (.-arr new-root) 0)
                   new-tail
                   meta
                   nil)

          :else
          (Vector. (dec cnt) shift new-root new-tail meta nil)))))

  IVector
  (-assoc-n [this i val]
    (cond
      (and (<= 0 i) (< i cnt))
      (let [tail-off (tail-offset cnt tail)]
        (if (>= i tail-off)
          (let [new-tail (make-array (alength tail))
                idx (- i tail-off)]
            (array-copy tail 0 new-tail 0 (alength tail))
            (aset new-tail idx val)
            (Vector. cnt shift root new-tail meta nil))
          (Vector. cnt shift (do-assoc shift root i val) tail meta nil)))

      (== i cnt) (-conj this val)
      :else (vector-index-out-of-bounds i cnt)))

  IReversible
  (-rseq [this]
    (if (pos? cnt)
      (RSeq. this (dec cnt) nil)
      nil))

  IAssociative
  (-assoc [this k v]
    (-assoc-n this k v))

  ILookup
  (-lookup [this k]
    (-nth this k nil))

  (-lookup [this k not-found]
    (-nth this k not-found))

  IFn
  (-invoke [this k]
    (-nth this k))

  (-invoke [this k not-found]
    (-nth this k not-found))

  IReduce
  (-reduce [this f]
    (ci-reduce this f))

  (-reduce [this f start]
    (ci-reduce this f start))

  IKVReduce
  (-kv-reduce [this f init]
    (loop [i    0
           j    0
           init init
           arr  (array-for cnt shift root tail i)
           lim  (dec (alength arr))
           step (inc lim)]
      (let [init (f init (+ i j) (aget arr j))]
        (if (reduced? init)
          @init
          (if (< j lim)
            (recur i (inc j) init arr lim step)
            (let [i (+ i step)]
              (if (< i cnt)
                (let [arr (array-for cnt shift root tail i)
                      len (alength arr)
                      lim (dec len)]
                  (recur i 0 init arr lim len))
                init)))))))

  IComparable
  (-compare [this that]
    (compare-indexed this that))

  IEditableCollection
  (-as-transient [this]
    (->Transient cnt
                 shift
                 (editable-root root)
                 (editable-tail tail)
                 (alength tail)))

  PSliceableVector
  (-slicev [this start end]
    (let [new-cnt (- end start)]
      (cond
        (or (neg? start) (> end cnt))
        (throw (js/Error. "vector index out of bounds"))

        (== start end)
        ;; NB. preserves metadata
        (empty this)

        (> start end)
        (throw (js/Error. "start index greater than end index"))

        :else
        (let [tail-off (tail-offset cnt tail)]
          (if (>= start tail-off)
            (let [new-tail (make-array new-cnt)]
              (array-copy tail (- start tail-off)
                          new-tail 0
                          new-cnt)
              (Vector. new-cnt 5 empty-node new-tail meta nil))
            (let [tail-cut? (> end tail-off)
                  new-root  (if tail-cut?
                              root
                              (slice-right root shift end))
                  new-root  (if (zero? start)
                              new-root
                              (slice-left new-root shift start
                                          (min end tail-off)))
                  new-tail  (if tail-cut?
                              (let [new-len  (- end tail-off)
                                    new-tail (make-array new-len)]
                                (array-copy tail 0 new-tail 0 new-len)
                                new-tail)
                              (array-for new-cnt shift new-root (array)
                                         (dec new-cnt)))
                  new-root  (if tail-cut?
                              new-root
                              (pop-tail shift new-cnt (.-edit new-root)
                                        new-root))]
              (if (nil? new-root)
                (Vector. new-cnt 5 empty-node new-tail meta nil)
                (loop [r new-root
                       s shift]
                  (if (and (> s 5)
                           (nil? (aget (.-arr r) 1)))
                    (recur (aget (.-arr r) 0) (- s 5))
                    (Vector. new-cnt s r new-tail meta nil))))))))))

  PSpliceableVector
  (-splicev [this that]
    (splice-rrbts this (-as-rrbt that)))

  AsRRBT
  (-as-rrbt [this]
    this))

(extend-protocol AsRRBT
  cljs.core.PersistentVector
  (-as-rrbt [this]
    (Vector. (count this) (.-shift this) (.-root this) (.-tail this)
             (meta this) nil))

  Subvec
  (-as-rrbt [this]
    (let [v     (.-v this)
          start (.-start this)
          end   (.-end this)]
      (-slicev (-as-rrbt v) start end))))

(defn shift-from-to [node from to]
  (cond
    (== from to)
    node

    (regular? node)
    (recur (->VectorNode (.-edit node) (doto (make-array 32) (aset 0 node)))
           (+ 5 from)
           to)

    :else
    (recur (->VectorNode (.-edit node)
                         (doto (make-array 33)
                           (aset 0 node)
                           (aset 32
                                 (doto (make-array 33)
                                   (aset 0  (last-range node))
                                   (aset 32 1)))))
           (+ 5 from)
           to)))

(defn slot-count [node shift]
  (let [arr (.-arr node)]
    (if (zero? shift)
      (alength arr)
      (if (regular? node)
        (index-of-nil arr)
        (let [rngs (ranges node)]
          (aget rngs 32))))))

(defn subtree-branch-count [node shift]
  ;; NB. positive shifts only
  (let [arr (.-arr node)
        cs  (- shift 5)]
    (if (regular? node)
      (loop [i 0 sbc 0]
        (if (== i 32)
          sbc
          (if-let [child (aget arr i)]
            (recur (inc i) (+ sbc (slot-count child cs)))
            sbc)))
      (let [lim (aget (ranges node) 32)]
        (loop [i 0 sbc 0]
          (if (== i lim)
            sbc
            (let [child (aget arr i)]
              (recur (inc i) (+ sbc (slot-count child cs))))))))))

(defn leaf-seq [arr]
  (mapcat #(.-arr %) (take (index-of-nil arr) arr)))

(defn rebalance-leaves
  [n1 cnt1 n2 cnt2 transferred-leaves]
  (let [slc1 (slot-count n1 5)
        slc2 (slot-count n2 5)
        a    (+ slc1 slc2)
        sbc1 (subtree-branch-count n1 5)
        sbc2 (subtree-branch-count n2 5)
        p    (+ sbc1 sbc2)
        e    (- a (inc (quot (dec p) 32)))]
    (cond
      (<= e max-extra-search-steps)
      (array n1 n2)

      (<= (+ sbc1 sbc2) 1024)
      (let [reg?    (zero? (mod p 32))
            new-arr (make-array (if reg? 32 33))
            new-n1  (->VectorNode nil new-arr)]
        (loop [i  0
               bs (partition-all 32
                                 (concat (leaf-seq (.-arr n1))
                                         (leaf-seq (.-arr n2))))]
          (when-first [block bs]
            (let [a (make-array (count block))]
              (loop [i 0 xs (seq block)]
                (when xs
                  (aset a i (first xs))
                  (recur (inc i) (next xs))))
              (aset new-arr i (->VectorNode nil a))
              (recur (inc i) (next bs)))))
        (if-not reg?
          (aset new-arr 32 (regular-ranges 5 p)))
        (set! (.-val transferred-leaves) sbc2)
        (array new-n1 nil))

      :else
      (let [reg?     (zero? (mod p 32))
            new-arr1 (make-array 32)
            new-arr2 (make-array (if reg? 32 33))
            new-n1   (->VectorNode nil new-arr1)
            new-n2   (->VectorNode nil new-arr2)]
        (loop [i  0
               bs (partition-all 32
                                 (concat (leaf-seq (make-array n1))
                                         (leaf-seq (make-array n2))))]
          (when-first [block bs]
            (let [a (make-array (count block))]
              (loop [i 0 xs (seq block)]
                (when xs
                  (aset a i (first xs))
                  (recur (inc i) (next xs))))
              (if (< i 32)
                (aset new-arr1 i (->VectorNode nil a))
                (aset new-arr2 (- i 32) (->VectorNode nil a)))
              (recur (inc i) (next bs)))))
        (if-not reg?
          (aset new-arr2 32 (regular-ranges 5 (- p 1024))))
        (set! (.-val transferred-leaves) (- 1024 sbc1))
        (array new-n1 new-n2)))))

(defn child-seq [node shift cnt]
  (let [arr  (.-arr node)
        rngs (if (regular? node)
               (regular-ranges shift cnt)
               (ranges node))
        cs   (if rngs (aget rngs 32) (index-of-nil arr))
        cseq (fn cseq [c r]
               (let [arr  (.-arr c)
                     rngs (if (regular? c)
                            (regular-ranges (- shift 5) r)
                            (ranges c))
                     gcs  (if rngs (aget rngs 32) (index-of-nil arr))]
                 (map list
                      (take gcs arr)
                      (take gcs (map - rngs (cons 0 rngs))))))]
    (mapcat cseq (take cs arr) (take cs (map - rngs (cons 0 rngs))))))

(defn rebalance
  [shift n1 cnt1 n2 cnt2 transferred-leaves]
  (if (nil? n2)
    (array n1 nil)
    (let [slc1 (slot-count n1 shift)
          slc2 (slot-count n2 shift)
          a    (+ slc1 slc2)
          sbc1 (subtree-branch-count n1 shift)
          sbc2 (subtree-branch-count n2 shift)
          p    (+ sbc1 sbc2)
          e    (- a (inc (quot (dec p) 32)))]
      (cond
        (<= e max-extra-search-steps)
        (array n1 n2)

        (<= (+ sbc1 sbc2) 1024)
        (let [new-arr  (make-array 33)
              new-rngs (make-array 33)
              new-n1   (->VectorNode nil new-arr)]
          (loop [i  0
                 bs (partition-all 32
                                   (concat (child-seq n1 shift cnt1)
                                           (child-seq n2 shift cnt2)))]
            (when-first [block bs]
              (let [a (make-array 33)
                    r (make-array 33)]
                (aset a 32 r)
                (aset r 32 (count block))
                (loop [i 0 o 0 gcs (seq block)]
                  (when-first [[gc gcr] gcs]
                    (aset a i gc)
                    (aset r i (+ o gcr))
                    (recur (inc i) (+ o gcr) (next gcs))))
                (aset new-arr i (->VectorNode nil a))
                (aset new-rngs i
                      (+ (aget r (dec (aget r 32)))
                         (if (pos? i) (aget new-rngs (dec i)) 0)))
                (aset new-rngs 32 (inc i))
                (recur (inc i) (next bs)))))
          (aset new-arr 32 new-rngs)
          (set! (.-val transferred-leaves) cnt2)
          (array new-n1 nil))

        :else
        (let [new-arr1  (make-array 33)
              new-arr2  (make-array 33)
              new-rngs1 (make-array 33)
              new-rngs2 (make-array 33)
              new-n1    (->VectorNode nil new-arr1)
              new-n2    (->VectorNode nil new-arr2)]
          (loop [i  0
                 bs (partition-all 32
                                   (concat (child-seq n1 shift cnt1)
                                           (child-seq n2 shift cnt2)))]
            (when-first [block bs]
              (let [a (make-array 33)
                    r (make-array 33)]
                (aset a 32 r)
                (aset r 32 (count block))
                (loop [i 0 o 0 gcs (seq block)]
                  (when-first [[gc gcr] gcs]
                    (aset a i gc)
                    (aset r i (+ o gcr))
                    (recur (inc i) (+ o gcr) (next gcs))))
                (if (and (< i 32) (> (+ (* i 32) (count block)) sbc1))
                  (let [tbs (- (+ (* i 32) (count block)) sbc1)
                        li  (dec (aget r 32))
                        d   (if (>= tbs 32)
                              (aget r li)
                              (- (aget r li) (aget r (- li tbs))))]
                    (set! (.-val transferred-leaves)
                          (+ (.-val transferred-leaves) d))))
                (let [new-arr  (if (< i 32) new-arr1 new-arr2)
                      new-rngs (if (< i 32) new-rngs1 new-rngs2)
                      i        (mod i 32)]
                  (aset new-arr i (->VectorNode nil a))
                  (aset new-rngs i
                        (+ (aget r (dec (aget r 32)))
                           (if (pos? i) (aget new-rngs (dec i)) 0)))
                  (aset new-rngs 32 (inc i)))
                (recur (inc i) (next bs)))))
          (aset new-arr1 32 new-rngs1)
          (aset new-arr2 32 new-rngs2)
          (array new-n1 new-n2))))))

(defn zippath
  [shift n1 cnt1 n2 cnt2 transferred-leaves]
  (if (== shift 5)
    (rebalance-leaves n1 cnt1 n2 cnt2 transferred-leaves)
    (let [c1 (last-child n1)
          c2 (first-child n2)
          ccnt1 (if (regular? n1)
                  (let [m (mod cnt1 (bit-shift-left 1 shift))]
                    (if (zero? m) (bit-shift-left 1 shift) m))
                  (let [rngs (ranges n1)
                        i    (dec (aget rngs 32))]
                    (if (zero? i)
                      (aget rngs 0)
                      (- (aget rngs i) (aget rngs (dec i))))))
          ccnt2 (if (regular? n2)
                  (let [m (mod cnt2 (bit-shift-left 1 shift))]
                    (if (zero? m) (bit-shift-left 1 shift) m))
                  (aget (ranges n2) 0))
          next-transferred-leaves (Box. 0)
          [new-c1 new-c2] (zippath (- shift 5) c1 ccnt1 c2 ccnt2
                                   next-transferred-leaves)
          d (.-val next-transferred-leaves)]
      (set! (.-val transferred-leaves) (+ (.-val transferred-leaves) d))
      (rebalance shift
                 (if (identical? c1 new-c1)
                   n1
                   (replace-rightmost-child shift n1 new-c1 d))
                 (+ cnt1 d)
                 (if new-c2
                   (if (identical? c2 new-c2)
                     n2
                     (replace-leftmost-child shift n2 cnt2 new-c2 d))
                   (remove-leftmost-child shift n2))
                 (- cnt2 d)
                 transferred-leaves))))

(defn squash-nodes [shift n1 cnt1 n2 cnt2]
  (let [arr1  (.-arr n1)
        arr2  (.-arr n2)
        li1   (index-of-nil arr1)
        li2   (index-of-nil arr2)
        slots (concat (take li1 arr1) (take li2 arr2))]
    (if (> (count slots) 32)
      (array n1 n2)
      (let [new-rngs (make-array 33)
            new-arr  (make-array 33)
            rngs1    (take li1 (if (regular? n1)
                                 (regular-ranges shift cnt1)
                                 (ranges n1)))
            rngs2    (take li2 (if (regular? n2)
                                 (regular-ranges shift cnt2)
                                 (ranges n2)))
            rngs2    (let [r (last rngs1)]
                       (map #(+ % r) rngs2))
            rngs     (concat rngs1 rngs2)]
        (aset new-arr 32 new-rngs)
        (loop [i 0 cs (seq slots)]
          (when cs
            (aset new-arr i (first cs))
            (recur (inc i) (next cs))))
        (loop [i 0 rngs (seq rngs)]
          (if rngs
            (do (aset new-rngs i (first rngs))
                (recur (inc i) (next rngs)))
            (aset new-rngs 32 i)))
        (array (->VectorNode nil new-arr) nil)))))

(defn splice-rrbts [v1 v2]
  (cond
    (zero? (count v1)) v2
    (< (count v2) rrbt-concat-threshold) (into v1 v2)
    :else
    (let [s1 (.-shift v1)
          s2 (.-shift v2)
          r1 (.-root v1)
          o? (overflow? r1 s1 (+ (count v1) (- 32 (alength (.-tail v1)))))
          r1 (if o?
               (let [tail      (.-tail v1)
                     tail-node (->VectorNode nil tail)
                     reg?      (and (regular? r1) (== (alength tail) 32))
                     arr       (make-array (if reg? 32 33))]
                 (aset arr 0 r1)
                 (aset arr 1 (new-path* s1 tail-node))
                 (if-not reg?
                   (let [rngs (make-array 33)]
                     (aset rngs 32 2)
                     (aset rngs 0 (- (count v1) (alength tail)))
                     (aset rngs 1 (count v1))
                     (aset arr 32 rngs)))
                 (->VectorNode nil arr))
               (fold-tail r1 s1
                          (tail-offset (.-cnt v1) (.-tail v1))
                          (.-tail v1)))
          s1 (if o? (+ s1 5) s1)
          r2 (.-root v2)
          s  (max s1 s2)
          r1 (shift-from-to r1 s1 s)
          r2 (shift-from-to r2 s2 s)
          transferred-leaves (Box. 0)
          [n1 n2] (zippath s
                           r1 (count v1)
                           r2 (- (count v2) (alength (.-tail v2)))
                           transferred-leaves)
          d (.-val transferred-leaves)
          ncnt1   (+ (count v1) d)
          ncnt2   (- (count v2) (alength (.-tail v2)) d)
          [n1 n2] (if (identical? n2 r2)
                    (squash-nodes s n1 ncnt1 n2 ncnt2)
                    (array n1 n2))
          ncnt1   (if n2
                    ncnt1
                    (+ ncnt1 ncnt2))
          ncnt2   (if n2
                    ncnt2
                    0)]
      (if n2
        (let [arr      (make-array 33)
              new-root (->VectorNode nil arr)]
          (aset arr 0 n1)
          (aset arr 1 n2)
          (aset arr 32 (doto (make-array 33)
                         (aset 0 ncnt1)
                         (aset 1 (+ ncnt1 ncnt2))
                         (aset 32 2)))
          (Vector. (+ (count v1) (count v2)) (+ s 5) new-root (.-tail v2)
                   nil nil))
        (loop [r n1
               s s]
          (if (and (> s 5)
                   (nil? (aget (.-arr r) 1)))
            (recur (aget (.-arr r) 0) (- s 5))
            (Vector. (+ (count v1) (count v2)) s r (.-tail v2)
                     nil nil)))))))

(deftype Transient [^:mutable cnt
                    ^:mutable shift
                    ^:mutable root
                    ^:mutable tail
                    ^:mutable tidx]
  ITransientCollection
  (-conj! [this o]
    (if ^boolean (.-edit root)
      (if (< tidx 32)
        (do (aset tail tidx o)
            (set! cnt  (inc cnt))
            (set! tidx (inc tidx))
            this)
        (let [tail-node (->VectorNode (.-edit root) tail)
              new-tail  (make-array 32)]
          (aset new-tail 0 o)
          (set! tail new-tail)
          (set! tidx 1)
          (if (overflow? root shift cnt)
            (if (regular? root)
              (let [new-arr (make-array 32)]
                (doto new-arr
                  (aset 0 root)
                  (aset 1 (new-path tail (.-edit root) shift tail-node)))
                (set! root  (->VectorNode (.-edit root) new-arr))
                (set! shift (+ shift 5))
                (set! cnt   (inc cnt))
                this)
              (let [new-arr  (make-array 33)
                    new-rngs (make-array 33)
                    new-root (->VectorNode (.-edit root) new-arr)
                    root-total-range (aget (ranges root) 31)]
                (doto new-arr
                  (aset 0  root)
                  (aset 1  (new-path tail (.-edit root) shift tail-node))
                  (aset 32 new-rngs))
                (doto new-rngs
                  (aset 0  root-total-range)
                  (aset 1  (+ root-total-range 32))
                  (aset 32 2))
                (set! root  new-root)
                (set! shift (+ shift 5))
                (set! cnt   (inc cnt))
                this))
            (let [new-root (push-tail! shift cnt (.-edit root) root tail-node)]
              (set! root new-root)
              (set! cnt  (inc cnt))
              this))))
      (throw (js/Error. "conj! after persistent!"))))

  (-persistent! [this]
    (if ^boolean (.-edit root)
      (do (set! (.-edit root) nil)
          (let [trimmed-tail (make-array tidx)]
            (array-copy tail 0 trimmed-tail 0 tidx)
            (Vector. cnt shift root trimmed-tail nil nil)))
      (throw (js/Error. "persistent! called twice"))))

  ITransientAssociative
  (-assoc! [this key val]
    (-assoc-n! this key val))

  ITransientVector
  (-assoc-n! [this i val]
    (if ^boolean (.-edit root)
      (cond
        (and (<= 0 i) (< i cnt))
        (let [tail-off (- cnt tidx)]
          (if (<= tail-off i)
            (aset tail (- i tail-off) val)
            (set! root (do-assoc! shift (.-edit root) root i val)))
          this)

        (== i cnt) (-conj! this val)

        :else (vector-index-out-of-bounds i cnt))
      (throw (js/Error. "assoc! after persistent!"))))

  (-pop! [this]
    (if ^boolean (.-edit root)
      (cond
        (zero? cnt)
        (throw (js/Error. "Can't pop empty vector"))

        (== 1 cnt)
        (do (set! cnt  0)
            (set! tidx 0)
            (aset tail 0 nil)
            this)

        (> tidx 1)
        (do (set! cnt  (dec cnt))
            (set! tidx (dec tidx))
            (aset tail tidx nil)
            this)

        :else
        (let [new-tail-base (array-for cnt shift root tail (- cnt 2))
              new-tail      (aclone new-tail-base)
              new-tidx      (alength new-tail-base)
              new-root      (pop-tail! shift cnt (.-edit root) root)]
          (cond
            (nil? new-root)
            (do (set! cnt  (dec cnt))
                (set! root (ensure-editable (.-edit root) empty-node))
                (set! tail new-tail)
                (set! tidx new-tidx)
                this)

            (and (> shift 5)
                 (nil? (aget (.-arr new-root) 1)))
            (do (set! cnt   (dec cnt))
                (set! shift (- shift 5))
                (set! root  (aget (.-arr new-root) 0))
                (set! tail  new-tail)
                (set! tidx  new-tidx)
                this)

            :else
            (do (set! cnt  (dec cnt))
                (set! root new-root)
                (set! tail new-tail)
                (set! tidx new-tidx)
                this))))
      (throw (js/Error. "count after persistent!"))))

  ICounted
  (-count [this]
    (if ^boolean (.-edit root)
      cnt
      (throw (js/Error. "count after persistent!")))))




© 2015 - 2025 Weber Informatics LLC | Privacy Policy