Make an integer-only deque
This commit is contained in:
parent
53a0acdb4c
commit
951c9e89e2
33
.github/workflows/go.yml
vendored
33
.github/workflows/go.yml
vendored
|
@ -1,33 +0,0 @@
|
||||||
name: Go
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ master ]
|
|
||||||
pull_request:
|
|
||||||
branches: [ master ]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- name: Set up Go
|
|
||||||
uses: actions/setup-go@v2
|
|
||||||
with:
|
|
||||||
go-version: 1.16
|
|
||||||
|
|
||||||
- name: Vet
|
|
||||||
run: go vet ./...
|
|
||||||
|
|
||||||
- name: Build
|
|
||||||
run: go build -v ./...
|
|
||||||
|
|
||||||
- name: Test
|
|
||||||
run: go test -v ./... -coverprofile=coverage.txt -covermode=atomic
|
|
||||||
|
|
||||||
- name: Upload coverage to Codecov
|
|
||||||
uses: codecov/codecov-action@v1
|
|
||||||
with:
|
|
||||||
files: coverage.txt
|
|
21
.github/workflows/main.yml
vendored
21
.github/workflows/main.yml
vendored
|
@ -1,21 +0,0 @@
|
||||||
name: golangci-lint
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
tags:
|
|
||||||
- v*
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
- main
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
|
|
||||||
golangci:
|
|
||||||
name: lint
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- name: golangci-lint
|
|
||||||
uses: golangci/golangci-lint-action@v2
|
|
|
@ -1,10 +1,6 @@
|
||||||
# deque
|
# deque
|
||||||
|
|
||||||
[![GoDoc](https://pkg.go.dev/badge/github.com/gammazero/deque)](https://pkg.go.dev/github.com/gammazero/deque)
|
Fork of [github.com/gammazero/deque](https://github.com/gammazero/deque)
|
||||||
[![Build Status](https://github.com/gammazero/deque/actions/workflows/go.yml/badge.svg)](https://github.com/gammazero/deque/actions/workflows/go.yml)
|
|
||||||
[![Go Report Card](https://goreportcard.com/badge/github.com/gammazero/deque)](https://goreportcard.com/report/github.com/gammazero/deque)
|
|
||||||
[![codecov](https://codecov.io/gh/gammazero/deque/branch/master/graph/badge.svg)](https://codecov.io/gh/gammazero/deque)
|
|
||||||
[![License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
|
|
||||||
|
|
||||||
Fast ring-buffer deque ([double-ended queue](https://en.wikipedia.org/wiki/Double-ended_queue)) implementation.
|
Fast ring-buffer deque ([double-ended queue](https://en.wikipedia.org/wiki/Double-ended_queue)) implementation.
|
||||||
|
|
||||||
|
|
42
deque.go
42
deque.go
|
@ -6,7 +6,7 @@ const minCapacity = 16
|
||||||
|
|
||||||
// Deque represents a single instance of the deque data structure.
|
// Deque represents a single instance of the deque data structure.
|
||||||
type Deque struct {
|
type Deque struct {
|
||||||
buf []interface{}
|
buf []*int
|
||||||
head int
|
head int
|
||||||
tail int
|
tail int
|
||||||
count int
|
count int
|
||||||
|
@ -39,13 +39,13 @@ func New(size ...int) *Deque {
|
||||||
minCap <<= 1
|
minCap <<= 1
|
||||||
}
|
}
|
||||||
|
|
||||||
var buf []interface{}
|
var buf []*int
|
||||||
if capacity != 0 {
|
if capacity != 0 {
|
||||||
bufSize := minCap
|
bufSize := minCap
|
||||||
for bufSize < capacity {
|
for bufSize < capacity {
|
||||||
bufSize <<= 1
|
bufSize <<= 1
|
||||||
}
|
}
|
||||||
buf = make([]interface{}, bufSize)
|
buf = make([]*int, bufSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Deque{
|
return &Deque{
|
||||||
|
@ -67,29 +67,29 @@ func (q *Deque) Len() int {
|
||||||
// PushBack appends an element to the back of the queue. Implements FIFO when
|
// PushBack appends an element to the back of the queue. Implements FIFO when
|
||||||
// elements are removed with PopFront(), and LIFO when elements are removed
|
// elements are removed with PopFront(), and LIFO when elements are removed
|
||||||
// with PopBack().
|
// with PopBack().
|
||||||
func (q *Deque) PushBack(elem interface{}) {
|
func (q *Deque) PushBack(elem int) {
|
||||||
q.growIfFull()
|
q.growIfFull()
|
||||||
|
|
||||||
q.buf[q.tail] = elem
|
q.buf[q.tail] = &elem
|
||||||
// Calculate new tail position.
|
// Calculate new tail position.
|
||||||
q.tail = q.next(q.tail)
|
q.tail = q.next(q.tail)
|
||||||
q.count++
|
q.count++
|
||||||
}
|
}
|
||||||
|
|
||||||
// PushFront prepends an element to the front of the queue.
|
// PushFront prepends an element to the front of the queue.
|
||||||
func (q *Deque) PushFront(elem interface{}) {
|
func (q *Deque) PushFront(elem int) {
|
||||||
q.growIfFull()
|
q.growIfFull()
|
||||||
|
|
||||||
// Calculate new head position.
|
// Calculate new head position.
|
||||||
q.head = q.prev(q.head)
|
q.head = q.prev(q.head)
|
||||||
q.buf[q.head] = elem
|
q.buf[q.head] = &elem
|
||||||
q.count++
|
q.count++
|
||||||
}
|
}
|
||||||
|
|
||||||
// PopFront removes and returns the element from the front of the queue.
|
// PopFront removes and returns the element from the front of the queue.
|
||||||
// Implements FIFO when used with PushBack(). If the queue is empty, the call
|
// Implements FIFO when used with PushBack(). If the queue is empty, the call
|
||||||
// panics.
|
// panics.
|
||||||
func (q *Deque) PopFront() interface{} {
|
func (q *Deque) PopFront() int {
|
||||||
if q.count <= 0 {
|
if q.count <= 0 {
|
||||||
panic("deque: PopFront() called on empty queue")
|
panic("deque: PopFront() called on empty queue")
|
||||||
}
|
}
|
||||||
|
@ -100,13 +100,13 @@ func (q *Deque) PopFront() interface{} {
|
||||||
q.count--
|
q.count--
|
||||||
|
|
||||||
q.shrinkIfExcess()
|
q.shrinkIfExcess()
|
||||||
return ret
|
return *ret
|
||||||
}
|
}
|
||||||
|
|
||||||
// PopBack removes and returns the element from the back of the queue.
|
// PopBack removes and returns the element from the back of the queue.
|
||||||
// Implements LIFO when used with PushBack(). If the queue is empty, the call
|
// Implements LIFO when used with PushBack(). If the queue is empty, the call
|
||||||
// panics.
|
// panics.
|
||||||
func (q *Deque) PopBack() interface{} {
|
func (q *Deque) PopBack() int {
|
||||||
if q.count <= 0 {
|
if q.count <= 0 {
|
||||||
panic("deque: PopBack() called on empty queue")
|
panic("deque: PopBack() called on empty queue")
|
||||||
}
|
}
|
||||||
|
@ -120,27 +120,27 @@ func (q *Deque) PopBack() interface{} {
|
||||||
q.count--
|
q.count--
|
||||||
|
|
||||||
q.shrinkIfExcess()
|
q.shrinkIfExcess()
|
||||||
return ret
|
return *ret
|
||||||
}
|
}
|
||||||
|
|
||||||
// Front returns the element at the front of the queue. This is the element
|
// Front returns the element at the front of the queue. This is the element
|
||||||
// that would be returned by PopFront(). This call panics if the queue is
|
// that would be returned by PopFront(). This call panics if the queue is
|
||||||
// empty.
|
// empty.
|
||||||
func (q *Deque) Front() interface{} {
|
func (q *Deque) Front() int {
|
||||||
if q.count <= 0 {
|
if q.count <= 0 {
|
||||||
panic("deque: Front() called when empty")
|
panic("deque: Front() called when empty")
|
||||||
}
|
}
|
||||||
return q.buf[q.head]
|
return *q.buf[q.head]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Back returns the element at the back of the queue. This is the element
|
// Back returns the element at the back of the queue. This is the element
|
||||||
// that would be returned by PopBack(). This call panics if the queue is
|
// that would be returned by PopBack(). This call panics if the queue is
|
||||||
// empty.
|
// empty.
|
||||||
func (q *Deque) Back() interface{} {
|
func (q *Deque) Back() int {
|
||||||
if q.count <= 0 {
|
if q.count <= 0 {
|
||||||
panic("deque: Back() called when empty")
|
panic("deque: Back() called when empty")
|
||||||
}
|
}
|
||||||
return q.buf[q.prev(q.tail)]
|
return *q.buf[q.prev(q.tail)]
|
||||||
}
|
}
|
||||||
|
|
||||||
// At returns the element at index i in the queue without removing the element
|
// At returns the element at index i in the queue without removing the element
|
||||||
|
@ -155,23 +155,23 @@ func (q *Deque) Back() interface{} {
|
||||||
// case of a fixed-size circular log buffer: A new entry is pushed onto one end
|
// 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
|
// 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.
|
// in the buffer must be readable without altering the buffer contents.
|
||||||
func (q *Deque) At(i int) interface{} {
|
func (q *Deque) At(i int) int {
|
||||||
if i < 0 || i >= q.count {
|
if i < 0 || i >= q.count {
|
||||||
panic("deque: At() called with index out of range")
|
panic("deque: At() called with index out of range")
|
||||||
}
|
}
|
||||||
// bitwise modulus
|
// bitwise modulus
|
||||||
return q.buf[(q.head+i)&(len(q.buf)-1)]
|
return *q.buf[(q.head+i)&(len(q.buf)-1)]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set puts the element at index i in the queue. Set shares the same purpose
|
// Set puts the element at index i in the queue. Set shares the same purpose
|
||||||
// than At() but perform the opposite operation. The index i is the same
|
// than At() but perform the opposite operation. The index i is the same
|
||||||
// index defined by At(). If the index is invalid, the call panics.
|
// index defined by At(). If the index is invalid, the call panics.
|
||||||
func (q *Deque) Set(i int, elem interface{}) {
|
func (q *Deque) Set(i int, elem int) {
|
||||||
if i < 0 || i >= q.count {
|
if i < 0 || i >= q.count {
|
||||||
panic("deque: Set() called with index out of range")
|
panic("deque: Set() called with index out of range")
|
||||||
}
|
}
|
||||||
// bitwise modulus
|
// bitwise modulus
|
||||||
q.buf[(q.head+i)&(len(q.buf)-1)] = elem
|
q.buf[(q.head+i)&(len(q.buf)-1)] = &elem
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear removes all elements from the queue, but retains the current capacity.
|
// Clear removes all elements from the queue, but retains the current capacity.
|
||||||
|
@ -270,7 +270,7 @@ func (q *Deque) growIfFull() {
|
||||||
if q.minCap == 0 {
|
if q.minCap == 0 {
|
||||||
q.minCap = minCapacity
|
q.minCap = minCapacity
|
||||||
}
|
}
|
||||||
q.buf = make([]interface{}, q.minCap)
|
q.buf = make([]*int, q.minCap)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
q.resize()
|
q.resize()
|
||||||
|
@ -287,7 +287,7 @@ func (q *Deque) shrinkIfExcess() {
|
||||||
// used to grow the queue when it is full, and also to shrink it when it is
|
// used to grow the queue when it is full, and also to shrink it when it is
|
||||||
// only a quarter full.
|
// only a quarter full.
|
||||||
func (q *Deque) resize() {
|
func (q *Deque) resize() {
|
||||||
newBuf := make([]interface{}, q.count<<1)
|
newBuf := make([]*int, q.count<<1)
|
||||||
if q.tail > q.head {
|
if q.tail > q.head {
|
||||||
copy(newBuf, q.buf[q.head:q.tail])
|
copy(newBuf, q.buf[q.head:q.tail])
|
||||||
} else {
|
} else {
|
||||||
|
|
727
deque_test.go
727
deque_test.go
|
@ -1,727 +0,0 @@
|
||||||
package deque
|
|
||||||
|
|
||||||
import "testing"
|
|
||||||
|
|
||||||
func TestEmpty(t *testing.T) {
|
|
||||||
var q Deque
|
|
||||||
if q.Len() != 0 {
|
|
||||||
t.Error("q.Len() =", q.Len(), "expect 0")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFrontBack(t *testing.T) {
|
|
||||||
var q Deque
|
|
||||||
q.PushBack("foo")
|
|
||||||
q.PushBack("bar")
|
|
||||||
q.PushBack("baz")
|
|
||||||
if q.Front() != "foo" {
|
|
||||||
t.Error("wrong value at front of queue")
|
|
||||||
}
|
|
||||||
if q.Back() != "baz" {
|
|
||||||
t.Error("wrong value at back of queue")
|
|
||||||
}
|
|
||||||
|
|
||||||
if q.PopFront() != "foo" {
|
|
||||||
t.Error("wrong value removed from front of queue")
|
|
||||||
}
|
|
||||||
if q.Front() != "bar" {
|
|
||||||
t.Error("wrong value remaining at front of queue")
|
|
||||||
}
|
|
||||||
if q.Back() != "baz" {
|
|
||||||
t.Error("wrong value remaining at back of queue")
|
|
||||||
}
|
|
||||||
|
|
||||||
if q.PopBack() != "baz" {
|
|
||||||
t.Error("wrong value removed from back of queue")
|
|
||||||
}
|
|
||||||
if q.Front() != "bar" {
|
|
||||||
t.Error("wrong value remaining at front of queue")
|
|
||||||
}
|
|
||||||
if q.Back() != "bar" {
|
|
||||||
t.Error("wrong value remaining at back of queue")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGrowShrinkBack(t *testing.T) {
|
|
||||||
var q Deque
|
|
||||||
size := minCapacity * 2
|
|
||||||
|
|
||||||
for i := 0; i < size; i++ {
|
|
||||||
if q.Len() != i {
|
|
||||||
t.Error("q.Len() =", q.Len(), "expected", i)
|
|
||||||
}
|
|
||||||
q.PushBack(i)
|
|
||||||
}
|
|
||||||
bufLen := len(q.buf)
|
|
||||||
|
|
||||||
// Remove from back.
|
|
||||||
for i := size; i > 0; i-- {
|
|
||||||
if q.Len() != i {
|
|
||||||
t.Error("q.Len() =", q.Len(), "expected", i)
|
|
||||||
}
|
|
||||||
x := q.PopBack()
|
|
||||||
if x != i-1 {
|
|
||||||
t.Error("q.PopBack() =", x, "expected", i-1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if q.Len() != 0 {
|
|
||||||
t.Error("q.Len() =", q.Len(), "expected 0")
|
|
||||||
}
|
|
||||||
if len(q.buf) == bufLen {
|
|
||||||
t.Error("queue buffer did not shrink")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGrowShrinkFront(t *testing.T) {
|
|
||||||
var q Deque
|
|
||||||
size := minCapacity * 2
|
|
||||||
|
|
||||||
for i := 0; i < size; i++ {
|
|
||||||
if q.Len() != i {
|
|
||||||
t.Error("q.Len() =", q.Len(), "expected", i)
|
|
||||||
}
|
|
||||||
q.PushBack(i)
|
|
||||||
}
|
|
||||||
bufLen := len(q.buf)
|
|
||||||
|
|
||||||
// Remove from Front
|
|
||||||
for i := 0; i < size; i++ {
|
|
||||||
if q.Len() != size-i {
|
|
||||||
t.Error("q.Len() =", q.Len(), "expected", minCapacity*2-i)
|
|
||||||
}
|
|
||||||
x := q.PopFront()
|
|
||||||
if x != i {
|
|
||||||
t.Error("q.PopBack() =", x, "expected", i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if q.Len() != 0 {
|
|
||||||
t.Error("q.Len() =", q.Len(), "expected 0")
|
|
||||||
}
|
|
||||||
if len(q.buf) == bufLen {
|
|
||||||
t.Error("queue buffer did not shrink")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSimple(t *testing.T) {
|
|
||||||
var q Deque
|
|
||||||
|
|
||||||
for i := 0; i < minCapacity; i++ {
|
|
||||||
q.PushBack(i)
|
|
||||||
}
|
|
||||||
for i := 0; i < minCapacity; i++ {
|
|
||||||
if q.Front() != i {
|
|
||||||
t.Error("peek", i, "had value", q.Front())
|
|
||||||
}
|
|
||||||
x := q.PopFront()
|
|
||||||
if x != i {
|
|
||||||
t.Error("remove", i, "had value", x)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
q.Clear()
|
|
||||||
for i := 0; i < minCapacity; i++ {
|
|
||||||
q.PushFront(i)
|
|
||||||
}
|
|
||||||
for i := minCapacity - 1; i >= 0; i-- {
|
|
||||||
x := q.PopFront()
|
|
||||||
if x != i {
|
|
||||||
t.Error("remove", i, "had value", x)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBufferWrap(t *testing.T) {
|
|
||||||
var q Deque
|
|
||||||
|
|
||||||
for i := 0; i < minCapacity; i++ {
|
|
||||||
q.PushBack(i)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < 3; i++ {
|
|
||||||
q.PopFront()
|
|
||||||
q.PushBack(minCapacity + i)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < minCapacity; i++ {
|
|
||||||
if q.Front().(int) != i+3 {
|
|
||||||
t.Error("peek", i, "had value", q.Front())
|
|
||||||
}
|
|
||||||
q.PopFront()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBufferWrapReverse(t *testing.T) {
|
|
||||||
var q Deque
|
|
||||||
|
|
||||||
for i := 0; i < minCapacity; i++ {
|
|
||||||
q.PushFront(i)
|
|
||||||
}
|
|
||||||
for i := 0; i < 3; i++ {
|
|
||||||
q.PopBack()
|
|
||||||
q.PushFront(minCapacity + i)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < minCapacity; i++ {
|
|
||||||
if q.Back().(int) != i+3 {
|
|
||||||
t.Error("peek", i, "had value", q.Front())
|
|
||||||
}
|
|
||||||
q.PopBack()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLen(t *testing.T) {
|
|
||||||
var q Deque
|
|
||||||
|
|
||||||
if q.Len() != 0 {
|
|
||||||
t.Error("empty queue length not 0")
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < 1000; i++ {
|
|
||||||
q.PushBack(i)
|
|
||||||
if q.Len() != i+1 {
|
|
||||||
t.Error("adding: queue with", i, "elements has length", q.Len())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for i := 0; i < 1000; i++ {
|
|
||||||
q.PopFront()
|
|
||||||
if q.Len() != 1000-i-1 {
|
|
||||||
t.Error("removing: queue with", 1000-i-i, "elements has length", q.Len())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBack(t *testing.T) {
|
|
||||||
var q Deque
|
|
||||||
|
|
||||||
for i := 0; i < minCapacity+5; i++ {
|
|
||||||
q.PushBack(i)
|
|
||||||
if q.Back() != i {
|
|
||||||
t.Errorf("Back returned wrong value")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNew(t *testing.T) {
|
|
||||||
minCap := 64
|
|
||||||
q := New(0, minCap)
|
|
||||||
if q.Cap() != 0 {
|
|
||||||
t.Fatal("should not have allowcated mem yet")
|
|
||||||
}
|
|
||||||
q.PushBack("foo")
|
|
||||||
q.PopFront()
|
|
||||||
if q.Len() != 0 {
|
|
||||||
t.Fatal("Len() should return 0")
|
|
||||||
}
|
|
||||||
if q.Cap() != minCap {
|
|
||||||
t.Fatalf("worng capactiy expected %d, got %d", minCap, q.Cap())
|
|
||||||
}
|
|
||||||
|
|
||||||
curCap := 128
|
|
||||||
q = New(curCap, minCap)
|
|
||||||
if q.Cap() != curCap {
|
|
||||||
t.Fatalf("Cap() should return %d, got %d", curCap, q.Cap())
|
|
||||||
}
|
|
||||||
if q.Len() != 0 {
|
|
||||||
t.Fatalf("Len() should return 0")
|
|
||||||
}
|
|
||||||
q.PushBack("foo")
|
|
||||||
if q.Cap() != curCap {
|
|
||||||
t.Fatalf("Cap() should return %d, got %d", curCap, q.Cap())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkRotate(t *testing.T, size int) {
|
|
||||||
var q Deque
|
|
||||||
for i := 0; i < size; i++ {
|
|
||||||
q.PushBack(i)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < q.Len(); i++ {
|
|
||||||
x := i
|
|
||||||
for n := 0; n < q.Len(); n++ {
|
|
||||||
if q.At(n) != x {
|
|
||||||
t.Fatalf("a[%d] != %d after rotate and copy", n, x)
|
|
||||||
}
|
|
||||||
x++
|
|
||||||
if x == q.Len() {
|
|
||||||
x = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
q.Rotate(1)
|
|
||||||
if q.Back().(int) != i {
|
|
||||||
t.Fatal("wrong value during rotation")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for i := q.Len() - 1; i >= 0; i-- {
|
|
||||||
q.Rotate(-1)
|
|
||||||
if q.Front().(int) != i {
|
|
||||||
t.Fatal("wrong value during reverse rotation")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRotate(t *testing.T) {
|
|
||||||
checkRotate(t, 10)
|
|
||||||
checkRotate(t, minCapacity)
|
|
||||||
checkRotate(t, minCapacity+minCapacity/2)
|
|
||||||
|
|
||||||
var q Deque
|
|
||||||
for i := 0; i < 10; i++ {
|
|
||||||
q.PushBack(i)
|
|
||||||
}
|
|
||||||
q.Rotate(11)
|
|
||||||
if q.Front() != 1 {
|
|
||||||
t.Error("rotating 11 places should have been same as one")
|
|
||||||
}
|
|
||||||
q.Rotate(-21)
|
|
||||||
if q.Front() != 0 {
|
|
||||||
t.Error("rotating -21 places should have been same as one -1")
|
|
||||||
}
|
|
||||||
q.Rotate(q.Len())
|
|
||||||
if q.Front() != 0 {
|
|
||||||
t.Error("should not have rotated")
|
|
||||||
}
|
|
||||||
q.Clear()
|
|
||||||
q.PushBack(0)
|
|
||||||
q.Rotate(13)
|
|
||||||
if q.Front() != 0 {
|
|
||||||
t.Error("should not have rotated")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 TestSet(t *testing.T) {
|
|
||||||
var q Deque
|
|
||||||
|
|
||||||
for i := 0; i < 1000; i++ {
|
|
||||||
q.PushBack(i)
|
|
||||||
q.Set(i, i+50)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Front to back.
|
|
||||||
for j := 0; j < q.Len(); j++ {
|
|
||||||
if q.At(j).(int) != j+50 {
|
|
||||||
t.Errorf("index %d doesn't contain %d", j, j+50)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestClear(t *testing.T) {
|
|
||||||
var q Deque
|
|
||||||
|
|
||||||
for i := 0; i < 100; i++ {
|
|
||||||
q.PushBack(i)
|
|
||||||
}
|
|
||||||
if q.Len() != 100 {
|
|
||||||
t.Error("push: queue with 100 elements has length", q.Len())
|
|
||||||
}
|
|
||||||
cap := len(q.buf)
|
|
||||||
q.Clear()
|
|
||||||
if q.Len() != 0 {
|
|
||||||
t.Error("empty queue length not 0 after clear")
|
|
||||||
}
|
|
||||||
if len(q.buf) != cap {
|
|
||||||
t.Error("queue capacity changed after clear")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that there are no remaining references after Clear()
|
|
||||||
for i := 0; i < len(q.buf); i++ {
|
|
||||||
if q.buf[i] != nil {
|
|
||||||
t.Error("queue has non-nil deleted elements after Clear()")
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestInsert(t *testing.T) {
|
|
||||||
q := new(Deque)
|
|
||||||
for _, x := range "ABCDEFG" {
|
|
||||||
q.PushBack(x)
|
|
||||||
}
|
|
||||||
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" {
|
|
||||||
if q.PopFront() != x {
|
|
||||||
t.Error("expected", x, "at position", i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRemove(t *testing.T) {
|
|
||||||
q := new(Deque)
|
|
||||||
for _, x := range "ABCDEFG" {
|
|
||||||
q.PushBack(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
if remove(q, 4) != 'E' { // ABCDFG
|
|
||||||
t.Error("expected E from position 4")
|
|
||||||
}
|
|
||||||
|
|
||||||
if remove(q, 2) != 'C' { // ABDFG
|
|
||||||
t.Error("expected C at position 2")
|
|
||||||
}
|
|
||||||
if q.Back() != 'G' {
|
|
||||||
t.Error("expected G at back")
|
|
||||||
}
|
|
||||||
|
|
||||||
if remove(q, 0) != 'A' { // BDFG
|
|
||||||
t.Error("expected to remove A from front")
|
|
||||||
}
|
|
||||||
if q.Front() != 'B' {
|
|
||||||
t.Error("expected G at back")
|
|
||||||
}
|
|
||||||
|
|
||||||
if remove(q, q.Len()-1) != 'G' { // BDF
|
|
||||||
t.Error("expected to remove G from back")
|
|
||||||
}
|
|
||||||
if q.Back() != 'F' {
|
|
||||||
t.Error("expected F at back")
|
|
||||||
}
|
|
||||||
|
|
||||||
if q.Len() != 3 {
|
|
||||||
t.Error("wrong length")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFrontBackOutOfRangePanics(t *testing.T) {
|
|
||||||
const msg = "should panic when peeking empty queue"
|
|
||||||
var q Deque
|
|
||||||
assertPanics(t, msg, func() {
|
|
||||||
q.Front()
|
|
||||||
})
|
|
||||||
assertPanics(t, msg, func() {
|
|
||||||
q.Back()
|
|
||||||
})
|
|
||||||
|
|
||||||
q.PushBack(1)
|
|
||||||
q.PopFront()
|
|
||||||
|
|
||||||
assertPanics(t, msg, func() {
|
|
||||||
q.Front()
|
|
||||||
})
|
|
||||||
assertPanics(t, msg, func() {
|
|
||||||
q.Back()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPopFrontOutOfRangePanics(t *testing.T) {
|
|
||||||
var q Deque
|
|
||||||
|
|
||||||
assertPanics(t, "should panic when removing empty queue", func() {
|
|
||||||
q.PopFront()
|
|
||||||
})
|
|
||||||
|
|
||||||
q.PushBack(1)
|
|
||||||
q.PopFront()
|
|
||||||
|
|
||||||
assertPanics(t, "should panic when removing emptied queue", func() {
|
|
||||||
q.PopFront()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPopBackOutOfRangePanics(t *testing.T) {
|
|
||||||
var q Deque
|
|
||||||
|
|
||||||
assertPanics(t, "should panic when removing empty queue", func() {
|
|
||||||
q.PopBack()
|
|
||||||
})
|
|
||||||
|
|
||||||
q.PushBack(1)
|
|
||||||
q.PopBack()
|
|
||||||
|
|
||||||
assertPanics(t, "should panic when removing emptied queue", func() {
|
|
||||||
q.PopBack()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
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 TestSetOutOfRangePanics(t *testing.T) {
|
|
||||||
var q Deque
|
|
||||||
|
|
||||||
q.PushBack(1)
|
|
||||||
q.PushBack(2)
|
|
||||||
q.PushBack(3)
|
|
||||||
|
|
||||||
assertPanics(t, "should panic when negative index", func() {
|
|
||||||
q.Set(-4, 1)
|
|
||||||
})
|
|
||||||
|
|
||||||
assertPanics(t, "should panic when index greater than length", func() {
|
|
||||||
q.Set(4, 1)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestInsertOutOfRangePanics(t *testing.T) {
|
|
||||||
q := new(Deque)
|
|
||||||
|
|
||||||
assertPanics(t, "should panic when inserting out of range", func() {
|
|
||||||
insert(q, 1, "X")
|
|
||||||
})
|
|
||||||
|
|
||||||
q.PushBack("A")
|
|
||||||
|
|
||||||
assertPanics(t, "should panic when inserting at negative index", func() {
|
|
||||||
insert(q, -1, "Y")
|
|
||||||
})
|
|
||||||
|
|
||||||
assertPanics(t, "should panic when inserting out of range", func() {
|
|
||||||
insert(q, 2, "B")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRemoveOutOfRangePanics(t *testing.T) {
|
|
||||||
q := new(Deque)
|
|
||||||
|
|
||||||
assertPanics(t, "should panic when removing from empty queue", func() {
|
|
||||||
remove(q, 0)
|
|
||||||
})
|
|
||||||
|
|
||||||
q.PushBack("A")
|
|
||||||
|
|
||||||
assertPanics(t, "should panic when removing at negative index", func() {
|
|
||||||
remove(q, -1)
|
|
||||||
})
|
|
||||||
|
|
||||||
assertPanics(t, "should panic when removing out of range", func() {
|
|
||||||
remove(q, 1)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSetMinCapacity(t *testing.T) {
|
|
||||||
var q Deque
|
|
||||||
exp := uint(8)
|
|
||||||
q.SetMinCapacity(exp)
|
|
||||||
q.PushBack("A")
|
|
||||||
if q.minCap != 1<<exp {
|
|
||||||
t.Fatal("wrong minimum capacity")
|
|
||||||
}
|
|
||||||
if len(q.buf) != 1<<exp {
|
|
||||||
t.Fatal("wrong buffer size")
|
|
||||||
}
|
|
||||||
q.PopBack()
|
|
||||||
if q.minCap != 1<<exp {
|
|
||||||
t.Fatal("wrong minimum capacity")
|
|
||||||
}
|
|
||||||
if len(q.buf) != 1<<exp {
|
|
||||||
t.Fatal("wrong buffer size")
|
|
||||||
}
|
|
||||||
q.SetMinCapacity(0)
|
|
||||||
if q.minCap != minCapacity {
|
|
||||||
t.Fatal("wrong minimum capacity")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func assertPanics(t *testing.T, name string, f func()) {
|
|
||||||
defer func() {
|
|
||||||
if r := recover(); r == nil {
|
|
||||||
t.Errorf("%s: didn't panic as expected", name)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
f()
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkPushFront(b *testing.B) {
|
|
||||||
var q Deque
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
q.PushFront(i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkPushBack(b *testing.B) {
|
|
||||||
var q Deque
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
q.PushBack(i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkSerial(b *testing.B) {
|
|
||||||
var q Deque
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
q.PushBack(i)
|
|
||||||
}
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
q.PopFront()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkSerialReverse(b *testing.B) {
|
|
||||||
var q Deque
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
q.PushFront(i)
|
|
||||||
}
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
q.PopBack()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkRotate(b *testing.B) {
|
|
||||||
q := new(Deque)
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
q.PushBack(i)
|
|
||||||
}
|
|
||||||
b.ResetTimer()
|
|
||||||
// N complete rotations on length N - 1.
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
q.Rotate(b.N - 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkInsert(b *testing.B) {
|
|
||||||
q := new(Deque)
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
q.PushBack(i)
|
|
||||||
}
|
|
||||||
b.ResetTimer()
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
insert(q, q.Len()/2, -i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkRemove(b *testing.B) {
|
|
||||||
q := new(Deque)
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
q.PushBack(i)
|
|
||||||
}
|
|
||||||
b.ResetTimer()
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
remove(q, q.Len()/2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkYoyo(b *testing.B) {
|
|
||||||
var q Deque
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
for j := 0; j < 65536; j++ {
|
|
||||||
q.PushBack(j)
|
|
||||||
}
|
|
||||||
for j := 0; j < 65536; j++ {
|
|
||||||
q.PopFront()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkYoyoFixed(b *testing.B) {
|
|
||||||
var q Deque
|
|
||||||
q.SetMinCapacity(16)
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
for j := 0; j < 65536; j++ {
|
|
||||||
q.PushBack(j)
|
|
||||||
}
|
|
||||||
for j := 0; j < 65536; j++ {
|
|
||||||
q.PopFront()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// insert is used to insert an element into the middle of the queue, before the
|
|
||||||
// element at the specified index. insert(0,e) is the same as PushFront(e) and
|
|
||||||
// insert(Len(),e) is the same as PushBack(e). Complexity is constant plus
|
|
||||||
// linear in the lesser of the distances between i and either of the ends of
|
|
||||||
// the queue. Accepts only non-negative index values, and panics if index is
|
|
||||||
// out of range.
|
|
||||||
func insert(q *Deque, i int, elem interface{}) {
|
|
||||||
if i < 0 || i > q.Len() {
|
|
||||||
panic("deque: Insert() called with index out of range")
|
|
||||||
}
|
|
||||||
if i == 0 {
|
|
||||||
q.PushFront(elem)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if i == q.Len() {
|
|
||||||
q.PushBack(elem)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if i <= q.Len()/2 {
|
|
||||||
q.Rotate(i)
|
|
||||||
q.PushFront(elem)
|
|
||||||
q.Rotate(-i)
|
|
||||||
} else {
|
|
||||||
rots := q.Len() - i
|
|
||||||
q.Rotate(-rots)
|
|
||||||
q.PushBack(elem)
|
|
||||||
q.Rotate(rots)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove removes and returns an element from the middle of the queue, at the
|
|
||||||
// specified index. remove(0) is the same as PopFront() and remove(Len()-1) is
|
|
||||||
// the same as PopBack(). Complexity is constant plus linear in the lesser of
|
|
||||||
// the distances between i and either of the ends of the queue. Accepts only
|
|
||||||
// non-negative index values, and panics if index is out of range.
|
|
||||||
func remove(q *Deque, i int) interface{} {
|
|
||||||
if i < 0 || i >= q.Len() {
|
|
||||||
panic("deque: Remove() called with index out of range")
|
|
||||||
}
|
|
||||||
if i == 0 {
|
|
||||||
return q.PopFront()
|
|
||||||
}
|
|
||||||
if i == q.Len()-1 {
|
|
||||||
return q.PopBack()
|
|
||||||
}
|
|
||||||
if i <= q.Len()/2 {
|
|
||||||
q.Rotate(i)
|
|
||||||
elem := q.PopFront()
|
|
||||||
q.Rotate(-i)
|
|
||||||
return elem
|
|
||||||
}
|
|
||||||
rots := q.Len() - 1 - i
|
|
||||||
q.Rotate(-rots)
|
|
||||||
elem := q.PopBack()
|
|
||||||
q.Rotate(rots)
|
|
||||||
return elem
|
|
||||||
}
|
|
Loading…
Reference in a new issue