diff --git a/README.md b/README.md index 8e78233..db93693 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ===== [![Build Status](https://travis-ci.org/eapache/queue.svg)](https://travis-ci.org/eapache/queue) -[![GoDoc](https://godoc.org/github.com/eapache/queue?status.png)](https://godoc.org/github.com/eapache/queue) +[![GoDoc](https://godoc.org/github.com/eapache/queue?status.svg)](https://godoc.org/github.com/eapache/queue) [![Code of Conduct](https://img.shields.io/badge/code%20of%20conduct-active-blue.svg)](https://eapache.github.io/conduct.html) A fast Golang queue using a ring-buffer, based on the version suggested by Dariusz Górecki. diff --git a/debian/changelog b/debian/changelog index f7a4c38..8af63df 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +golang-gopkg-eapache-queue.v1 (1.1.0+git20180227.1.093482f-1) UNRELEASED; urgency=low + + * New upstream snapshot. + + -- Debian Janitor Sun, 26 Sep 2021 06:11:13 -0000 + golang-gopkg-eapache-queue.v1 (1.0.2-5) unstable; urgency=medium [ Alexandre Viau ] diff --git a/queue.go b/queue.go index 2dc8d93..71d1acd 100644 --- a/queue.go +++ b/queue.go @@ -7,6 +7,8 @@ */ package queue +// minQueueLen is smallest capacity that queue may have. +// Must be power of 2 for bitwise modulus: x % n == x & (n - 1). const minQueueLen = 16 // Queue represents a single instance of the queue data structure. @@ -30,7 +32,7 @@ // resizes the queue to fit exactly twice its current contents // this can result in shrinking if the queue is less than half-full func (q *Queue) resize() { - newBuf := make([]interface{}, q.count*2) + newBuf := make([]interface{}, q.count<<1) if q.tail > q.head { copy(newBuf, q.buf[q.head:q.tail]) @@ -51,7 +53,8 @@ } q.buf[q.tail] = elem - q.tail = (q.tail + 1) % len(q.buf) + // bitwise modulus + q.tail = (q.tail + 1) & (len(q.buf) - 1) q.count++ } @@ -65,24 +68,35 @@ } // Get returns the element at index i in the queue. If the index is -// invalid, the call will panic. +// invalid, the call will panic. This method accepts both positive and +// negative index values. Index 0 refers to the first element, and +// index -1 refers to the last. func (q *Queue) Get(i int) interface{} { + // If indexing backwards, convert to positive index. + if i < 0 { + i += q.count + } if i < 0 || i >= q.count { panic("queue: Get() called with index out of range") } - return q.buf[(q.head+i)%len(q.buf)] + // bitwise modulus + return q.buf[(q.head+i)&(len(q.buf)-1)] } -// Remove removes the element from the front of the queue. If you actually -// want the element, call Peek first. This call panics if the queue is empty. -func (q *Queue) Remove() { +// Remove removes and returns the element from the front of the queue. If the +// queue is empty, the call will panic. +func (q *Queue) Remove() interface{} { if q.count <= 0 { panic("queue: Remove() called on empty queue") } + ret := q.buf[q.head] q.buf[q.head] = nil - q.head = (q.head + 1) % len(q.buf) + // bitwise modulus + q.head = (q.head + 1) & (len(q.buf) - 1) q.count-- - if len(q.buf) > minQueueLen && q.count*4 == len(q.buf) { + // Resize down if buffer 1/4 full. + if len(q.buf) > minQueueLen && (q.count<<2) == len(q.buf) { q.resize() } + return ret } diff --git a/queue_test.go b/queue_test.go index f2765c1..a875848 100644 --- a/queue_test.go +++ b/queue_test.go @@ -12,7 +12,10 @@ if q.Peek().(int) != i { t.Error("peek", i, "had value", q.Peek()) } - q.Remove() + x := q.Remove() + if x != i { + t.Error("remove", i, "had value", x) + } } } @@ -69,6 +72,19 @@ } } +func TestQueueGetNegative(t *testing.T) { + q := New() + + for i := 0; i < 1000; i++ { + q.Add(i) + for j := 1; j <= q.Length(); j++ { + if q.Get(-j).(int) != q.Length()-j { + t.Errorf("index %d doesn't contain %d", -j, q.Length()-j) + } + } + } +} + func TestQueueGetOutOfRangePanics(t *testing.T) { q := New() @@ -77,7 +93,7 @@ q.Add(3) assertPanics(t, "should panic when negative index", func() { - q.Get(-1) + q.Get(-4) }) assertPanics(t, "should panic when index greater than length", func() {