Skip to content

Instantly share code, notes, and snippets.

@matthewdowney
Created November 4, 2020 22:16
Show Gist options
  • Save matthewdowney/8adcff7ee58891ff17f16066e3ab6b1e to your computer and use it in GitHub Desktop.
Save matthewdowney/8adcff7ee58891ff17f16066e3ab6b1e to your computer and use it in GitHub Desktop.
(ns user.ring-buffer
"A fast, mutable ring buffer, backed by a fixed Java array.
Prefer https://github.com/clj-commons/ring-buffer unless you have very
specific needs."
(:require [taoensso.tufte :as tufte])
(:import (clojure.lang IDeref)))
(defprotocol ^:private Cursor (get-cursor! [this]))
(deftype ^:private RingBuffer [^:unsynchronized-mutable cursor size buf]
IDeref (deref [this] (vec buf))
Cursor (get-cursor! [this] (set! cursor (inc cursor))))
(defn ring-buffer
"Create a ring buffer of the given size.
Supports `deref` and `rb-conj!`."
[size]
(RingBuffer. -1 size (make-array Object size)))
(defn rb-conj!
"N.B. NOT thread safe.
Insert element `x` into the ring buffer `rb`.
Returns the element that `x` displaced, otherwise nil."
[^RingBuffer rb x]
(tufte/p :rb/insert
(let [cursor (get-cursor! rb)
index (rem cursor (.size rb))
^objects buf (.buf rb)
prev (aget buf index)]
(aset buf index ^Object x)
prev)))
(comment
(def b (ring-buffer 30))
(tufte/add-basic-println-handler! {})
(tufte/profile {} (dotimes [i 5e6] (rb-conj! b i)))
; Mean of 65 ns for insertion
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment