├── go.mod ├── .gitignore ├── .github └── workflows │ ├── main.yml │ └── go.yml ├── LICENSE ├── doc.go ├── README.md ├── deque.go └── deque_test.go /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/sekoyo/deque 2 | 3 | go 1.18 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | 3 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 4 | *.o 5 | *.a 6 | *.so 7 | 8 | # Folders 9 | _obj 10 | _test 11 | 12 | # Architecture specific extensions/prefixes 13 | *.[568vq] 14 | [568vq].out 15 | 16 | *.cgo1.go 17 | *.cgo2.c 18 | _cgo_defun.c 19 | _cgo_gotypes.go 20 | _cgo_export.* 21 | 22 | _testmain.go 23 | 24 | *.exe 25 | *.test 26 | *.prof 27 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: golangci-lint 2 | 3 | on: 4 | push: 5 | tags: 6 | - v* 7 | branches: 8 | - master 9 | - main 10 | pull_request: 11 | 12 | jobs: 13 | 14 | golangci: 15 | name: lint 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/checkout@v2 19 | 20 | - name: golangci-lint 21 | uses: golangci/golangci-lint-action@v2 22 | -------------------------------------------------------------------------------- /.github/workflows/go.yml: -------------------------------------------------------------------------------- 1 | name: Go 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | pull_request: 7 | branches: [master] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | 15 | - name: Set up Go 16 | uses: actions/setup-go@v2 17 | with: 18 | go-version: 1.18 19 | 20 | - name: Vet 21 | run: go vet ./... 22 | 23 | - name: Build 24 | run: go build -v ./... 25 | 26 | - name: Test 27 | run: go test -v ./... -coverprofile=coverage.txt -covermode=atomic 28 | 29 | - name: Upload coverage to Codecov 30 | uses: codecov/codecov-action@v1 31 | with: 32 | files: coverage.txt 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Andrew J. Gillis 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package deque provides a fast ring-buffer deque (double-ended queue) 3 | implementation. 4 | 5 | Deque generalizes a queue and a stack, to efficiently add and remove items at 6 | either end with O(1) performance. Queue (FIFO) operations are supported using 7 | PushBack() and PopFront(). Stack (LIFO) operations are supported using 8 | PushBack() and PopBack(). 9 | 10 | Ring-buffer Performance 11 | 12 | The ring-buffer automatically resizes by 13 | powers of two, growing when additional capacity is needed and shrinking when 14 | only a quarter of the capacity is used, and uses bitwise arithmetic for all 15 | calculations. 16 | 17 | The ring-buffer implementation significantly improves memory and time 18 | performance with fewer GC pauses, compared to implementations based on slices 19 | and linked lists. 20 | 21 | For maximum speed, this deque implementation leaves concurrency safety up to 22 | the application to provide, however the application chooses, if needed at all. 23 | 24 | Reading Empty Deque 25 | 26 | Since it is OK for the deque to contain a nil value, it is necessary to either 27 | panic or return a second boolean value to indicate the deque is empty, when 28 | reading or removing an element. This deque panics when reading from an empty 29 | deque. This is a run-time check to help catch programming errors, which may be 30 | missed if a second return value is ignored. Simply check Deque.Len() before 31 | reading from the deque. 32 | 33 | */ 34 | package deque 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # deque 2 | 3 | This is a fork of [github.com/gammazero/deque](https://github.com/gammazero/deque) to switch to Generics in order to improve performance (Go 1.18+). Here are the results: 4 | 5 | #### no generics 6 | 7 | ``` 8 | go: go1.18beta1 darwin/amd64 9 | cpu: VirtualApple @ 2.50GHz 10 | BenchmarkPushFront-10 10000 25.81 ns/op 11 | BenchmarkPushBack-10 10000 40.87 ns/op 12 | BenchmarkSerial-10 10000 40.05 ns/op 13 | BenchmarkSerialReverse-10 10000 30.43 ns/op 14 | BenchmarkRotate-10 10000 30122 ns/op 15 | BenchmarkInsert-10 10000 29192 ns/op 16 | BenchmarkRemove-10 10000 13927 ns/op 17 | BenchmarkYoyo-10 10000 1801284 ns/op 18 | BenchmarkYoyoFixed-10 10000 1136005 ns/op 19 | ``` 20 | 21 | #### generics (2-3x faster) 22 | 23 | ``` 24 | go1.18beta1 darwin/amd64 25 | cpu: VirtualApple @ 2.50GHz 26 | BenchmarkPushFront-10 10000 9.846 ns/op 27 | BenchmarkPushBack-10 10000 10.04 ns/op 28 | BenchmarkSerial-10 10000 11.08 ns/op 29 | BenchmarkSerialReverse-10 10000 26.22 ns/op 30 | BenchmarkRotate-10 10000 11047 ns/op 31 | BenchmarkInsert-10 10000 15644 ns/op 32 | BenchmarkRemove-10 10000 5203 ns/op 33 | BenchmarkYoyo-10 10000 561729 ns/op 34 | BenchmarkYoyoFixed-10 10000 393723 ns/op 35 | ``` 36 | 37 | [![GoDoc](https://pkg.go.dev/badge/github.com/sekoyo/deque)](https://pkg.go.dev/github.com/sekoyo/deque) 38 | [![Build Status](https://github.com/sekoyo/deque/actions/workflows/go.yml/badge.svg)](https://github.com/sekoyo/deque/actions/workflows/go.yml) 39 | [![Go Report Card](https://goreportcard.com/badge/github.com/sekoyo/deque)](https://goreportcard.com/report/github.com/sekoyo/deque) 40 | [![codecov](https://codecov.io/gh/sekoyo/deque/branch/master/graph/badge.svg)](https://codecov.io/gh/sekoyo/deque) 41 | [![License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) 42 | 43 | Fast ring-buffer deque ([double-ended queue](https://en.wikipedia.org/wiki/Double-ended_queue)) implementation. 44 | 45 | For a pictorial description, see the [Deque diagram](https://github.com/sekoyo/deque/wiki) 46 | 47 | ## Installation 48 | 49 | ``` 50 | $ go get github.com/sekoyo/deque 51 | ``` 52 | 53 | ## Deque data structure 54 | 55 | Deque generalizes a queue and a stack, to efficiently add and remove items at either end with O(1) performance. [Queue]() (FIFO) operations are supported using `PushBack()` and `PopFront()`. [Stack]() (LIFO) operations are supported using `PushBack()` and `PopBack()`. 56 | 57 | ## Ring-buffer Performance 58 | 59 | This deque implementation is optimized for CPU and GC performance. The circular buffer automatically re-sizes by powers of two, growing when additional capacity is needed and shrinking when only a quarter of the capacity is used, and uses bitwise arithmetic for all calculations. Since growth is by powers of two, adding elements will only cause O(log n) allocations. 60 | 61 | The ring-buffer implementation improves memory and time performance with fewer GC pauses, compared to implementations based on slices and linked lists. By wrapping around the buffer, previously used space is reused, making allocation unnecessary until all buffer capacity is used. This is particularly efficient when data going into the dequeue is relatively balanced against data coming out. However, if size changes are very large and only fill and then empty then deque, the ring structure offers little benefit for memory reuse. For that usage pattern a different implementation may be preferable. 62 | 63 | For maximum speed, this deque implementation leaves concurrency safety up to the application to provide, however the application chooses, if needed at all. 64 | 65 | ## Reading Empty Deque 66 | 67 | Since it is OK for the deque to contain a nil value, it is necessary to either panic or return a second boolean value to indicate the deque is empty, when reading or removing an element. This deque panics when reading from an empty deque. This is a run-time check to help catch programming errors, which may be missed if a second return value is ignored. Simply check Deque.Len() before reading from the deque. 68 | 69 | ## Example 70 | 71 | ```go 72 | package main 73 | 74 | import ( 75 | "fmt" 76 | "github.com/sekoyo/deque" 77 | ) 78 | 79 | func main() { 80 | var q deque.Deque[string] 81 | q.PushBack("foo") 82 | q.PushBack("bar") 83 | q.PushBack("baz") 84 | 85 | fmt.Println(q.Len()) // Prints: 3 86 | fmt.Println(q.Front()) // Prints: foo 87 | fmt.Println(q.Back()) // Prints: baz 88 | 89 | q.PopFront() // remove "foo" 90 | q.PopBack() // remove "baz" 91 | 92 | q.PushFront("hello") 93 | q.PushBack("world") 94 | 95 | // Consume deque and print elements. 96 | for q.Len() != 0 { 97 | fmt.Println(q.PopFront()) 98 | } 99 | } 100 | ``` 101 | 102 | ## Uses 103 | 104 | Deque can be used as both a: 105 | 106 | - [Queue]() using `PushBack` and `PopFront` 107 | - [Stack]() using `PushBack` and `PopBack` 108 | -------------------------------------------------------------------------------- /deque.go: -------------------------------------------------------------------------------- 1 | package deque 2 | 3 | // minCapacity is the smallest capacity that deque may have. 4 | // Must be power of 2 for bitwise modulus: x % n == x & (n - 1). 5 | const minCapacity = 16 6 | 7 | // Deque represents a single instance of the deque data structure. 8 | type Deque[T any] struct { 9 | buf []T 10 | head int 11 | tail int 12 | count int 13 | minCap int 14 | } 15 | 16 | // New creates a new Deque, optionally setting the current and minimum capacity 17 | // when non-zero values are given for these. 18 | // 19 | // To create a Deque with capacity to store 2048 items without resizing, and 20 | // that will not resize below space for 32 items when removing items: 21 | // d := deque.New(2048, 32) 22 | // 23 | // To create a Deque that has not yet allocated memory, but after it does will 24 | // never resize to have space for less than 64 items: 25 | // d := deque.New(0, 64) 26 | // 27 | // Note that any values supplied here are rounded up to the nearest power of 2. 28 | func New[T any](size ...int) *Deque[T] { 29 | var capacity, minimum int 30 | if len(size) >= 1 { 31 | capacity = size[0] 32 | if len(size) >= 2 { 33 | minimum = size[1] 34 | } 35 | } 36 | 37 | minCap := minCapacity 38 | for minCap < minimum { 39 | minCap <<= 1 40 | } 41 | 42 | var buf []T 43 | if capacity != 0 { 44 | bufSize := minCap 45 | for bufSize < capacity { 46 | bufSize <<= 1 47 | } 48 | buf = make([]T, bufSize) 49 | } 50 | 51 | return &Deque[T]{ 52 | buf: buf, 53 | minCap: minCap, 54 | } 55 | } 56 | 57 | // Cap returns the current capacity of the Deque. 58 | func (q *Deque[T]) Cap() int { 59 | if q == nil { 60 | return 0 61 | } 62 | return len(q.buf) 63 | } 64 | 65 | // Len returns the number of elements currently stored in the queue. 66 | func (q *Deque[T]) Len() int { 67 | if q == nil { 68 | return 0 69 | } 70 | return q.count 71 | } 72 | 73 | // PushBack appends an element to the back of the queue. Implements FIFO when 74 | // elements are removed with PopFront(), and LIFO when elements are removed 75 | // with PopBack(). 76 | func (q *Deque[T]) PushBack(elem T) { 77 | q.growIfFull() 78 | 79 | q.buf[q.tail] = elem 80 | // Calculate new tail position. 81 | q.tail = q.next(q.tail) 82 | q.count++ 83 | } 84 | 85 | // PushFront prepends an element to the front of the queue. 86 | func (q *Deque[T]) PushFront(elem T) { 87 | q.growIfFull() 88 | 89 | // Calculate new head position. 90 | q.head = q.prev(q.head) 91 | q.buf[q.head] = elem 92 | q.count++ 93 | } 94 | 95 | // PopFront removes and returns the element from the front of the queue. 96 | // Implements FIFO when used with PushBack(). If the queue is empty, the call 97 | // panics. 98 | func (q *Deque[T]) PopFront() T { 99 | if q.count <= 0 { 100 | panic("deque: PopFront() called on empty queue") 101 | } 102 | ret := q.buf[q.head] 103 | var empty T 104 | q.buf[q.head] = empty 105 | // Calculate new head position. 106 | q.head = q.next(q.head) 107 | q.count-- 108 | 109 | q.shrinkIfExcess() 110 | return ret 111 | } 112 | 113 | // PopBack removes and returns the element from the back of the queue. 114 | // Implements LIFO when used with PushBack(). If the queue is empty, the call 115 | // panics. 116 | func (q *Deque[T]) PopBack() T { 117 | if q.count <= 0 { 118 | panic("deque: PopBack() called on empty queue") 119 | } 120 | 121 | // Calculate new tail position 122 | q.tail = q.prev(q.tail) 123 | 124 | // Remove value at tail. 125 | ret := q.buf[q.tail] 126 | var empty T 127 | q.buf[q.tail] = empty 128 | q.count-- 129 | 130 | q.shrinkIfExcess() 131 | return ret 132 | } 133 | 134 | // Front returns the element at the front of the queue. This is the element 135 | // that would be returned by PopFront(). This call panics if the queue is 136 | // empty. 137 | func (q *Deque[T]) Front() T { 138 | if q.count <= 0 { 139 | panic("deque: Front() called when empty") 140 | } 141 | return q.buf[q.head] 142 | } 143 | 144 | // Back returns the element at the back of the queue. This is the element 145 | // that would be returned by PopBack(). This call panics if the queue is 146 | // empty. 147 | func (q *Deque[T]) Back() T { 148 | if q.count <= 0 { 149 | panic("deque: Back() called when empty") 150 | } 151 | return q.buf[q.prev(q.tail)] 152 | } 153 | 154 | // At returns the element at index i in the queue without removing the element 155 | // from the queue. This method accepts only non-negative index values. At(0) 156 | // refers to the first element and is the same as Front(). At(Len()-1) refers 157 | // to the last element and is the same as Back(). If the index is invalid, the 158 | // call panics. 159 | // 160 | // The purpose of At is to allow Deque to serve as a more general purpose 161 | // circular buffer, where items are only added to and removed from the ends of 162 | // the deque, but may be read from any place within the deque. Consider the 163 | // case of a fixed-size circular log buffer: A new entry is pushed onto one end 164 | // and when full the oldest is popped from the other end. All the log entries 165 | // in the buffer must be readable without altering the buffer contents. 166 | func (q *Deque[T]) At(i int) T { 167 | if i < 0 || i >= q.count { 168 | panic("deque: At() called with index out of range") 169 | } 170 | // bitwise modulus 171 | return q.buf[(q.head+i)&(len(q.buf)-1)] 172 | } 173 | 174 | // Set puts the element at index i in the queue. Set shares the same purpose 175 | // than At() but perform the opposite operation. The index i is the same 176 | // index defined by At(). If the index is invalid, the call panics. 177 | func (q *Deque[T]) Set(i int, elem T) { 178 | if i < 0 || i >= q.count { 179 | panic("deque: Set() called with index out of range") 180 | } 181 | // bitwise modulus 182 | q.buf[(q.head+i)&(len(q.buf)-1)] = elem 183 | } 184 | 185 | // Clear removes all elements from the queue, but retains the current capacity. 186 | // This is useful when repeatedly reusing the queue at high frequency to avoid 187 | // GC during reuse. The queue will not be resized smaller as long as items are 188 | // only added. Only when items are removed is the queue subject to getting 189 | // resized smaller. 190 | func (q *Deque[T]) Clear() { 191 | // bitwise modulus 192 | modBits := len(q.buf) - 1 193 | for h := q.head; h != q.tail; h = (h + 1) & modBits { 194 | var empty T 195 | q.buf[h] = empty 196 | } 197 | q.head = 0 198 | q.tail = 0 199 | q.count = 0 200 | } 201 | 202 | // Rotate rotates the deque n steps front-to-back. If n is negative, rotates 203 | // back-to-front. Having Deque provide Rotate() avoids resizing that could 204 | // happen if implementing rotation using only Pop and Push methods. 205 | func (q *Deque[T]) Rotate(n int) { 206 | if q.Len() <= 1 { 207 | return 208 | } 209 | // Rotating a multiple of q.count is same as no rotation. 210 | n %= q.count 211 | if n == 0 { 212 | return 213 | } 214 | 215 | modBits := len(q.buf) - 1 216 | // If no empty space in buffer, only move head and tail indexes. 217 | if q.head == q.tail { 218 | // Calculate new head and tail using bitwise modulus. 219 | q.head = (q.head + n) & modBits 220 | q.tail = (q.tail + n) & modBits 221 | return 222 | } 223 | 224 | if n < 0 { 225 | // Rotate back to front. 226 | for ; n < 0; n++ { 227 | // Calculate new head and tail using bitwise modulus. 228 | q.head = (q.head - 1) & modBits 229 | q.tail = (q.tail - 1) & modBits 230 | // Put tail value at head and remove value at tail. 231 | q.buf[q.head] = q.buf[q.tail] 232 | var empty T 233 | q.buf[q.tail] = empty 234 | } 235 | return 236 | } 237 | 238 | // Rotate front to back. 239 | for ; n > 0; n-- { 240 | // Put head value at tail and remove value at head. 241 | q.buf[q.tail] = q.buf[q.head] 242 | var empty T 243 | q.buf[q.head] = empty 244 | // Calculate new head and tail using bitwise modulus. 245 | q.head = (q.head + 1) & modBits 246 | q.tail = (q.tail + 1) & modBits 247 | } 248 | } 249 | 250 | // SetMinCapacity sets a minimum capacity of 2^minCapacityExp. If the value of 251 | // the minimum capacity is less than or equal to the minimum allowed, then 252 | // capacity is set to the minimum allowed. This may be called at anytime to 253 | // set a new minimum capacity. 254 | // 255 | // Setting a larger minimum capacity may be used to prevent resizing when the 256 | // number of stored items changes frequently across a wide range. 257 | func (q *Deque[T]) SetMinCapacity(minCapacityExp uint) { 258 | if 1< minCapacity { 259 | q.minCap = 1 << minCapacityExp 260 | } else { 261 | q.minCap = minCapacity 262 | } 263 | } 264 | 265 | // prev returns the previous buffer position wrapping around buffer. 266 | func (q *Deque[T]) prev(i int) int { 267 | return (i - 1) & (len(q.buf) - 1) // bitwise modulus 268 | } 269 | 270 | // next returns the next buffer position wrapping around buffer. 271 | func (q *Deque[T]) next(i int) int { 272 | return (i + 1) & (len(q.buf) - 1) // bitwise modulus 273 | } 274 | 275 | // growIfFull resizes up if the buffer is full. 276 | func (q *Deque[T]) growIfFull() { 277 | if q.count != len(q.buf) { 278 | return 279 | } 280 | if len(q.buf) == 0 { 281 | if q.minCap == 0 { 282 | q.minCap = minCapacity 283 | } 284 | q.buf = make([]T, q.minCap) 285 | return 286 | } 287 | q.resize() 288 | } 289 | 290 | // shrinkIfExcess resize down if the buffer 1/4 full. 291 | func (q *Deque[T]) shrinkIfExcess() { 292 | if len(q.buf) > q.minCap && (q.count<<2) == len(q.buf) { 293 | q.resize() 294 | } 295 | } 296 | 297 | // resize resizes the deque to fit exactly twice its current contents. This is 298 | // used to grow the queue when it is full, and also to shrink it when it is 299 | // only a quarter full. 300 | func (q *Deque[T]) resize() { 301 | newBuf := make([]T, q.count<<1) 302 | if q.tail > q.head { 303 | copy(newBuf, q.buf[q.head:q.tail]) 304 | } else { 305 | n := copy(newBuf, q.buf[q.head:]) 306 | copy(newBuf[n:], q.buf[:q.tail]) 307 | } 308 | 309 | q.head = 0 310 | q.tail = q.count 311 | q.buf = newBuf 312 | } 313 | -------------------------------------------------------------------------------- /deque_test.go: -------------------------------------------------------------------------------- 1 | package deque 2 | 3 | import "testing" 4 | 5 | func TestEmpty(t *testing.T) { 6 | var q Deque[string] 7 | if q.Len() != 0 { 8 | t.Error("q.Len() =", q.Len(), "expect 0") 9 | } 10 | } 11 | 12 | func TestNil(t *testing.T) { 13 | var q *Deque[string] 14 | if q.Len() != 0 { 15 | t.Error("expected q.Len() == 0") 16 | } 17 | if q.Cap() != 0 { 18 | t.Error("expected q.Cap() == 0") 19 | } 20 | } 21 | 22 | func TestFrontBack(t *testing.T) { 23 | var q Deque[string] 24 | q.PushBack("foo") 25 | q.PushBack("bar") 26 | q.PushBack("baz") 27 | if q.Front() != "foo" { 28 | t.Error("wrong value at front of queue") 29 | } 30 | if q.Back() != "baz" { 31 | t.Error("wrong value at back of queue") 32 | } 33 | 34 | if q.PopFront() != "foo" { 35 | t.Error("wrong value removed from front of queue") 36 | } 37 | if q.Front() != "bar" { 38 | t.Error("wrong value remaining at front of queue") 39 | } 40 | if q.Back() != "baz" { 41 | t.Error("wrong value remaining at back of queue") 42 | } 43 | 44 | if q.PopBack() != "baz" { 45 | t.Error("wrong value removed from back of queue") 46 | } 47 | if q.Front() != "bar" { 48 | t.Error("wrong value remaining at front of queue") 49 | } 50 | if q.Back() != "bar" { 51 | t.Error("wrong value remaining at back of queue") 52 | } 53 | } 54 | 55 | func TestGrowShrinkBack(t *testing.T) { 56 | var q Deque[int] 57 | size := minCapacity * 2 58 | 59 | for i := 0; i < size; i++ { 60 | if q.Len() != i { 61 | t.Error("q.Len() =", q.Len(), "expected", i) 62 | } 63 | q.PushBack(i) 64 | } 65 | bufLen := len(q.buf) 66 | 67 | // Remove from back. 68 | for i := size; i > 0; i-- { 69 | if q.Len() != i { 70 | t.Error("q.Len() =", q.Len(), "expected", i) 71 | } 72 | x := q.PopBack() 73 | if x != i-1 { 74 | t.Error("q.PopBack() =", x, "expected", i-1) 75 | } 76 | } 77 | if q.Len() != 0 { 78 | t.Error("q.Len() =", q.Len(), "expected 0") 79 | } 80 | if len(q.buf) == bufLen { 81 | t.Error("queue buffer did not shrink") 82 | } 83 | } 84 | 85 | func TestGrowShrinkFront(t *testing.T) { 86 | var q Deque[int] 87 | size := minCapacity * 2 88 | 89 | for i := 0; i < size; i++ { 90 | if q.Len() != i { 91 | t.Error("q.Len() =", q.Len(), "expected", i) 92 | } 93 | q.PushBack(i) 94 | } 95 | bufLen := len(q.buf) 96 | 97 | // Remove from Front 98 | for i := 0; i < size; i++ { 99 | if q.Len() != size-i { 100 | t.Error("q.Len() =", q.Len(), "expected", minCapacity*2-i) 101 | } 102 | x := q.PopFront() 103 | if x != i { 104 | t.Error("q.PopBack() =", x, "expected", i) 105 | } 106 | } 107 | if q.Len() != 0 { 108 | t.Error("q.Len() =", q.Len(), "expected 0") 109 | } 110 | if len(q.buf) == bufLen { 111 | t.Error("queue buffer did not shrink") 112 | } 113 | } 114 | 115 | func TestSimple(t *testing.T) { 116 | var q Deque[int] 117 | 118 | for i := 0; i < minCapacity; i++ { 119 | q.PushBack(i) 120 | } 121 | if q.Front() != 0 { 122 | t.Fatalf("expected 0 at front, got %d", q.Front()) 123 | } 124 | if q.Back() != minCapacity-1 { 125 | t.Fatalf("expected %d at back, got %d", minCapacity-1, q.Back()) 126 | } 127 | 128 | for i := 0; i < minCapacity; i++ { 129 | if q.Front() != i { 130 | t.Error("peek", i, "had value", q.Front()) 131 | } 132 | x := q.PopFront() 133 | if x != i { 134 | t.Error("remove", i, "had value", x) 135 | } 136 | } 137 | 138 | q.Clear() 139 | for i := 0; i < minCapacity; i++ { 140 | q.PushFront(i) 141 | } 142 | for i := minCapacity - 1; i >= 0; i-- { 143 | x := q.PopFront() 144 | if x != i { 145 | t.Error("remove", i, "had value", x) 146 | } 147 | } 148 | } 149 | 150 | func TestBufferWrap(t *testing.T) { 151 | var q Deque[int] 152 | 153 | for i := 0; i < minCapacity; i++ { 154 | q.PushBack(i) 155 | } 156 | 157 | for i := 0; i < 3; i++ { 158 | q.PopFront() 159 | q.PushBack(minCapacity + i) 160 | } 161 | 162 | for i := 0; i < minCapacity; i++ { 163 | if q.Front() != i+3 { 164 | t.Error("peek", i, "had value", q.Front()) 165 | } 166 | q.PopFront() 167 | } 168 | } 169 | 170 | func TestBufferWrapReverse(t *testing.T) { 171 | var q Deque[int] 172 | 173 | for i := 0; i < minCapacity; i++ { 174 | q.PushFront(i) 175 | } 176 | for i := 0; i < 3; i++ { 177 | q.PopBack() 178 | q.PushFront(minCapacity + i) 179 | } 180 | 181 | for i := 0; i < minCapacity; i++ { 182 | if q.Back() != i+3 { 183 | t.Error("peek", i, "had value", q.Front()) 184 | } 185 | q.PopBack() 186 | } 187 | } 188 | 189 | func TestLen(t *testing.T) { 190 | var q Deque[int] 191 | 192 | if q.Len() != 0 { 193 | t.Error("empty queue length not 0") 194 | } 195 | 196 | for i := 0; i < 1000; i++ { 197 | q.PushBack(i) 198 | if q.Len() != i+1 { 199 | t.Error("adding: queue with", i, "elements has length", q.Len()) 200 | } 201 | } 202 | for i := 0; i < 1000; i++ { 203 | q.PopFront() 204 | if q.Len() != 1000-i-1 { 205 | t.Error("removing: queue with", 1000-i-i, "elements has length", q.Len()) 206 | } 207 | } 208 | } 209 | 210 | func TestBack(t *testing.T) { 211 | var q Deque[int] 212 | 213 | for i := 0; i < minCapacity+5; i++ { 214 | q.PushBack(i) 215 | if q.Back() != i { 216 | t.Errorf("Back returned wrong value") 217 | } 218 | } 219 | } 220 | 221 | func TestNew(t *testing.T) { 222 | minCap := 64 223 | q := New[string](0, minCap) 224 | if q.Cap() != 0 { 225 | t.Fatal("should not have allowcated mem yet") 226 | } 227 | q.PushBack("foo") 228 | q.PopFront() 229 | if q.Len() != 0 { 230 | t.Fatal("Len() should return 0") 231 | } 232 | if q.Cap() != minCap { 233 | t.Fatalf("worng capactiy expected %d, got %d", minCap, q.Cap()) 234 | } 235 | 236 | curCap := 128 237 | q = New[string](curCap, minCap) 238 | if q.Cap() != curCap { 239 | t.Fatalf("Cap() should return %d, got %d", curCap, q.Cap()) 240 | } 241 | if q.Len() != 0 { 242 | t.Fatalf("Len() should return 0") 243 | } 244 | q.PushBack("foo") 245 | if q.Cap() != curCap { 246 | t.Fatalf("Cap() should return %d, got %d", curCap, q.Cap()) 247 | } 248 | } 249 | 250 | func checkRotate(t *testing.T, size int) { 251 | var q Deque[int] 252 | for i := 0; i < size; i++ { 253 | q.PushBack(i) 254 | } 255 | 256 | for i := 0; i < q.Len(); i++ { 257 | x := i 258 | for n := 0; n < q.Len(); n++ { 259 | if q.At(n) != x { 260 | t.Fatalf("a[%d] != %d after rotate and copy", n, x) 261 | } 262 | x++ 263 | if x == q.Len() { 264 | x = 0 265 | } 266 | } 267 | q.Rotate(1) 268 | if q.Back() != i { 269 | t.Fatal("wrong value during rotation") 270 | } 271 | } 272 | for i := q.Len() - 1; i >= 0; i-- { 273 | q.Rotate(-1) 274 | if q.Front() != i { 275 | t.Fatal("wrong value during reverse rotation") 276 | } 277 | } 278 | } 279 | 280 | func TestRotate(t *testing.T) { 281 | checkRotate(t, 10) 282 | checkRotate(t, minCapacity) 283 | checkRotate(t, minCapacity+minCapacity/2) 284 | 285 | var q Deque[int] 286 | for i := 0; i < 10; i++ { 287 | q.PushBack(i) 288 | } 289 | q.Rotate(11) 290 | if q.Front() != 1 { 291 | t.Error("rotating 11 places should have been same as one") 292 | } 293 | q.Rotate(-21) 294 | if q.Front() != 0 { 295 | t.Error("rotating -21 places should have been same as one -1") 296 | } 297 | q.Rotate(q.Len()) 298 | if q.Front() != 0 { 299 | t.Error("should not have rotated") 300 | } 301 | q.Clear() 302 | q.PushBack(0) 303 | q.Rotate(13) 304 | if q.Front() != 0 { 305 | t.Error("should not have rotated") 306 | } 307 | } 308 | 309 | func TestAt(t *testing.T) { 310 | var q Deque[int] 311 | 312 | for i := 0; i < 1000; i++ { 313 | q.PushBack(i) 314 | } 315 | 316 | // Front to back. 317 | for j := 0; j < q.Len(); j++ { 318 | if q.At(j) != j { 319 | t.Errorf("index %d doesn't contain %d", j, j) 320 | } 321 | } 322 | 323 | // Back to front 324 | for j := 1; j <= q.Len(); j++ { 325 | if q.At(q.Len()-j) != q.Len()-j { 326 | t.Errorf("index %d doesn't contain %d", q.Len()-j, q.Len()-j) 327 | } 328 | } 329 | } 330 | 331 | func TestSet(t *testing.T) { 332 | var q Deque[int] 333 | 334 | for i := 0; i < 1000; i++ { 335 | q.PushBack(i) 336 | q.Set(i, i+50) 337 | } 338 | 339 | // Front to back. 340 | for j := 0; j < q.Len(); j++ { 341 | if q.At(j) != j+50 { 342 | t.Errorf("index %d doesn't contain %d", j, j+50) 343 | } 344 | } 345 | } 346 | 347 | func TestClear(t *testing.T) { 348 | var q Deque[int] 349 | 350 | for i := 0; i < 100; i++ { 351 | q.PushBack(i) 352 | } 353 | if q.Len() != 100 { 354 | t.Error("push: queue with 100 elements has length", q.Len()) 355 | } 356 | cap := len(q.buf) 357 | q.Clear() 358 | if q.Len() != 0 { 359 | t.Error("empty queue length not 0 after clear") 360 | } 361 | if len(q.buf) != cap { 362 | t.Error("queue capacity changed after clear") 363 | } 364 | 365 | // Check that there are no remaining references after Clear() 366 | for i := 0; i < len(q.buf); i++ { 367 | if q.buf[i] != 0 { 368 | t.Error("queue has non-nil deleted elements after Clear()") 369 | break 370 | } 371 | } 372 | } 373 | 374 | func TestInsert(t *testing.T) { 375 | q := new(Deque[rune]) 376 | for _, x := range "ABCDEFG" { 377 | q.PushBack(x) 378 | } 379 | insert(q, 4, 'x') // ABCDxEFG 380 | if q.At(4) != 'x' { 381 | t.Error("expected x at position 4") 382 | } 383 | 384 | insert(q, 2, 'y') // AByCDxEFG 385 | if q.At(2) != 'y' { 386 | t.Error("expected y at position 2") 387 | } 388 | if q.At(5) != 'x' { 389 | t.Error("expected x at position 5") 390 | } 391 | 392 | insert(q, 0, 'b') // bAByCDxEFG 393 | if q.Front() != 'b' { 394 | t.Error("expected b inserted at front") 395 | } 396 | 397 | insert(q, q.Len(), 'e') // bAByCDxEFGe 398 | 399 | for i, x := range "bAByCDxEFGe" { 400 | if q.PopFront() != x { 401 | t.Error("expected", x, "at position", i) 402 | } 403 | } 404 | } 405 | 406 | func TestRemove(t *testing.T) { 407 | q := new(Deque[rune]) 408 | for _, x := range "ABCDEFG" { 409 | q.PushBack(x) 410 | } 411 | 412 | if remove(q, 4) != 'E' { // ABCDFG 413 | t.Error("expected E from position 4") 414 | } 415 | 416 | if remove(q, 2) != 'C' { // ABDFG 417 | t.Error("expected C at position 2") 418 | } 419 | if q.Back() != 'G' { 420 | t.Error("expected G at back") 421 | } 422 | 423 | if remove(q, 0) != 'A' { // BDFG 424 | t.Error("expected to remove A from front") 425 | } 426 | if q.Front() != 'B' { 427 | t.Error("expected G at back") 428 | } 429 | 430 | if remove(q, q.Len()-1) != 'G' { // BDF 431 | t.Error("expected to remove G from back") 432 | } 433 | if q.Back() != 'F' { 434 | t.Error("expected F at back") 435 | } 436 | 437 | if q.Len() != 3 { 438 | t.Error("wrong length") 439 | } 440 | } 441 | 442 | func TestFrontBackOutOfRangePanics(t *testing.T) { 443 | const msg = "should panic when peeking empty queue" 444 | var q Deque[int] 445 | assertPanics(t, msg, func() { 446 | q.Front() 447 | }) 448 | assertPanics(t, msg, func() { 449 | q.Back() 450 | }) 451 | 452 | q.PushBack(1) 453 | q.PopFront() 454 | 455 | assertPanics(t, msg, func() { 456 | q.Front() 457 | }) 458 | assertPanics(t, msg, func() { 459 | q.Back() 460 | }) 461 | } 462 | 463 | func TestPopFrontOutOfRangePanics(t *testing.T) { 464 | var q Deque[int] 465 | 466 | assertPanics(t, "should panic when removing empty queue", func() { 467 | q.PopFront() 468 | }) 469 | 470 | q.PushBack(1) 471 | q.PopFront() 472 | 473 | assertPanics(t, "should panic when removing emptied queue", func() { 474 | q.PopFront() 475 | }) 476 | } 477 | 478 | func TestPopBackOutOfRangePanics(t *testing.T) { 479 | var q Deque[int] 480 | 481 | assertPanics(t, "should panic when removing empty queue", func() { 482 | q.PopBack() 483 | }) 484 | 485 | q.PushBack(1) 486 | q.PopBack() 487 | 488 | assertPanics(t, "should panic when removing emptied queue", func() { 489 | q.PopBack() 490 | }) 491 | } 492 | 493 | func TestAtOutOfRangePanics(t *testing.T) { 494 | var q Deque[int] 495 | 496 | q.PushBack(1) 497 | q.PushBack(2) 498 | q.PushBack(3) 499 | 500 | assertPanics(t, "should panic when negative index", func() { 501 | q.At(-4) 502 | }) 503 | 504 | assertPanics(t, "should panic when index greater than length", func() { 505 | q.At(4) 506 | }) 507 | } 508 | 509 | func TestSetOutOfRangePanics(t *testing.T) { 510 | var q Deque[int] 511 | 512 | q.PushBack(1) 513 | q.PushBack(2) 514 | q.PushBack(3) 515 | 516 | assertPanics(t, "should panic when negative index", func() { 517 | q.Set(-4, 1) 518 | }) 519 | 520 | assertPanics(t, "should panic when index greater than length", func() { 521 | q.Set(4, 1) 522 | }) 523 | } 524 | 525 | func TestInsertOutOfRangePanics(t *testing.T) { 526 | q := new(Deque[string]) 527 | 528 | assertPanics(t, "should panic when inserting out of range", func() { 529 | insert(q, 1, "X") 530 | }) 531 | 532 | q.PushBack("A") 533 | 534 | assertPanics(t, "should panic when inserting at negative index", func() { 535 | insert(q, -1, "Y") 536 | }) 537 | 538 | assertPanics(t, "should panic when inserting out of range", func() { 539 | insert(q, 2, "B") 540 | }) 541 | } 542 | 543 | func TestRemoveOutOfRangePanics(t *testing.T) { 544 | q := new(Deque[string]) 545 | 546 | assertPanics(t, "should panic when removing from empty queue", func() { 547 | remove(q, 0) 548 | }) 549 | 550 | q.PushBack("A") 551 | 552 | assertPanics(t, "should panic when removing at negative index", func() { 553 | remove(q, -1) 554 | }) 555 | 556 | assertPanics(t, "should panic when removing out of range", func() { 557 | remove(q, 1) 558 | }) 559 | } 560 | 561 | func TestSetMinCapacity(t *testing.T) { 562 | var q Deque[string] 563 | exp := uint(8) 564 | q.SetMinCapacity(exp) 565 | q.PushBack("A") 566 | if q.minCap != 1< q.Len() { 696 | panic("deque: Insert() called with index out of range") 697 | } 698 | if i == 0 { 699 | q.PushFront(elem) 700 | return 701 | } 702 | if i == q.Len() { 703 | q.PushBack(elem) 704 | return 705 | } 706 | if i <= q.Len()/2 { 707 | q.Rotate(i) 708 | q.PushFront(elem) 709 | q.Rotate(-i) 710 | } else { 711 | rots := q.Len() - i 712 | q.Rotate(-rots) 713 | q.PushBack(elem) 714 | q.Rotate(rots) 715 | } 716 | } 717 | 718 | // remove removes and returns an element from the middle of the queue, at the 719 | // specified index. remove(0) is the same as PopFront() and remove(Len()-1) is 720 | // the same as PopBack(). Complexity is constant plus linear in the lesser of 721 | // the distances between i and either of the ends of the queue. Accepts only 722 | // non-negative index values, and panics if index is out of range. 723 | func remove[T any](q *Deque[T], i int) T { 724 | if i < 0 || i >= q.Len() { 725 | panic("deque: Remove() called with index out of range") 726 | } 727 | if i == 0 { 728 | return q.PopFront() 729 | } 730 | if i == q.Len()-1 { 731 | return q.PopBack() 732 | } 733 | if i <= q.Len()/2 { 734 | q.Rotate(i) 735 | elem := q.PopFront() 736 | q.Rotate(-i) 737 | return elem 738 | } 739 | rots := q.Len() - 1 - i 740 | q.Rotate(-rots) 741 | elem := q.PopBack() 742 | q.Rotate(rots) 743 | return elem 744 | } 745 | --------------------------------------------------------------------------------