├── .circleci └── config.yml ├── .github └── CODEOWNERS ├── .gitignore ├── CHANGELOG.md ├── ORIGINATOR ├── README.md ├── dev └── user.clj ├── project.clj ├── src ├── amalloy │ ├── ring_buffer.clj │ └── ring_buffer.cljs └── data_readers.clj └── test └── amalloy ├── ring_buffer_test.cljc └── runner.cljs /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | commands: 3 | setup-project: 4 | description: "Setup project" 5 | steps: 6 | - checkout 7 | 8 | # Download and cache dependencies 9 | - restore_cache: 10 | keys: 11 | - v1-dependencies-{{ checksum "project.clj" }} 12 | 13 | - run: 14 | name: Fetch dependencies 15 | command: | 16 | lein deps-all 17 | 18 | - save_cache: 19 | paths: 20 | - ~/.m2 21 | key: v1-dependencies-{{ checksum "project.clj" }} 22 | 23 | run-tests: 24 | description: "Run tests" 25 | steps: 26 | - run: 27 | name: Run JVM tests with clojure 1.8 28 | command: | 29 | lein with-profile +1.8 test 30 | - run: 31 | name: Run JVM tests with clojure 1.9 32 | command: | 33 | lein with-profile +1.9 test 34 | - run: 35 | name: Run JVM tests with clojure 1.10.0 36 | command: | 37 | lein with-profile +1.10.0 test 38 | - run: 39 | name: Run JVM tests with clojure 1.10.1 40 | command: | 41 | lein with-profile +1.10.1 test 42 | - run: 43 | name: Run nodejs tests 44 | command: | 45 | lein doo node node-test once 46 | 47 | jobs: 48 | 49 | openjdk-8: 50 | docker: 51 | - image: circleci/clojure:openjdk-8-lein-2.9.1-node 52 | working_directory: ~/repo 53 | 54 | environment: 55 | JVM_OPTS: -Xmx3200m 56 | 57 | steps: 58 | - setup-project 59 | - run-tests 60 | 61 | openjdk-11: 62 | docker: 63 | - image: circleci/clojure:openjdk-11-lein-2.9.1-node 64 | working_directory: ~/repo 65 | 66 | environment: 67 | JVM_OPTS: -Xmx3200m 68 | 69 | steps: 70 | - setup-project 71 | - run-tests 72 | 73 | workflows: 74 | version: 2 75 | default: 76 | jobs: 77 | - openjdk-8 78 | - openjdk-11 79 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @danielcompton 2 | * @BrunoBonacci 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /lib 3 | /classes 4 | /checkouts 5 | pom.xml 6 | pom.xml.asc 7 | *.jar 8 | *.class 9 | .lein-deps-sum 10 | .lein-failures 11 | .lein-plugins 12 | out/ 13 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## [Unreleased] 8 | 9 | ## 1.3.1 - 2019-12-01 10 | 11 | * Changed: Clojure and ClojureScript are now marked as `:scope "provided"` in project.clj 12 | 13 | ## 1.3.0 - 2018-12-15 14 | 15 | ### Added 16 | 17 | * Added support for `nth` lookups (also with negative indices) 18 | 19 | ## 1.2.2 - 2018-12-07 20 | 21 | ### Fixed 22 | 23 | * Fixed ambiguous Collection.toArray definition under Java 11 [#11](https://github.com/clj-commons/ring-buffer/pull/11) 24 | 25 | ## 1.2.1 - 2016-06-24 26 | 27 | ### Added 28 | 29 | * Added support for `rseq`/the `Reversible` interface. 30 | -------------------------------------------------------------------------------- /ORIGINATOR: -------------------------------------------------------------------------------- 1 | @amalloy 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ring-buffer 2 | [![Clojars Project](https://img.shields.io/clojars/v/amalloy/ring-buffer.svg)](https://clojars.org/amalloy/ring-buffer) 3 | [![cljdoc badge](https://cljdoc.org/badge/amalloy/ring-buffer)](https://cljdoc.org/d/amalloy/ring-buffer) 4 | [![CircleCI](https://circleci.com/gh/clj-commons/ring-buffer.svg?style=svg)](https://circleci.com/gh/clj-commons/ring-buffer) 5 | 6 | A persistent collection with semantics roughly equivalent to a ring 7 | buffer: acts like a queue, but has a predetermined maximum capacity; 8 | items added after that capacity is exceeded implicitly eject items 9 | from the front of the queue to make room. 10 | 11 | Implements all the relevant Clojure interfaces, but none of the java 12 | interop interfaces; pull requests welcome. 13 | 14 | Possible optimization: keep a reference to unused items until some new 15 | item overwrites it. This is easier and faster, but if you have a queue 16 | with very large objects (or a very large, mostly-empty queue), you may 17 | see memory leaks. The performance gain is probably not worth it, but I 18 | suppose that's a tradeoff some may not be willing to make. 19 | 20 | ## Usage 21 | 22 | Add the dependency into your `project.clj` 23 | 24 | ``` clojure 25 | [amalloy/ring-buffer "1.3.1"] 26 | ``` 27 | Latest version: [![Clojars Project](https://img.shields.io/clojars/v/amalloy/ring-buffer.svg)](https://clojars.org/amalloy/ring-buffer) 28 | 29 | See the [ring-buffer Clojars page](https://clojars.org/amalloy/ring-buffer) for Leiningen and Maven 30 | install snippets. 31 | 32 | Then require the namespace: 33 | 34 | ```clojure 35 | (ns your.ns 36 | (:require [amalloy.ring-buffer :refer :all])) 37 | ``` 38 | 39 | Finally add and remove items from the ring-buffer 40 | 41 | ```clojure 42 | ;; create a ring-buffer of given capacity 43 | (ring-buffer 3) 44 | ;; => #amalloy/ring-buffer [3 ()] 45 | 46 | ;; add one item to a empty ring-buffer 47 | (conj (ring-buffer 3) 'a) 48 | ;; => #amalloy/ring-buffer [3 (a)] 49 | 50 | ;; add multiple items at once 51 | (into (ring-buffer 3) '(a b)) 52 | ;; => #amalloy/ring-buffer [3 (a b)] 53 | 54 | ;; if you go beyond the ring-buffer capacity 55 | ;; the oldest elements are evicted 56 | (into (ring-buffer 3) '(a b c d e)) 57 | ;; => #amalloy/ring-buffer [3 (c d e)] 58 | 59 | ;; remove the first element from the buffer 60 | (pop (into (ring-buffer 3) '(a b c d e))) 61 | ;; => #amalloy/ring-buffer [3 (d e)] 62 | 63 | ;; retrieve the first element from the buffer 64 | (peek (into (ring-buffer 3) '(a b c d e))) 65 | ;; => c 66 | 67 | ;; alternatively use `first` and `last` 68 | (first (into (ring-buffer 3) '(a b c d e))) 69 | ;; => c 70 | (last (into (ring-buffer 3) '(a b c d e))) 71 | ;; => e 72 | 73 | ;; Lookup a specific index with `nth` 74 | (nth (into (ring-buffer 3) '(a b c)) 1) 75 | ;; => b 76 | 77 | ;; `nth` suports negative indices to lookup 78 | ;; from the end (`-1` -> last element) 79 | ;; and it also wraps around 80 | (nth (into (ring-buffer 3) '(a b c)) -1) 81 | ;; => c 82 | (nth (into (ring-buffer 3) '(a b c)) 7) 83 | ;; => b 84 | 85 | ;; `nth` suports default value which is used 86 | ;; when element isn't present or instead of 87 | ;; wrapping around 88 | (nth (into (ring-buffer 3) '(a b c)) 7 'z) 89 | ;; => z 90 | (nth (into (ring-buffer 3) '(a )) 2 'z) 91 | ;; => z 92 | 93 | ;; to obtain the content of the buffer 94 | ;; in insertion order (FIFO) use `seq`. 95 | ;; use `rseq` to obtain the content in 96 | ;; reverse order (LIFO). 97 | (seq (into (ring-buffer 3) '(a b c d e))) 98 | ;; => (c d e) 99 | (rseq (into (ring-buffer 3) '(a b c d e))) 100 | ;; => (e d c) 101 | ``` 102 | 103 | Note of performance characteristics: 104 | 105 | - `conj`, `pop`, `peek`, `nth` are **O(1)** operations 106 | - `seq`, `rseq`, and all the operation which rely on sequence are 107 | **O(n)** where *n* is the size of the buffer 108 | - `into` with a sequence runs in **O(n)** where *n* is the size of 109 | the input sequence. 110 | 111 | 112 | ## Development 113 | 114 | ### Running tests 115 | 116 | The project uses [lein-doo](http://github.com/bensu/doo) to run cljs 117 | tests. So for example, if `phantomjs` is in the path, the tests can be 118 | run with: 119 | 120 | $ lein doo phantom test 121 | 122 | ## History 123 | 124 | ring-buffer was originally created by [Alan Malloy](https://github.com/amalloy). 125 | In December 2018 it was moved to CLJ Commons for continued maintenance. 126 | 127 | It could previously be found at [amalloy/ring-buffer](https://github.com/amalloy/ring-buffer). [clj-commons/ring-buffer](https://github.com/clj-commons/ring-buffer) is the canonical repository now. 128 | 129 | ## License 130 | 131 | Copyright © 2012 Alan Malloy 132 | 133 | Distributed under the Eclipse Public License, the same as Clojure. 134 | -------------------------------------------------------------------------------- /dev/user.clj: -------------------------------------------------------------------------------- 1 | (ns user 2 | (:require [amalloy.ring-buffer :refer :all])) 3 | 4 | ;; create a ring-buffer of given capacity 5 | (ring-buffer 3) 6 | ;; => #amalloy/ring-buffer [3 ()] 7 | 8 | ;; add one item to a empty ring-buffer 9 | (conj (ring-buffer 3) 'a) 10 | ;; => #amalloy/ring-buffer [3 (a)] 11 | 12 | ;; add multiple items at once 13 | (into (ring-buffer 3) '(a b)) 14 | ;; => #amalloy/ring-buffer [3 (a b)] 15 | 16 | ;; if you go beyond the ring-buffer capacity 17 | ;; the oldest elements are evicted 18 | (into (ring-buffer 3) '(a b c d e)) 19 | ;; => #amalloy/ring-buffer [3 (c d e)] 20 | 21 | ;; remove the first element from the buffer 22 | (pop (into (ring-buffer 3) '(a b c d e))) 23 | ;; => #amalloy/ring-buffer [3 (d e)] 24 | 25 | ;; retrieve the first element from the buffer 26 | (peek (into (ring-buffer 3) '(a b c d e))) 27 | ;; => c 28 | 29 | ;; alternatively use `first` and `last` 30 | (first (into (ring-buffer 3) '(a b c d e))) 31 | ;; => c 32 | (last (into (ring-buffer 3) '(a b c d e))) 33 | ;; => e 34 | 35 | ;; Lookup a specific index with `nth` 36 | (nth (into (ring-buffer 3) '(a b c)) 1) 37 | ;; => b 38 | 39 | ;; `nth` suports negative indices to lookup 40 | ;; from the end (`-1` -> last element) 41 | ;; and it also wraps around 42 | (nth (into (ring-buffer 3) '(a b c)) -1) 43 | ;; => c 44 | (nth (into (ring-buffer 3) '(a b c)) 7) 45 | ;; => b 46 | 47 | ;; `nth` suports default value which is used 48 | ;; when element isn't present or instead of 49 | ;; wrapping around 50 | (nth (into (ring-buffer 3) '(a b c)) 7 'z) 51 | ;; => z 52 | (nth (into (ring-buffer 3) '(a )) 2 'z) 53 | ;; => z 54 | 55 | ;; to obtain the content of the buffer 56 | ;; in insertion order (FIFO) use `seq`. 57 | ;; use `rseq` to obtain the content in 58 | ;; reverse order (LIFO). 59 | (seq (into (ring-buffer 3) '(a b c d e))) 60 | ;; => (c d e) 61 | (rseq (into (ring-buffer 3) '(a b c d e))) 62 | ;; => (e d c) 63 | -------------------------------------------------------------------------------- /project.clj: -------------------------------------------------------------------------------- 1 | (defproject amalloy/ring-buffer "1.3.2-SNAPSHOT" 2 | :description "Persistent bounded-size queue implementation in Clojure" 3 | :url "https://github.com/clj-commons/ring-buffer" 4 | :license {:name "Eclipse Public License" 5 | :url "http://www.eclipse.org/legal/epl-v10.html"} 6 | :dependencies [[org.clojure/clojure "1.10.1" :scope "provided"] 7 | [org.clojure/clojurescript "1.10.520" :scope "provided"]] 8 | :plugins [[lein-cljsbuild "1.1.7"] 9 | [lein-doo "0.1.11"]] 10 | :deploy-repositories [["releases" :clojars] 11 | ["snapshots" :clojars]] 12 | :profiles {:1.8 {:dependencies [[org.clojure/clojure "1.8.0"] 13 | [org.clojure/clojurescript "1.8.51"]]} 14 | :1.9 {:dependencies [[org.clojure/clojure "1.9.0"] 15 | [org.clojure/clojurescript "1.9.946"]]} 16 | :1.10.0 {:dependencies [[org.clojure/clojure "1.10.0"] 17 | [org.clojure/clojurescript "1.10.520"]]} 18 | :1.10.1 {:dependencies [[org.clojure/clojure "1.10.1"] 19 | [org.clojure/clojurescript "1.10.520"]]}} 20 | :aliases {"test-all" ["with-profile" "+1.8:+1.9:+1.10.0:+1.10.1" "test"] 21 | "deps-all" ["with-profile" "+1.8:+1.9:+1.10.0:+1.10.1" "deps"]} 22 | :cljsbuild {:builds [{:id "node-test" 23 | :source-paths ["src" "test"] 24 | :compiler {:output-to "target/testable.js" 25 | :main amalloy.runner 26 | :target :nodejs 27 | :optimizations :none}}]}) 28 | -------------------------------------------------------------------------------- /src/amalloy/ring_buffer.clj: -------------------------------------------------------------------------------- 1 | (ns amalloy.ring-buffer 2 | (:import (clojure.lang Counted 3 | Sequential 4 | IPersistentCollection 5 | Indexed 6 | IPersistentStack 7 | Reversible 8 | IObj) 9 | (java.io Writer Serializable) 10 | (java.util Collection))) 11 | 12 | ;; If one of our numbers gets over 2 billion, the user's ring buffer is way too large! 13 | ;; and count is defined to return an int anyway, so we can't make it work regardless. 14 | ;; So we'll just skip that overflow check for a mild speed boost. 15 | (def ^:private old-unchecked-math *unchecked-math*) 16 | (set! *unchecked-math* true) 17 | 18 | (deftype RingBuffer [^long start ^long len buf meta] 19 | Serializable 20 | 21 | Counted 22 | (count [this] len) 23 | 24 | Sequential ;; tagging interface 25 | 26 | IObj 27 | (withMeta [this m] 28 | (RingBuffer. start len buf m)) 29 | (meta [this] meta) 30 | 31 | Object 32 | (toString [this] 33 | (pr-str (lazy-seq (seq this)))) 34 | 35 | IPersistentStack 36 | (peek [this] 37 | (nth buf (rem start (count buf)))) 38 | (pop [this] 39 | (if (zero? len) 40 | (throw (IllegalStateException. "Can't pop empty queue")) 41 | (RingBuffer. (rem (inc start) (count buf)) (dec len) (assoc buf start nil) meta))) 42 | (empty [this] 43 | (RingBuffer. 0 0 (vec (repeat (count buf) nil)) meta)) 44 | (equiv [this other] 45 | (and (sequential? other) 46 | (or (not (counted? other)) 47 | (= (count this) (count other))) 48 | (= (seq this) (seq other)))) 49 | 50 | IPersistentCollection 51 | (cons [this x] 52 | (if (= len (count buf)) 53 | (RingBuffer. (rem (inc start) len) len (assoc buf start x) meta) 54 | (RingBuffer. start (inc len) (assoc buf (rem (+ start len) (count buf)) x) meta))) 55 | (seq [this] 56 | (seq (for [i (range len)] 57 | (nth buf (rem (+ start i) (count buf)))))) 58 | 59 | Reversible 60 | (rseq [this] 61 | (seq (for [i (range (- len 1) -1 -1)] 62 | (nth buf (rem (+ start i) (count buf)))))) 63 | 64 | Collection 65 | (iterator [this] 66 | (.iterator ^Iterable (sequence this))) 67 | (contains [this e] 68 | (boolean (some #(= e %) (.seq this)))) 69 | (containsAll [this elts] 70 | (every? #(.contains this %) elts)) 71 | (size [this] 72 | (.count this)) 73 | (isEmpty [this] 74 | (empty? this)) 75 | (^objects toArray [this ^objects dest] 76 | (reduce (fn [idx item] 77 | (aset dest idx item) 78 | (inc idx)) 79 | 0, this) 80 | dest) 81 | (toArray [this] 82 | (.toArray this (object-array (.count this)))) 83 | 84 | Indexed 85 | (nth [this i] 86 | (nth buf (mod (+ start i) len))) 87 | (nth [this i default] 88 | (if (< (max i (- i)) len) 89 | (nth buf (mod (+ start i) len)) 90 | default))) 91 | 92 | (defmethod print-method RingBuffer [^RingBuffer b ^Writer w] 93 | (.write w "#amalloy/ring-buffer ") 94 | (print-method [(count (.buf b)) (sequence b)] w)) 95 | 96 | (defn- read-method [[capacity items]] 97 | (RingBuffer. 0 (count items) (vec (take capacity (concat items (repeat nil)))) nil)) 98 | 99 | (defn ring-buffer 100 | "Create an empty ring buffer with the specified [capacity]." 101 | [capacity] 102 | (RingBuffer. 0 0 (vec (repeat capacity nil)) nil)) 103 | 104 | (set! *unchecked-math* old-unchecked-math) 105 | -------------------------------------------------------------------------------- /src/amalloy/ring_buffer.cljs: -------------------------------------------------------------------------------- 1 | (ns amalloy.ring-buffer) 2 | 3 | ;; TODO: If one of our numbers gets over 2 billion, the user's ring buffer is way too large! 4 | ;; and count is defined to return an int anyway, so we can't make it work regardless. 5 | ;; So we'll just skip that overflow check for a mild speed boost. 6 | #_(def ^:private old-unchecked-math *unchecked-math*) 7 | #_(set! *unchecked-math* true) 8 | 9 | (deftype RingBuffer [start len buf meta] 10 | ICounted 11 | (-count [this] len) 12 | 13 | ISequential ;; tagging interface 14 | 15 | IWithMeta 16 | (-with-meta [this m] 17 | (RingBuffer. start len buf m)) 18 | 19 | IMeta 20 | (-meta [this] meta) 21 | 22 | IStack 23 | (-peek [this] 24 | (nth buf (rem start (count buf)))) 25 | (-pop [this] 26 | (if (zero? len) 27 | (throw (js/Error. "Can't pop empty queue")) 28 | (RingBuffer. (rem (inc start) (count buf)) (dec len) (assoc buf start nil) meta))) 29 | 30 | IEmptyableCollection 31 | (-empty [this] 32 | (RingBuffer. 0 0 (vec (repeat (count buf) nil)) meta)) 33 | 34 | IEquiv 35 | (-equiv [this other] 36 | (and (sequential? other) 37 | (or (not (counted? other)) 38 | (= (count this) (count other))) 39 | (= (seq this) (seq other)))) 40 | 41 | ICollection 42 | (-conj [this x] 43 | (if (= len (count buf)) 44 | (RingBuffer. (rem (inc start) len) len (assoc buf start x) meta) 45 | (RingBuffer. start (inc len) (assoc buf (rem (+ start len) (count buf)) x) meta))) 46 | 47 | ISeqable 48 | (-seq [this] 49 | (seq (for [i (range len)] 50 | (nth buf (rem (+ start i) (count buf)))))) 51 | 52 | IReversible 53 | (-rseq [this] 54 | (seq (for [i (range (- len 1) -1 -1)] 55 | (nth buf (rem (+ start i) (count buf)))))) 56 | 57 | IIndexed 58 | (-nth [this i] 59 | (nth buf (mod (+ start i) len))) 60 | (-nth [this i default] 61 | (if (< (max i (- i)) len) 62 | (nth buf (mod (+ start i) len)) 63 | default)) 64 | 65 | IPrintWithWriter 66 | (-pr-writer [b w opts] 67 | (-write w "(") 68 | (loop [b (seq b)] 69 | (when-let [[x & xs] b] 70 | (-write w x) 71 | (when xs 72 | (-write w " ") 73 | (recur xs)))) 74 | (-write w ")"))) 75 | 76 | 77 | 78 | 79 | 80 | (defn ring-buffer 81 | "Create an empty ring buffer with the specified [capacity]." 82 | [capacity] 83 | (RingBuffer. 0 0 (vec (repeat capacity nil)) nil)) 84 | 85 | #_(set! *unchecked-math* old-unchecked-math) 86 | -------------------------------------------------------------------------------- /src/data_readers.clj: -------------------------------------------------------------------------------- 1 | {amalloy/ring-buffer amalloy.ring-buffer/read-method} 2 | -------------------------------------------------------------------------------- /test/amalloy/ring_buffer_test.cljc: -------------------------------------------------------------------------------- 1 | (ns amalloy.ring-buffer-test 2 | (:require #?(:clj [clojure.test :refer :all] 3 | :cljs [cljs.test :refer-macros [deftest is]]) 4 | [amalloy.ring-buffer #?@(:clj [:refer :all] 5 | :cljs [:refer [ring-buffer]])]) 6 | #?(:clj 7 | (:import [java.io 8 | ByteArrayOutputStream 9 | ByteArrayInputStream 10 | ObjectOutputStream 11 | ObjectInputStream] 12 | [amalloy.ring_buffer RingBuffer]))) 13 | 14 | (deftest features 15 | (let [b (ring-buffer 3)] 16 | (is (= '(a b) (into b '(a b)))) 17 | (is (= '(c d e) (into b '(a b c d e)))) 18 | (is (= '(d e) (pop (into b '(a b c d e))))) 19 | (is (= 'c (peek (into b '(a b c d e))))) 20 | ;; nth 21 | (is (= 'a (nth (into b '(a b c)) 0))) 22 | (is (= 'b (nth (into b '(a b c)) 1))) 23 | (is (= 'c (nth (into b '(a b c)) 2))) 24 | (is (= 'a (nth (into b '(a b c)) 3))) ;; wrap 25 | (is (= 'a (nth (into b '(a b c)) 30))) ;; wrap 26 | ;; nth with negative idx 27 | (is (= 'c (nth (into b '(a b c)) -1))) 28 | (is (= 'a (nth (into b '(a b c)) -3))) 29 | (is (= 'a (nth (into b '(a b c)) -6))) 30 | ;; nth with default value 31 | (is (= 'a (nth (into b '(a b c)) 0 'z))) 32 | (is (= 'z (nth (into b '(a b)) 2 'z))) 33 | (is (= 'z (nth (into b '(a b c)) 10 'z))) 34 | (is (= 'z (nth (into b '(a b c)) -10 'z))))) 35 | 36 | #?(:clj 37 | (deftest test-serializable 38 | (let [^ByteArrayOutputStream baos (ByteArrayOutputStream.) 39 | ^ObjectOutputStream ois (ObjectOutputStream. baos) 40 | rb (-> (ring-buffer 5) 41 | (conj 1 2 3 4 5) 42 | (conj "one" "two" "three"))] 43 | (.writeObject ois rb) 44 | (let [^ObjectInputStream ois (-> baos 45 | .toByteArray 46 | ByteArrayInputStream. 47 | ObjectInputStream.) 48 | rb2 (.readObject ois)] 49 | (is (= rb rb2)))))) 50 | 51 | (deftest test-collection 52 | ;; Use a ring buffer that has wrapped to ensure we are 53 | ;; using proper offsets 54 | (let [rb (into (ring-buffer 4) [:gone1 :gone2 :one :two :three nil]) 55 | expected [:one :two :three nil]] 56 | #?(:clj (is (= expected (iterator-seq (.iterator rb))))) 57 | (is (some #(= :two %) rb)) 58 | (is (some #(= nil %) rb)) 59 | (is (not (first (filter #(= :gone1 %) rb)))) 60 | (is (= (set rb) (set expected))) 61 | (is (not (= (set rb) (set [:gone1 :gone2])))) 62 | (is (= 4 (count rb))) 63 | (is (empty? (ring-buffer 10))) 64 | (is (not (empty? rb))) 65 | (is (= (reverse expected) (rseq rb))) 66 | (is (= expected (seq (to-array rb)))))) 67 | -------------------------------------------------------------------------------- /test/amalloy/runner.cljs: -------------------------------------------------------------------------------- 1 | (ns amalloy.runner 2 | (:require [doo.runner :refer-macros [doo-tests]] 3 | [amalloy.ring-buffer-test])) 4 | 5 | (doo-tests 'amalloy.ring-buffer-test) 6 | --------------------------------------------------------------------------------