Skip to content

Commit

Permalink
Initial commit - draft of ring buffer
Browse files Browse the repository at this point in the history
  • Loading branch information
amalloy committed Jul 21, 2012
0 parents commit f2dfad9
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 0 deletions.
10 changes: 10 additions & 0 deletions .gitignore
@@ -0,0 +1,10 @@
/target
/lib
/classes
/checkouts
pom.xml
*.jar
*.class
.lein-deps-sum
.lein-failures
.lein-plugins
31 changes: 31 additions & 0 deletions README.md
@@ -0,0 +1,31 @@
# ring-buffer

A persistent collection with semantics roughly equivalent to a ring buffer: acts like a queue, but
has a predetermined maximum capacity; items added after that capacity is exceeded implicitly eject
items from the front of the queue to make room.

Implements all the relevant Clojure interfaces, but none of the java interop interfaces; pull
requests welcome.

Possible optimization: keep a reference to unused items until some new item overwrites it. This is
easier and faster, but if you have a queue with very large objects (or a very large, mostly-empty
queue), you may see memory leaks. The performance gain is probably not worth it, but I suppose

## Usage

```clojure
ring-buffer.core> (into (ring-buffer 3) '(a b))
(a b)
ring-buffer.core> (into (ring-buffer 3) '(a b c d e))
(c d e)
ring-buffer.core> (pop (into (ring-buffer 3) '(a b c d e)))
(d e)
ring-buffer.core> (peek (into (ring-buffer 3) '(a b c d e)))
c
```

## License

Copyright © 2012 Alan Malloy

Distributed under the Eclipse Public License, the same as Clojure.
3 changes: 3 additions & 0 deletions doc/intro.md
@@ -0,0 +1,3 @@
# Introduction to ring-buffer

TODO: write [great documentation](http://jacobian.org/writing/great-documentation/what-to-write/)
6 changes: 6 additions & 0 deletions project.clj
@@ -0,0 +1,6 @@
(defproject ring-buffer "0.1.0-SNAPSHOT"
:description "Persistent bounded-size queue implementation in Clojure"
:url "http://github.com/amalloy/ring-buffer"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.4.0"]])
57 changes: 57 additions & 0 deletions src/ring_buffer/core.clj
@@ -0,0 +1,57 @@
(ns ring-buffer.core
(:import (clojure.lang Counted Sequential IPersistentCollection IPersistentStack Reversible IObj)
(java.io Writer)))

(deftype RingBuffer [^int start ^int len buf meta]
Counted
(count [this] len)

Sequential ;; tagging interface

IObj
(withMeta [this m]
(RingBuffer. start len buf m))
(meta [this] meta)

Object
(toString [this]
(pr-str (lazy-seq (seq this))))

IPersistentStack
(peek [this]
(nth buf (mod start (count buf))))
(pop [this]
(if (zero? len)
(throw (IllegalStateException. "Can't pop empty queue"))
(RingBuffer. (mod (inc start) (count buf)) (dec len) (assoc buf start nil) meta)))
(empty [this]
(RingBuffer. 0 0 (vec (repeat (count buf) nil)) meta))
(equiv [this other]
(and (sequential? other)
(or (not (counted? other))
(= (count this) (count other)))
(= (seq this) (seq other))))

IPersistentCollection
(cons [this x]
(if (= len (count buf))
(RingBuffer. (mod (inc start) len) len (assoc buf start x) meta)
(RingBuffer. start (inc len) (assoc buf (mod (+ start len) (count buf)) x) meta)))
(seq [this]
(seq (for [i (range len)]
(nth buf (mod (+ start i) (count buf)))))))

(defmethod print-method RingBuffer [b ^Writer w]
(.write w "(")
(loop [b (seq b)]
(when-let [[x & xs] b]
(print-method x w)
(when xs
(.write w " ")
(recur xs))))
(.write w ")"))

(defn ring-buffer
"Create an empty ring buffer with the specified [capacity]."
[capacity]
(RingBuffer. 0 0 (vec (repeat capacity nil)) nil))
7 changes: 7 additions & 0 deletions test/ring_buffer/core_test.clj
@@ -0,0 +1,7 @@
(ns ring-buffer.core-test
(:use clojure.test
ring-buffer.core))

(deftest a-test
(testing "FIXME, I fail."
(is (= 0 1))))

0 comments on commit f2dfad9

Please sign in to comment.