From 7d7061a1b6141065b7041efc166ed0f1294dbc22 Mon Sep 17 00:00:00 2001 From: Andrew Gillis Date: Thu, 10 May 2018 19:11:55 -0400 Subject: [PATCH 1/2] Add At() method --- deque.go | 21 +++++++++++++ deque_test.go | 81 ++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 85 insertions(+), 17 deletions(-) diff --git a/deque.go b/deque.go index 6eed4a3..f3b14c7 100644 --- a/deque.go +++ b/deque.go @@ -129,6 +129,27 @@ func (q *Deque) Back() interface{} { return q.buf[q.prev(q.tail)] } +// Get returns the element at index i in the queue without removing the element +// from the queue. This method accepts only non-negative index values. get(0) +// refers to the first element and is the same as Front(). get(Len()-1) refers +// to the last element and is the same as Back(). If the index is invalid, the +// call panics. +// +// The purpose of Get is to allow Deque to serve as a more general purpose +// circular buffer, such as an LRU cache or a circular log. For such uses, +// items are only added to and removed from the the ends of the deque, but may +// be read from any place within the deque. Consider the case of a circular +// log buffer, where new entries are pushed on one end and the oldest entries +// are popped from the other end, and any/all of the entries in the buffer must +// be readable without altering the buffer contents. +func (q *Deque) At(i int) interface{} { + if i < 0 || i >= q.count { + panic("deque: Get() called with index out of range") + } + // bitwise modulus + return q.buf[(q.head+i)&(len(q.buf)-1)] +} + // Clear removes all elements from the queue, but retains the current capacity. // This is useful when repeatedly reusing the queue at high frequency to avoid // GC during reuse. The queue will not be resized smaller as long as items are diff --git a/deque_test.go b/deque_test.go index 473a2f7..36c5771 100644 --- a/deque_test.go +++ b/deque_test.go @@ -211,7 +211,7 @@ func checkRotate(t *testing.T, size int) { for i := 0; i < q.Len(); i++ { x := i for n := 0; n < q.Len(); n++ { - if get(q, n) != x { + if q.At(n) != x { t.Fatalf("a[%d] != %d after rotate and copy", n, x) } x++ @@ -261,6 +261,28 @@ func TestRotate(t *testing.T) { } } +func TestAt(t *testing.T) { + var q Deque + + for i := 0; i < 1000; i++ { + q.PushBack(i) + } + + // Front to back. + for j := 0; j < q.Len(); j++ { + if q.At(j).(int) != j { + t.Errorf("index %d doesn't contain %d", j, j) + } + } + + // Back to front + for j := 1; j <= q.Len(); j++ { + if q.At(q.Len()-j).(int) != q.Len()-j { + t.Errorf("index %d doesn't contain %d", q.Len()-j, q.Len()-j) + } + } +} + func TestClear(t *testing.T) { var q Deque @@ -293,9 +315,24 @@ func TestInsert(t *testing.T) { for _, x := range "ABCDEFG" { q.PushBack(x) } - insert(q, 4, 'x') // ABCDxEFG - insert(q, 2, 'y') // AByCDxEFG - insert(q, 0, 'b') // bAByCDxEFG + insert(q, 4, 'x') // ABCDxEFG + if q.At(4) != 'x' { + t.Error("expected x at position 4") + } + + insert(q, 2, 'y') // AByCDxEFG + if q.At(2) != 'y' { + t.Error("expected y at position 2") + } + if q.At(5) != 'x' { + t.Error("expected x at position 5") + } + + insert(q, 0, 'b') // bAByCDxEFG + if q.Front() != 'b' { + t.Error("expected b inserted at front") + } + insert(q, q.Len(), 'e') // bAByCDxEFGe for i, x := range "bAByCDxEFGe" { @@ -314,9 +351,16 @@ func TestRemove(t *testing.T) { if remove(q, 4) != 'E' { // ABCDFG t.Error("expected E from position 4") } + if q.At(4) != 'F' { + t.Error("expected F at position 4") + } + if remove(q, 2) != 'C' { // ABDFG t.Error("expected C at position 2") } + if q.At(2) != 'D' { + t.Error("expected D at position 4") + } if q.Back() != 'G' { t.Error("expected G at back") } @@ -391,6 +435,22 @@ func TestPopBackOutOfRangePanics(t *testing.T) { }) } +func TestAtOutOfRangePanics(t *testing.T) { + var q Deque + + q.PushBack(1) + q.PushBack(2) + q.PushBack(3) + + assertPanics(t, "should panic when negative index", func() { + q.At(-4) + }) + + assertPanics(t, "should panic when index greater than length", func() { + q.At(4) + }) +} + func TestInsertOutOfRangePanics(t *testing.T) { q := new(Deque) @@ -562,16 +622,3 @@ func remove(q *Deque, i int) interface{} { q.Rotate(rots) return elem } - -// get returns the element at index i in the queue without removing the element -// from the queue. This method accepts only non-negative index values. get(0) -// refers to the first element and is the same as Front(). get(Len()-1) refers -// to the last element and is the same as Back(). If the index is invalid, the -// call panics. -func get(q Deque, i int) interface{} { - if i < 0 || i >= q.count { - panic("deque: get() called with index out of range") - } - // bitwise modulus - return q.buf[(q.head+i)&(len(q.buf)-1)] -} From d00173d949865473fadbe8161f520984442d399e Mon Sep 17 00:00:00 2001 From: Andrew Gillis Date: Thu, 10 May 2018 19:23:41 -0400 Subject: [PATCH 2/2] comment --- deque.go | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/deque.go b/deque.go index f3b14c7..8cb0f58 100644 --- a/deque.go +++ b/deque.go @@ -136,12 +136,11 @@ func (q *Deque) Back() interface{} { // call panics. // // The purpose of Get is to allow Deque to serve as a more general purpose -// circular buffer, such as an LRU cache or a circular log. For such uses, -// items are only added to and removed from the the ends of the deque, but may -// be read from any place within the deque. Consider the case of a circular -// log buffer, where new entries are pushed on one end and the oldest entries -// are popped from the other end, and any/all of the entries in the buffer must -// be readable without altering the buffer contents. +// circular buffer, where items are only added to and removed from the the ends +// of the deque, but may be read from any place within the deque. Consider the +// case of a fixed-size circular log buffer: A new entry is pushed onto one end +// and when full the oldest is popped from the other end. All the log entries +// in the buffer must be readable without altering the buffer contents. func (q *Deque) At(i int) interface{} { if i < 0 || i >= q.count { panic("deque: Get() called with index out of range")