Merge pull request #1 from gammazero/insertremove
Add Insert and Remove. No negative indexing.
This commit is contained in:
commit
09ca60094b
|
@ -49,7 +49,7 @@ func main() {
|
|||
|
||||
// Print: hello bar world
|
||||
for i := 0; i < q.Len(); i++ {
|
||||
fmt.Print(q.PeekAt(i), " ")
|
||||
fmt.Print(q.Get(i), " ")
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
|
108
deque.go
108
deque.go
|
@ -123,23 +123,109 @@ func (q *Deque) Back() interface{} {
|
|||
return q.buf[(q.tail-1)&(len(q.buf)-1)]
|
||||
}
|
||||
|
||||
// PeekAt returns the element at index i in the queue. This method accepts
|
||||
// both positive and negative index values. PeekAt(0) refers to the first
|
||||
// (earliest added) element and is the same as Front(). PeekAt(-1) refers to
|
||||
// the last (latest added) element and is the same as Back(). If the index
|
||||
// is invalid, the call panics.
|
||||
func (q *Deque) PeekAt(i int) interface{} {
|
||||
// If indexing backwards, convert to positive index.
|
||||
if i < 0 {
|
||||
i += q.count
|
||||
}
|
||||
// Get returns the element at index i in 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 (q *Deque) Get(i int) interface{} {
|
||||
if i < 0 || i >= q.count {
|
||||
panic("deque: PeekAt() called with index out of range")
|
||||
panic("deque: Get() called with index out of range")
|
||||
}
|
||||
// bitwise modulus
|
||||
return q.buf[(q.head+i)&(len(q.buf)-1)]
|
||||
}
|
||||
|
||||
// Insert is used to insert an element into the middle of the queue.
|
||||
// Insert(0,e) is the same as PushFront(e) and Insert(Len(),e) is the same as
|
||||
// PushBack(e). Accepts only non-negative index values, and panics if index is
|
||||
// out of range.
|
||||
func (q *Deque) Insert(i int, elem interface{}) {
|
||||
if i < 0 || i > q.count {
|
||||
panic("deque: Insert() called with index out of range")
|
||||
}
|
||||
if i == 0 {
|
||||
q.PushFront(elem)
|
||||
return
|
||||
}
|
||||
if i == q.count {
|
||||
q.PushBack(elem)
|
||||
return
|
||||
}
|
||||
if i <= q.count/2 {
|
||||
// If inserting closer to front, rotate front to back i places, put
|
||||
// element at front, then rotate back to front i places.
|
||||
for j := 0; j < i; j++ {
|
||||
q.PushBack(q.PopFront())
|
||||
}
|
||||
q.PushFront(elem)
|
||||
for j := 0; j < i; j++ {
|
||||
q.PushFront(q.PopBack())
|
||||
}
|
||||
} else {
|
||||
// If inserting closer to back, rotate back to front Len() - i places,
|
||||
// put element at back, then rotate front to back same amount.
|
||||
rots := q.count - i
|
||||
for j := 0; j < rots; j++ {
|
||||
q.PushFront(q.PopBack())
|
||||
}
|
||||
q.PushBack(elem)
|
||||
for j := 0; j < rots; j++ {
|
||||
q.PushBack(q.PopFront())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove removes and returns an element from the middle of the queue.
|
||||
// Remove(0) is the same as PopFront() and Remove(Len()-1) is the same as
|
||||
// PopBack(). Accepts only non-negative index values, and panics if index is
|
||||
// out of range.
|
||||
func (q *Deque) Remove(i int) interface{} {
|
||||
if i < 0 || i >= q.count {
|
||||
panic("deque: Remove() called with index out of range")
|
||||
}
|
||||
if i == 0 {
|
||||
return q.PopFront()
|
||||
}
|
||||
if i == q.count-1 {
|
||||
return q.PopBack()
|
||||
}
|
||||
var elem interface{}
|
||||
if i <= q.count/2 {
|
||||
// If removing closer to front, rotate front to back i places, remove
|
||||
// element at front, then rotate back to front i places.
|
||||
for j := 0; j < i; j++ {
|
||||
q.PushBack(q.PopFront())
|
||||
}
|
||||
elem = q.PopFront()
|
||||
for j := 0; j < i; j++ {
|
||||
q.PushFront(q.PopBack())
|
||||
}
|
||||
} else {
|
||||
// If removing closer to back, rotate back to front Len() - 1 - i
|
||||
// places, remove element at back, then rotate front to back same
|
||||
// amount.
|
||||
rots := (q.count - 1) - i
|
||||
for j := 0; j < rots; j++ {
|
||||
q.PushFront(q.PopBack())
|
||||
}
|
||||
elem = q.PopBack()
|
||||
for j := 0; j < rots; j++ {
|
||||
q.PushBack(q.PopFront())
|
||||
}
|
||||
}
|
||||
return elem
|
||||
}
|
||||
|
||||
// Replace replaces the element at position i with the given element. Accepts
|
||||
// only non-negative index values, and panics if index is out of range
|
||||
func (q *Deque) Replace(i int, elem interface{}) {
|
||||
if i < 0 || i >= q.count {
|
||||
panic("deque: Remove() called with index out of range")
|
||||
}
|
||||
// bitwise modulus
|
||||
q.buf[(q.head+i)&(len(q.buf)-1)] = elem
|
||||
}
|
||||
|
||||
// Clear removes all elements from the queue, but retains the current capacity.
|
||||
// The queue will not be resized smaller as long as items are only added.
|
||||
// Only when items are removed is the queue subject to getting resized smaller.
|
||||
|
|
240
deque_test.go
240
deque_test.go
|
@ -52,8 +52,8 @@ func TestGrowShrink(t *testing.T) {
|
|||
}
|
||||
// Check that all values are as expected.
|
||||
for i := 0; i < minCapacity*2; i++ {
|
||||
if q.PeekAt(i) != i {
|
||||
t.Errorf("q.PeekAt(%d) = %d, expected %d", i, q.PeekAt(i), i)
|
||||
if q.Get(i) != i {
|
||||
t.Errorf("q.Get(%d) = %d, expected %d", i, q.Get(i), i)
|
||||
}
|
||||
}
|
||||
bufLen := len(q.buf)
|
||||
|
@ -102,8 +102,8 @@ func TestGrowShrink(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestDequeSimple(t *testing.T) {
|
||||
q := new(Deque)
|
||||
func TestSimple(t *testing.T) {
|
||||
var q Deque
|
||||
|
||||
for i := 0; i < minCapacity; i++ {
|
||||
q.PushBack(i)
|
||||
|
@ -130,8 +130,8 @@ func TestDequeSimple(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestDequeWrap(t *testing.T) {
|
||||
q := new(Deque)
|
||||
func TestBufferWrap(t *testing.T) {
|
||||
var q Deque
|
||||
|
||||
for i := 0; i < minCapacity; i++ {
|
||||
q.PushBack(i)
|
||||
|
@ -150,8 +150,8 @@ func TestDequeWrap(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestDequeWrapReverse(t *testing.T) {
|
||||
q := new(Deque)
|
||||
func TestBufferWrapReverse(t *testing.T) {
|
||||
var q Deque
|
||||
|
||||
for i := 0; i < minCapacity; i++ {
|
||||
q.PushFront(i)
|
||||
|
@ -169,8 +169,8 @@ func TestDequeWrapReverse(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestDequeLen(t *testing.T) {
|
||||
q := new(Deque)
|
||||
func TestLen(t *testing.T) {
|
||||
var q Deque
|
||||
|
||||
if q.Len() != 0 {
|
||||
t.Error("empty queue length not 0")
|
||||
|
@ -190,34 +190,30 @@ func TestDequeLen(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestDequePeekAt(t *testing.T) {
|
||||
q := new(Deque)
|
||||
func TestGet(t *testing.T) {
|
||||
var q Deque
|
||||
|
||||
for i := 0; i < 1000; i++ {
|
||||
q.PushBack(i)
|
||||
for j := 0; j < q.Len(); j++ {
|
||||
if q.PeekAt(j).(int) != j {
|
||||
t.Errorf("index %d doesn't contain %d", j, j)
|
||||
}
|
||||
}
|
||||
|
||||
// Front to back.
|
||||
for j := 0; j < q.Len(); j++ {
|
||||
if q.Get(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.Get(q.Len()-j).(int) != q.Len()-j {
|
||||
t.Errorf("index %d doesn't contain %d", q.Len()-j, q.Len()-j)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDequePeekAtNegative(t *testing.T) {
|
||||
q := new(Deque)
|
||||
|
||||
for i := 0; i < 1000; i++ {
|
||||
q.PushBack(i)
|
||||
for j := 1; j <= q.Len(); j++ {
|
||||
if q.PeekAt(-j).(int) != q.Len()-j {
|
||||
t.Errorf("index %d doesn't contain %d", -j, q.Len()-j)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDequeBack(t *testing.T) {
|
||||
q := new(Deque)
|
||||
func TestBack(t *testing.T) {
|
||||
var q Deque
|
||||
|
||||
for i := 0; i < minCapacity+5; i++ {
|
||||
q.PushBack(i)
|
||||
|
@ -228,7 +224,7 @@ func TestDequeBack(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestCopy(t *testing.T) {
|
||||
q := new(Deque)
|
||||
var q Deque
|
||||
a := make([]interface{}, minCapacity)
|
||||
if q.Copy(a) != 0 {
|
||||
t.Error("Copied wrong size, expected 0")
|
||||
|
@ -265,7 +261,7 @@ func TestCopy(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestRotate(t *testing.T) {
|
||||
q := new(Deque)
|
||||
var q Deque
|
||||
for i := 0; i < 10; i++ {
|
||||
q.PushBack(i)
|
||||
}
|
||||
|
@ -300,8 +296,8 @@ func TestRotate(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestDequeClear(t *testing.T) {
|
||||
q := new(Deque)
|
||||
func TestClear(t *testing.T) {
|
||||
var q Deque
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
q.PushBack(i)
|
||||
|
@ -327,25 +323,119 @@ func TestDequeClear(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestPeekAtOutOfRangePanics(t *testing.T) {
|
||||
q := new(Deque)
|
||||
func TestInsert(t *testing.T) {
|
||||
var q Deque
|
||||
q.PushBack("A")
|
||||
q.PushBack("B")
|
||||
q.PushBack("C")
|
||||
q.PushBack("D")
|
||||
q.PushBack("E")
|
||||
q.PushBack("F")
|
||||
q.PushBack("G")
|
||||
|
||||
q.Insert(4, "x")
|
||||
if q.Get(4) != "x" {
|
||||
t.Error("expected x at position 4")
|
||||
}
|
||||
|
||||
q.Insert(2, "y")
|
||||
if q.Get(2) != "y" {
|
||||
t.Error("expected y at position 2")
|
||||
}
|
||||
|
||||
if q.Get(5) != "x" {
|
||||
t.Error("expected x at position 5")
|
||||
}
|
||||
|
||||
q.Insert(0, "b")
|
||||
if q.Front() != "b" {
|
||||
t.Error("expected b inserted at front")
|
||||
}
|
||||
|
||||
q.Insert(q.Len(), "e")
|
||||
if q.Back() != "e" {
|
||||
t.Error("expected e inserted at back")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemove(t *testing.T) {
|
||||
var q Deque
|
||||
q.PushBack("A")
|
||||
q.PushBack("B")
|
||||
q.PushBack("C")
|
||||
q.PushBack("D")
|
||||
q.PushBack("E")
|
||||
q.PushBack("F")
|
||||
q.PushBack("G")
|
||||
|
||||
if q.Remove(4) != "E" {
|
||||
t.Error("expected E from position 4")
|
||||
}
|
||||
if q.Get(4) != "F" {
|
||||
t.Error("expected F at position 4")
|
||||
}
|
||||
|
||||
if q.Remove(2) != "C" {
|
||||
t.Error("expected C at position 2")
|
||||
}
|
||||
if q.Get(2) != "D" {
|
||||
t.Error("expected D at position 4")
|
||||
}
|
||||
|
||||
if q.Get(4) != "G" {
|
||||
t.Error("expected G at position 4")
|
||||
}
|
||||
|
||||
if q.Remove(0) != "A" {
|
||||
t.Error("expected to remove A from front")
|
||||
}
|
||||
|
||||
if q.Remove(q.Len()-1) != "G" {
|
||||
t.Error("expected to remove G from back")
|
||||
}
|
||||
}
|
||||
|
||||
func TestReplace(t *testing.T) {
|
||||
var q Deque
|
||||
q.PushBack("a")
|
||||
q.PushBack("b")
|
||||
q.PushBack("c")
|
||||
|
||||
q.Replace(0, "A")
|
||||
if q.Front() != "A" {
|
||||
t.Error("expected A at front")
|
||||
}
|
||||
|
||||
q.Replace(q.Len()-1, "C")
|
||||
if q.Back() != "C" {
|
||||
t.Error("expected C at back")
|
||||
}
|
||||
|
||||
q.Replace(1, "-")
|
||||
if q.Get(1) != "-" {
|
||||
t.Error("expected - at position 1")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOutOfRangePanics(t *testing.T) {
|
||||
var q Deque
|
||||
|
||||
q.PushBack(1)
|
||||
q.PushBack(2)
|
||||
q.PushBack(3)
|
||||
|
||||
assertPanics(t, "should panic when negative index", func() {
|
||||
q.PeekAt(-4)
|
||||
q.Get(-4)
|
||||
})
|
||||
|
||||
assertPanics(t, "should panic when index greater than length", func() {
|
||||
q.PeekAt(4)
|
||||
q.Get(4)
|
||||
})
|
||||
}
|
||||
|
||||
func TestFrontBackOutOfRangePanics(t *testing.T) {
|
||||
const msg = "should panic when peeking empty queue"
|
||||
q := new(Deque)
|
||||
var q Deque
|
||||
assertPanics(t, msg, func() {
|
||||
q.Front()
|
||||
})
|
||||
|
@ -365,7 +455,7 @@ func TestFrontBackOutOfRangePanics(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestPopFrontOutOfRangePanics(t *testing.T) {
|
||||
q := new(Deque)
|
||||
var q Deque
|
||||
|
||||
assertPanics(t, "should panic when removing empty queue", func() {
|
||||
q.PopFront()
|
||||
|
@ -380,7 +470,7 @@ func TestPopFrontOutOfRangePanics(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestPopBackOutOfRangePanics(t *testing.T) {
|
||||
q := new(Deque)
|
||||
var q Deque
|
||||
|
||||
assertPanics(t, "should panic when removing empty queue", func() {
|
||||
q.PopBack()
|
||||
|
@ -394,6 +484,60 @@ func TestPopBackOutOfRangePanics(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestInsertOutOfRangePanics(t *testing.T) {
|
||||
var q Deque
|
||||
|
||||
assertPanics(t, "should panic when inserting out of range", func() {
|
||||
q.Insert(1, "X")
|
||||
})
|
||||
|
||||
q.PushBack("A")
|
||||
|
||||
assertPanics(t, "should panic when inserting at negative index", func() {
|
||||
q.Insert(-1, "Y")
|
||||
})
|
||||
|
||||
assertPanics(t, "should panic when inserting out of range", func() {
|
||||
q.Insert(2, "B")
|
||||
})
|
||||
}
|
||||
|
||||
func TestRemoveOutOfRangePanics(t *testing.T) {
|
||||
var q Deque
|
||||
|
||||
assertPanics(t, "should panic when removing from empty queue", func() {
|
||||
q.Remove(0)
|
||||
})
|
||||
|
||||
q.PushBack("A")
|
||||
|
||||
assertPanics(t, "should panic when removing at negative index", func() {
|
||||
q.Remove(-1)
|
||||
})
|
||||
|
||||
assertPanics(t, "should panic when removing out of range", func() {
|
||||
q.Remove(1)
|
||||
})
|
||||
}
|
||||
|
||||
func TestReplaceOutOfRangePanics(t *testing.T) {
|
||||
var q Deque
|
||||
|
||||
assertPanics(t, "should panic when replacing in empty queue", func() {
|
||||
q.Replace(0, "x")
|
||||
})
|
||||
|
||||
q.PushBack("A")
|
||||
|
||||
assertPanics(t, "should panic when replacing at negative index", func() {
|
||||
q.Replace(-1, "Z")
|
||||
})
|
||||
|
||||
assertPanics(t, "should panic when replacing out of range", func() {
|
||||
q.Replace(1, "Y")
|
||||
})
|
||||
}
|
||||
|
||||
func assertPanics(t *testing.T, name string, f func()) {
|
||||
defer func() {
|
||||
if r := recover(); r == nil {
|
||||
|
@ -456,7 +600,7 @@ func BenchmarkSerialReverse(b *testing.B) {
|
|||
}
|
||||
|
||||
func BenchmarkRotate(b *testing.B) {
|
||||
q := new(Deque)
|
||||
var q Deque
|
||||
for i := 0; i < size; i++ {
|
||||
q.PushBack(i)
|
||||
}
|
||||
|
@ -470,7 +614,7 @@ func BenchmarkRotate(b *testing.B) {
|
|||
}
|
||||
|
||||
func BenchmarkRotateReverse(b *testing.B) {
|
||||
q := new(Deque)
|
||||
var q Deque
|
||||
for i := 0; i < size; i++ {
|
||||
q.PushBack(i)
|
||||
}
|
||||
|
@ -483,21 +627,21 @@ func BenchmarkRotateReverse(b *testing.B) {
|
|||
}
|
||||
}
|
||||
|
||||
func BenchmarkDequePeekAt(b *testing.B) {
|
||||
q := new(Deque)
|
||||
func BenchmarkDequeGet(b *testing.B) {
|
||||
var q Deque
|
||||
for i := 0; i < size; i++ {
|
||||
q.PushBack(i)
|
||||
}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
for j := 0; j < size; j++ {
|
||||
q.PeekAt(j)
|
||||
q.Get(j)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkDequePushPop(b *testing.B) {
|
||||
q := new(Deque)
|
||||
var q Deque
|
||||
for i := 0; i < b.N; i++ {
|
||||
for n := 0; n < size; n++ {
|
||||
q.PushBack(nil)
|
||||
|
|
|
@ -4,7 +4,7 @@ set -e
|
|||
echo "" > coverage.txt
|
||||
|
||||
for d in $(go list ./... | grep -v vendor); do
|
||||
go test -race -coverprofile=profile.out -covermode=atomic $d
|
||||
go test -coverprofile=profile.out -covermode=atomic $d
|
||||
if [ -f profile.out ]; then
|
||||
cat profile.out >> coverage.txt
|
||||
rm profile.out
|
||||
|
|
Loading…
Reference in a new issue