Skip to content
This repository has been archived by the owner on Nov 9, 2017. It is now read-only.

Commit

Permalink
use collection-check, and mark 0.1.3
Browse files Browse the repository at this point in the history
  • Loading branch information
ztellman committed Oct 29, 2013
1 parent bd3673f commit 305601d
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 87 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ A tuple behaves exactly like a Clojure vector. However, compared lists and vect
## Usage

```clj
[clj-tuple "0.1.2"]
[clj-tuple "0.1.3"]
```

```clj
Expand Down
4 changes: 2 additions & 2 deletions project.clj
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
(defproject clj-tuple "0.1.3-SNAPSHOT"
(defproject clj-tuple "0.1.3"
:description "Efficient small collections."
:license {:name "MIT License"
:url "http://opensource.org/licenses/MIT"}
:dependencies []
:profiles {:dev {:dependencies [[org.clojure/clojure "1.5.1"]
[criterium "0.4.1"]
[reiddraper/simple-check "0.2.1"]]}}
[collection-check "0.1.0"]]}}
:global-vars {*warn-on-reflection* true}
:test-selectors {:benchmark :benchmark
:default (complement :benchmark)}
Expand Down
117 changes: 57 additions & 60 deletions src/clj_tuple.clj
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
(:import
[clojure.lang
Util
IMapEntry]
IMapEntry
MapEntry]
[java.util
List
Map$Entry
Iterator
Collection]))
Expand Down Expand Up @@ -50,30 +52,12 @@
(let [gensym* (memoize gensym)]
(postwalk
#(if (unified-gensym? %)
(symbol (str (gensym* (str (un-gensym %) "__")) "__auto__"))
(symbol (str (gensym* (str (un-gensym %) "__")) "__unified__"))
%)
body)))

;;;

(defn map-entry [k v]
(reify
IMapEntry
Map$Entry

(key [_] k)
(getKey [_] k)

(val [_] v)
(getValue [_] v)

(hashCode [_]
(bit-xor (Util/hash k) (Util/hash v)))
(equals [_ x]
(and (instance? Map$Entry x)
(Util/equals k (.getKey ^Map$Entry x))
(Util/equals v (.getValue ^Map$Entry x))))))

(declare conj-tuple tuple)

(defn- throw-arity [actual]
Expand Down Expand Up @@ -145,6 +129,14 @@
(val [_] ~(second fields))
(getValue [_] ~(second fields))))

clojure.lang.IEditableCollection
(asTransient [_]
(-> []
transient
~@(map
(fn [x] `(conj! ~x))
fields)))

clojure.lang.Associative
clojure.lang.IPersistentVector
(count [_] ~cardinality)
Expand All @@ -158,24 +150,24 @@
(<= 0 k## ~(dec cardinality)))))
(entryAt [_ k##]
(let [v# ~(lookup `(int k##))]
(map-entry k## v#)))
(MapEntry. k## v#)))
(assoc [this# k# v##]
(case (int k#)
~@(mapcat
(fn [idx field]
`(~idx (new ~name ~@(-> fields vec (assoc idx `v##)) `mta##)))
`(~idx (new ~name ~@(-> fields vec (assoc idx `v##)) mta##)))
(range)
fields)
~cardinality (.cons this# v##)
~cardinality (conj-tuple this# v##)
(throw (IndexOutOfBoundsException. (str k#)))))
(assocN [this# k# v##]
(case k#
~@(mapcat
(fn [idx field]
`(~idx (new ~name ~@(-> fields vec (assoc idx `v##)) `mta##)))
`(~idx (new ~name ~@(-> fields vec (assoc idx `v##)) mta##)))
(range)
fields)
~cardinality (.cons this# v##)
~cardinality (conj-tuple this# v##)
(throw (IndexOutOfBoundsException. (str k#)))))

java.util.Collection
Expand All @@ -197,13 +189,15 @@
clojure.lang.Sequential
clojure.lang.ISeq
clojure.lang.Seqable
java.util.List

(empty [_] (tuple))
(empty [_]
(tuple))
(first [_]
~(first fields))
(next [this##]
~(when (> cardinality 1)
`(new ~dec-name ~@(rest fields) nil)))
`(new ~dec-name ~@(rest fields) mta##)))
(more [this##]
(if-let [rst# (next this##)]
rst#
Expand All @@ -213,10 +207,11 @@
(peek [_]
~(last fields))
(pop [_]
~(when (> cardinality 1)
`(new ~dec-name ~@(butlast fields) nil)))
~(if (zero? cardinality)
`(throw (IllegalArgumentException. "Cannot pop from an empty vector."))
`(new ~dec-name ~@(butlast fields) mta##)))
(rseq [_]
(new ~name ~@(reverse fields) nil))
(new ~name ~@(reverse fields) mta##))
(seq [this##]
~(when-not (zero? cardinality)
`this##))
Expand All @@ -225,6 +220,8 @@
~(lookup `idx## `not-found##))
(nth [_ idx##]
~(lookup `idx##))
(get [_ idx##]
~(lookup `idx##))

(equiv [this# x##]
(if (instance? ~name x##)
Expand Down Expand Up @@ -300,34 +297,32 @@
1
fields))))

p/InternalReduce
(internal-reduce [_ f## start##]
~(if (zero? cardinality)
`(f## start##)
(reduce
(fn [form field]
`(f## ~form ~field))
`start##
fields)))

p/CollReduce
(coll-reduce [_ f##]
~(if (zero? cardinality)
`(f##)
(reduce
(fn [form field]
`(f## ~form ~field))
(first fields)
(rest fields))))
(coll-reduce [_ f## start##]
~(if (zero? cardinality)
`(f## start##)
(reduce
(fn [form field]
`(f## ~form ~field))
`start##
fields)))

~@(let [reduce-form (fn [val elements]
`(let [x## ~val]
~(reduce
(fn [form field]
`(let [x## (f## x## ~field)]
(if (reduced? x##)
@x##
~form)))
`x##
(reverse elements))))]
`(p/InternalReduce
(internal-reduce [_ f## start##]
~(if (zero? cardinality)
`start##
(reduce-form `start## fields)))

p/CollReduce
(coll-reduce [_ f##]
~(if (zero? cardinality)
`(f##)
(reduce-form (first fields) (rest fields))))
(coll-reduce [_ f## start##]
~(if (zero? cardinality)
`start##
(reduce-form `start## fields)))))

(toString [_]
(str "[" ~@(->> fields (map (fn [f] `(pr-str ~f))) (interpose " ")) "]")))

Expand Down Expand Up @@ -356,9 +351,11 @@
(fn [n] `(. ~(with-meta `t## {:tag (str "Tuple" idx)}) ~(symbol (str "e" n))))
(range idx))
x##
nil))))
(meta t##)))))
(range 6))
6 (conj (clojure.lang.PersistentVector/create ^clojure.lang.ISeq t##) x##)
6 (with-meta
(conj (clojure.lang.PersistentVector/create (seq t##)) x##)
(meta t##))
)))))

(defn tuple
Expand Down
28 changes: 4 additions & 24 deletions test/clj_tuple_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,17 @@
(:require
[clojure.test :refer :all]
[clj-tuple :refer :all]
[criterium.core :as c])
[criterium.core :as c]
[collection-check :as check]
[simple-check.generators :as gen])
(:import
[java.util.concurrent
ConcurrentHashMap]
[java.util
HashMap]))

(defn equivalent? [a b]
(is (= a b))
(is (= b a))
(is (every? #(= (nth a %) (nth b %)) (range (count a))))
(when (instance? clojure.lang.PersistentVector a)
(when-not (empty? a)
(is (= (into (empty a) a) (into (empty b) b) a b)))
(is (every? #(= (a %) (b %)) (range (count a))))
(is (every? #(= (get a %) (get b %)) (range (inc (count a)))))
(is (= 0 (compare a b))))
(is (= (apply + b) (apply + a)))
(is (= (reduce + b) (reduce + a)))
(is (.equals ^Object a b) (str (class a) (class b)))
(is (.equals ^Object b a))
(is (= (hash a) (hash b)))
(is (= (first a) (first b)))
(when-not (empty? a)
(equivalent? (rest a) (rest b))))

(deftest test-equivalency
(let [seqs (map #(range %) (range 10))]
(doseq [s seqs]
(equivalent? (vec s) (apply tuple s))
(equivalent? (apply tuple s) (apply tuple s)))))
(check/assert-vector-like 1e4 (tuple) gen/int))

(defmacro do-benchmark [description bench-form-fn]
(let [bench-form-fn (eval bench-form-fn)]
Expand Down

0 comments on commit 305601d

Please sign in to comment.