Switch branches/tags
clojure-1.9.0 clojure-1.9.0-beta4 clojure-1.9.0-beta3 clojure-1.9.0-beta2 clojure-1.9.0-beta1 clojure-1.9.0-alpha20 clojure-1.9.0-alpha19 clojure-1.9.0-alpha18 clojure-1.9.0-alpha17 clojure-1.9.0-alpha16 clojure-1.9.0-alpha15 clojure-1.9.0-alpha14 clojure-1.9.0-alpha13 clojure-1.9.0-alpha12 clojure-1.9.0-alpha11 clojure-1.9.0-alpha10 clojure-1.9.0-alpha9 clojure-1.9.0-alpha8 clojure-1.9.0-alpha7 clojure-1.9.0-alpha6 clojure-1.9.0-alpha5 clojure-1.9.0-alpha4 clojure-1.9.0-alpha3 clojure-1.9.0-alpha2 clojure-1.9.0-alpha1 clojure-1.9.0-RC2 clojure-1.9.0-RC1 clojure-1.8.0 clojure-1.8.0-beta2 clojure-1.8.0-beta1 clojure-1.8.0-alpha5 clojure-1.8.0-alpha4 clojure-1.8.0-alpha3 clojure-1.8.0-alpha2 clojure-1.8.0-alpha1 clojure-1.8.0-RC5 clojure-1.8.0-RC4 clojure-1.8.0-RC3 clojure-1.8.0-RC2 clojure-1.8.0-RC1 clojure-1.7.0 clojure-1.7.0-beta3 clojure-1.7.0-beta2 clojure-1.7.0-beta1 clojure-1.7.0-alpha6 clojure-1.7.0-alpha5 clojure-1.7.0-alpha4 clojure-1.7.0-alpha3 clojure-1.7.0-alpha2 clojure-1.7.0-alpha1 clojure-1.7.0-RC2 clojure-1.7.0-RC1 clojure-1.6.0 clojure-1.6.0-beta2 clojure-1.6.0-beta1 clojure-1.6.0-alpha3 clojure-1.6.0-alpha2 clojure-1.6.0-alpha1 clojure-1.6.0-RC4 clojure-1.6.0-RC3 clojure-1.6.0-RC2 clojure-1.6.0-RC1 clojure-1.5.1 clojure-1.5.0 clojure-1.5.0-beta13 clojure-1.5.0-beta12 clojure-1.5.0-beta11 clojure-1.5.0-beta10 clojure-1.5.0-beta9 clojure-1.5.0-beta8 clojure-1.5.0-beta7 clojure-1.5.0-beta2 clojure-1.5.0-beta1 clojure-1.5.0-alpha7 clojure-1.5.0-alpha6 clojure-1.5.0-alpha5 clojure-1.5.0-alpha4 clojure-1.5.0-alpha3 clojure-1.5.0-alpha2 clojure-1.5.0-alpha1 clojure-1.5.0-RC17 clojure-1.5.0-RC16 clojure-1.5.0-RC15 clojure-1.5.0-RC14 clojure-1.5.0-RC6 clojure-1.5.0-RC5 clojure-1.5.0-RC4 clojure-1.5.0-RC3 clojure-1.5.0-RC2 clojure-1.5.0-RC1 clojure-1.4.0 clojure-1.4.0-beta7 clojure-1.4.0-beta6 clojure-1.4.0-beta5 clojure-1.4.0-beta4 clojure-1.4.0-beta3 clojure-1.4.0-beta2 clojure-1.4.0-beta1 clojure-1.4.0-alpha5 clojure-1.4.0-alpha4
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
528 lines (471 sloc) 17.5 KB
; Copyright (c) Rich Hickey. All rights reserved.
; The use and distribution terms for this software are covered by the
; Eclipse Public License 1.0 (
; which can be found in the file epl-v10.html at the root of this distribution.
; By using this software in any fashion, you are agreeing to be bound by
; the terms of this license.
; You must not remove this notice, or any other, from this software.
;;; a generic vector implementation for vectors of primitives
(in-ns 'clojure.core)
(import '(clojure.lang Murmur3))
(set! *warn-on-reflection* true)
(deftype VecNode [edit arr])
(def EMPTY-NODE (VecNode. nil (object-array 32)))
(definterface IVecImpl
(^int tailoff [])
(arrayFor [^int i])
(pushTail [^int level ^clojure.core.VecNode parent ^clojure.core.VecNode tailnode])
(popTail [^int level node])
(newPath [edit ^int level node])
(doAssoc [^int level node ^int i val]))
(definterface ArrayManager
(array [^int size])
(^int alength [arr])
(aclone [arr])
(aget [arr ^int i])
(aset [arr ^int i val]))
(deftype ArrayChunk [^clojure.core.ArrayManager am arr ^int off ^int end]
(nth [_ i] (.aget am arr (+ off i)))
(count [_] (- end off))
(dropFirst [_]
(if (= off end)
(throw (IllegalStateException. "dropFirst of empty chunk"))
(new ArrayChunk am arr (inc off) end)))
(reduce [_ f init]
(loop [ret init i off]
(if (< i end)
(let [ret (f ret (.aget am arr i))]
(if (reduced? ret)
(recur ret (inc i))))
(deftype VecSeq [^clojure.core.ArrayManager am ^clojure.core.IVecImpl vec anode ^int i ^int offset]
:no-print true
[_ f val]
(loop [result val
aidx (+ i offset)]
(if (< aidx (count vec))
(let [node (.arrayFor vec aidx)
result (loop [result result
node-idx (bit-and 0x1f aidx)]
(if (< node-idx (.alength am node))
(let [result (f result (.aget am node node-idx))]
(if (reduced? result)
(recur result (inc node-idx))))
(if (reduced? result)
(recur result (bit-and 0xffe0 (+ aidx 32)))))
(first [_] (.aget am anode offset))
(next [this]
(if (< (inc offset) (.alength am anode))
(new VecSeq am vec anode i (inc offset))
(.chunkedNext this)))
(more [this]
(let [s (.next this)]
(or s (clojure.lang.PersistentList/EMPTY))))
(cons [this o]
(clojure.lang.Cons. o this))
(count [this]
(loop [i 1
s (next this)]
(if s
(if (instance? clojure.lang.Counted s)
(+ i (.count s))
(recur (inc i) (next s)))
(equiv [this o]
(identical? this o) true
(or (instance? clojure.lang.Sequential o) (instance? java.util.List o))
(loop [me this
you (seq o)]
(if (nil? me)
(nil? you)
(and (clojure.lang.Util/equiv (first me) (first you))
(recur (next me) (next you)))))
:else false))
(empty [_]
(seq [this] this)
(chunkedFirst [_] (ArrayChunk. am anode offset (.alength am anode)))
(chunkedNext [_]
(let [nexti (+ i (.alength am anode))]
(when (< nexti (count vec))
(new VecSeq am vec (.arrayFor vec nexti) nexti 0))))
(chunkedMore [this]
(let [s (.chunkedNext this)]
(or s (clojure.lang.PersistentList/EMPTY)))))
(defmethod print-method ::VecSeq [v w]
((get (methods print-method) clojure.lang.ISeq) v w))
(deftype Vec [^clojure.core.ArrayManager am ^int cnt ^int shift ^clojure.core.VecNode root tail _meta]
(equals [this o]
(identical? this o) true
(or (instance? clojure.lang.IPersistentVector o) (instance? java.util.RandomAccess o))
(and (= cnt (count o))
(loop [i (int 0)]
(= i cnt) true
(.equals (.nth this i) (nth o i)) (recur (inc i))
:else false)))
(or (instance? clojure.lang.Sequential o) (instance? java.util.List o))
(if-let [st (seq this)]
(.equals st (seq o))
(nil? (seq o)))
:else false))
;todo - cache
(hashCode [this]
(loop [hash (int 1) i (int 0)]
(if (= i cnt)
(let [val (.nth this i)]
(recur (unchecked-add-int (unchecked-multiply-int 31 hash)
(clojure.lang.Util/hash val))
(inc i))))))
;todo - cache
(hasheq [this]
(Murmur3/hashOrdered this))
(count [_] cnt)
(meta [_] _meta)
(withMeta [_ m] (new Vec am cnt shift root tail m))
(nth [this i]
(let [a (.arrayFor this i)]
(.aget am a (bit-and i (int 0x1f)))))
(nth [this i not-found]
(let [z (int 0)]
(if (and (>= i z) (< i (.count this)))
(.nth this i)
(cons [this val]
(if (< (- cnt (.tailoff this)) (int 32))
(let [new-tail (.array am (inc (.alength am tail)))]
(System/arraycopy tail 0 new-tail 0 (.alength am tail))
(.aset am new-tail (.alength am tail) val)
(new Vec am (inc cnt) shift root new-tail (meta this)))
(let [tail-node (VecNode. (.edit root) tail)]
(if (> (bit-shift-right cnt (int 5)) (bit-shift-left (int 1) shift)) ;overflow root?
(let [new-root (VecNode. (.edit root) (object-array 32))]
(doto ^objects (.arr new-root)
(aset 0 root)
(aset 1 (.newPath this (.edit root) shift tail-node)))
(new Vec am (inc cnt) (+ shift (int 5)) new-root (let [tl (.array am 1)] (.aset am tl 0 val) tl) (meta this)))
(new Vec am (inc cnt) shift (.pushTail this shift root tail-node)
(let [tl (.array am 1)] (.aset am tl 0 val) tl) (meta this))))))
(empty [_] (new Vec am 0 5 EMPTY-NODE (.array am 0) nil))
(equiv [this o]
(or (instance? clojure.lang.IPersistentVector o) (instance? java.util.RandomAccess o))
(and (= cnt (count o))
(loop [i (int 0)]
(= i cnt) true
(= (.nth this i) (nth o i)) (recur (inc i))
:else false)))
(or (instance? clojure.lang.Sequential o) (instance? java.util.List o))
(clojure.lang.Util/equiv (seq this) (seq o))
:else false))
(peek [this]
(when (> cnt (int 0))
(.nth this (dec cnt))))
(pop [this]
(zero? cnt)
(throw (IllegalStateException. "Can't pop empty vector"))
(= 1 cnt)
(new Vec am 0 5 EMPTY-NODE (.array am 0) (meta this))
(> (- cnt (.tailoff this)) 1)
(let [new-tail (.array am (dec (.alength am tail)))]
(System/arraycopy tail 0 new-tail 0 (.alength am new-tail))
(new Vec am (dec cnt) shift root new-tail (meta this)))
(let [new-tail (.arrayFor this (- cnt 2))
new-root ^clojure.core.VecNode (.popTail this shift root)]
(nil? new-root)
(new Vec am (dec cnt) shift EMPTY-NODE new-tail (meta this))
(and (> shift 5) (nil? (aget ^objects (.arr new-root) 1)))
(new Vec am (dec cnt) (- shift 5) (aget ^objects (.arr new-root) 0) new-tail (meta this))
(new Vec am (dec cnt) shift new-root new-tail (meta this))))))
(assocN [this i val]
(and (<= (int 0) i) (< i cnt))
(if (>= i (.tailoff this))
(let [new-tail (.array am (.alength am tail))]
(System/arraycopy tail 0 new-tail 0 (.alength am tail))
(.aset am new-tail (bit-and i (int 0x1f)) val)
(new Vec am cnt shift root new-tail (meta this)))
(new Vec am cnt shift (.doAssoc this shift root i val) tail (meta this)))
(= i cnt) (.cons this val)
:else (throw (IndexOutOfBoundsException.))))
(length [_] cnt)
(rseq [this]
(if (> (.count this) 0)
(clojure.lang.APersistentVector$RSeq. this (dec (.count this)))
(assoc [this k v]
(if (clojure.lang.Util/isInteger k)
(.assocN this k v)
(throw (IllegalArgumentException. "Key must be integer"))))
(containsKey [this k]
(and (clojure.lang.Util/isInteger k)
(<= 0 (int k))
(< (int k) cnt)))
(entryAt [this k]
(if (.containsKey this k)
(clojure.lang.MapEntry/create k (.nth this (int k)))
(valAt [this k not-found]
(if (clojure.lang.Util/isInteger k)
(let [i (int k)]
(if (and (>= i 0) (< i cnt))
(.nth this i)
(valAt [this k] (.valAt this k nil))
(invoke [this k]
(if (clojure.lang.Util/isInteger k)
(let [i (int k)]
(if (and (>= i 0) (< i cnt))
(.nth this i)
(throw (IndexOutOfBoundsException.))))
(throw (IllegalArgumentException. "Key must be integer"))))
(seq [this]
(if (zero? cnt)
(VecSeq. am this (.arrayFor this 0) 0 0)))
clojure.lang.Sequential ;marker, no methods
(tailoff [_]
(- cnt (.alength am tail)))
(arrayFor [this i]
(if (and (<= (int 0) i) (< i cnt))
(if (>= i (.tailoff this))
(loop [node root level shift]
(if (zero? level)
(.arr node)
(recur (aget ^objects (.arr node) (bit-and (bit-shift-right i level) (int 0x1f)))
(- level (int 5))))))
(throw (IndexOutOfBoundsException.))))
(pushTail [this level parent tailnode]
(let [subidx (bit-and (bit-shift-right (dec cnt) level) (int 0x1f))
parent ^clojure.core.VecNode parent
ret (VecNode. (.edit parent) (aclone ^objects (.arr parent)))
node-to-insert (if (= level (int 5))
(let [child (aget ^objects (.arr parent) subidx)]
(if child
(.pushTail this (- level (int 5)) child tailnode)
(.newPath this (.edit root) (- level (int 5)) tailnode))))]
(aset ^objects (.arr ret) subidx node-to-insert)
(popTail [this level node]
(let [node ^clojure.core.VecNode node
subidx (bit-and (bit-shift-right (- cnt (int 2)) level) (int 0x1f))]
(> level 5)
(let [new-child (.popTail this (- level 5) (aget ^objects (.arr node) subidx))]
(if (and (nil? new-child) (zero? subidx))
(let [arr (aclone ^objects (.arr node))]
(aset arr subidx new-child)
(VecNode. (.edit root) arr))))
(zero? subidx) nil
:else (let [arr (aclone ^objects (.arr node))]
(aset arr subidx nil)
(VecNode. (.edit root) arr)))))
(newPath [this edit ^int level node]
(if (zero? level)
(let [ret (VecNode. edit (object-array 32))]
(aset ^objects (.arr ret) 0 (.newPath this edit (- level (int 5)) node))
(doAssoc [this level node i val]
(let [node ^clojure.core.VecNode node]
(if (zero? level)
;on this branch, array will need val type
(let [arr (.aclone am (.arr node))]
(.aset am arr (bit-and i (int 0x1f)) val)
(VecNode. (.edit node) arr))
(let [arr (aclone ^objects (.arr node))
subidx (bit-and (bit-shift-right i level) (int 0x1f))]
(aset arr subidx (.doAssoc this (- level (int 5)) (aget arr subidx) i val))
(VecNode. (.edit node) arr)))))
(compareTo [this o]
(if (identical? this o)
(let [^clojure.lang.IPersistentVector v (cast clojure.lang.IPersistentVector o)
vcnt (.count v)]
(< cnt vcnt) -1
(> cnt vcnt) 1
(loop [i (int 0)]
(if (= i cnt)
(let [comp (clojure.lang.Util/compare (.nth this i) (.nth v i))]
(if (= 0 comp)
(recur (inc i))
(iterator [this]
(let [i (java.util.concurrent.atomic.AtomicInteger. 0)]
(reify java.util.Iterator
(hasNext [_] (< (.get i) cnt))
(next [_] (try
(.nth this (dec (.incrementAndGet i)))
(catch IndexOutOfBoundsException _
(throw (java.util.NoSuchElementException.)))))
(remove [_] (throw (UnsupportedOperationException.))))))
(contains [this o] (boolean (some #(= % o) this)))
(containsAll [this c] (every? #(.contains this %) c))
(isEmpty [_] (zero? cnt))
(toArray [this] (into-array Object this))
(toArray [this arr]
(if (>= (count arr) cnt)
(dotimes [i cnt]
(aset arr i (.nth this i)))
(into-array Object this)))
(size [_] cnt)
(add [_ o] (throw (UnsupportedOperationException.)))
(addAll [_ c] (throw (UnsupportedOperationException.)))
(clear [_] (throw (UnsupportedOperationException.)))
(^boolean remove [_ o] (throw (UnsupportedOperationException.)))
(removeAll [_ c] (throw (UnsupportedOperationException.)))
(retainAll [_ c] (throw (UnsupportedOperationException.)))
(get [this i] (.nth this i))
(indexOf [this o]
(loop [i (int 0)]
(== i cnt) -1
(= o (.nth this i)) i
:else (recur (inc i)))))
(lastIndexOf [this o]
(loop [i (dec cnt)]
(< i 0) -1
(= o (.nth this i)) i
:else (recur (dec i)))))
(listIterator [this] (.listIterator this 0))
(listIterator [this i]
(let [i (java.util.concurrent.atomic.AtomicInteger. i)]
(reify java.util.ListIterator
(hasNext [_] (< (.get i) cnt))
(hasPrevious [_] (pos? i))
(next [_] (try
(.nth this (dec (.incrementAndGet i)))
(catch IndexOutOfBoundsException _
(throw (java.util.NoSuchElementException.)))))
(nextIndex [_] (.get i))
(previous [_] (try
(.nth this (.decrementAndGet i))
(catch IndexOutOfBoundsException _
(throw (java.util.NoSuchElementException.)))))
(previousIndex [_] (dec (.get i)))
(add [_ e] (throw (UnsupportedOperationException.)))
(remove [_] (throw (UnsupportedOperationException.)))
(set [_ e] (throw (UnsupportedOperationException.))))))
(subList [this a z] (subvec this a z))
(add [_ i o] (throw (UnsupportedOperationException.)))
(addAll [_ i c] (throw (UnsupportedOperationException.)))
(^Object remove [_ ^int i] (throw (UnsupportedOperationException.)))
(set [_ i e] (throw (UnsupportedOperationException.)))
(defmethod print-method ::Vec [v w]
((get (methods print-method) clojure.lang.IPersistentVector) v w))
(defmacro mk-am {:private true} [t]
(let [garr (gensym)
tgarr (with-meta garr {:tag (symbol (str t "s"))})]
`(reify clojure.core.ArrayManager
(array [_ size#] (~(symbol (str t "-array")) size#))
(alength [_ ~garr] (alength ~tgarr))
(aclone [_ ~garr] (aclone ~tgarr))
(aget [_ ~garr i#] (aget ~tgarr i#))
(aset [_ ~garr i# val#] (aset ~tgarr i# (~t val#))))))
(def ^{:private true} ams
{:int (mk-am int)
:long (mk-am long)
:float (mk-am float)
:double (mk-am double)
:byte (mk-am byte)
:short (mk-am short)
:char (mk-am char)
:boolean (mk-am boolean)})
(defmacro ^:private ams-check [t]
`(let [am# (ams ~t)]
(if am#
(throw (IllegalArgumentException. (str "Unrecognized type " ~t))))))
(defn vector-of
"Creates a new vector of a single primitive type t, where t is one
of :int :long :float :double :byte :short :char or :boolean. The
resulting vector complies with the interface of vectors in general,
but stores the values unboxed internally.
Optionally takes one or more elements to populate the vector."
{:added "1.2"
:arglists '([t] [t & elements])}
(let [^clojure.core.ArrayManager am (ams-check t)]
(Vec. am 0 5 EMPTY-NODE (.array am 0) nil)))
([t x1]
(let [^clojure.core.ArrayManager am (ams-check t)
arr (.array am 1)]
(.aset am arr 0 x1)
(Vec. am 1 5 EMPTY-NODE arr nil)))
([t x1 x2]
(let [^clojure.core.ArrayManager am (ams-check t)
arr (.array am 2)]
(.aset am arr 0 x1)
(.aset am arr 1 x2)
(Vec. am 2 5 EMPTY-NODE arr nil)))
([t x1 x2 x3]
(let [^clojure.core.ArrayManager am (ams-check t)
arr (.array am 3)]
(.aset am arr 0 x1)
(.aset am arr 1 x2)
(.aset am arr 2 x3)
(Vec. am 3 5 EMPTY-NODE arr nil)))
([t x1 x2 x3 x4]
(let [^clojure.core.ArrayManager am (ams-check t)
arr (.array am 4)]
(.aset am arr 0 x1)
(.aset am arr 1 x2)
(.aset am arr 2 x3)
(.aset am arr 3 x4)
(Vec. am 4 5 EMPTY-NODE arr nil)))
([t x1 x2 x3 x4 & xn]
(loop [v (vector-of t x1 x2 x3 x4)
xn xn]
(if xn
(recur (conj v (first xn)) (next xn))