aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRose Hogenson <rosehogenson@posteo.net>2025-04-05 17:13:22 -0700
committerRose Hogenson <rosehogenson@posteo.net>2025-04-05 17:13:22 -0700
commit9e21d75e8d13763bfdca8e11925bbef605042cbe (patch)
tree2865db0412189b3e229bf37d4b3d2096b3454bbf
parentdfc639535656e0f53500222dc1bbe392175f9cb4 (diff)
downloaddeque-9e21d75e8d13763bfdca8e11925bbef605042cbe.tar.zst
Add more methods
-rw-r--r--vecdeque.go34
-rw-r--r--vecdeque_test.go41
2 files changed, 70 insertions, 5 deletions
diff --git a/vecdeque.go b/vecdeque.go
index 94d64da..5d6cc92 100644
--- a/vecdeque.go
+++ b/vecdeque.go
@@ -100,6 +100,23 @@ func (q *DQ[T]) PushBack(values ...T) {
q.buf = q.buf[:len(q.buf)+len(values)]
}
+// Reset empties the deque, retaining the underlying storage for use by
+// future pushes.
+func (q *DQ[T]) Reset() {
+ q.buf = q.buf[:0]
+}
+
+// AvailableBuffer returns an empty slice with q.Cap()-q.Len() capacity. This
+// slice is intended to be appended to and passed to an immediately succeeding
+// DQ.PushBack call. The slice is only valid until the next push operation on q.
+func (q *DQ[T]) AvailableBuffer() []T {
+ endIdx := q.toPhysicalIdx(len(q.buf))
+ if endIdx <= q.head {
+ return q.buf[endIdx:endIdx:q.head]
+ }
+ return q.buf[endIdx:endIdx]
+}
+
// Grow makes space for at least n more elements to be inserted in the given
// deque without reallocation.
func (q *DQ[T]) Grow(n int) {
@@ -151,7 +168,7 @@ func (q *DQ[T]) Grow(n int) {
// any elements.
func (q *DQ[T]) All() func(func(int, T) bool) {
return func(yield func(int, T) bool) {
- for i := range q.Len() {
+ for i := range len(q.buf) {
if !yield(i, q.Get(i)) {
return
}
@@ -159,14 +176,21 @@ func (q *DQ[T]) All() func(func(int, T) bool) {
}
}
-// PopAll returns an iterator that consumes all the values in the deque, leaving
-// it empty.
+// PopAll empties the deque and returns an iterator over the popped elements.
+// It's not safe to modify the deque while iterating using PopAll.
func (q *DQ[T]) PopAll() func(func(T) bool) {
+ n := len(q.buf)
+ q.buf = q.buf[:0]
return func(yield func(T) bool) {
- for val, ok := q.PopFront(); ok; val, ok = q.PopFront() {
- if !yield(val) {
+ endIdx := q.toPhysicalIdx(n)
+ for i := q.head; ; {
+ if !yield(q.buf[:cap(q.buf)][i]) {
return
}
+ i = q.wrapAdd(i, 1)
+ if i == endIdx {
+ break
+ }
}
}
}
diff --git a/vecdeque_test.go b/vecdeque_test.go
index 527c46c..a66fff4 100644
--- a/vecdeque_test.go
+++ b/vecdeque_test.go
@@ -1,6 +1,8 @@
package vecdeque
import (
+ "bytes"
+ "fmt"
"slices"
"testing"
)
@@ -242,7 +244,22 @@ func TestPopFrontPushFront(t *testing.T) {
}
}
+func TestReset(t *testing.T) {
+ t.Parallel()
+
+ q := From([]int{1, 2, 3, 4, 5})
+ q.Reset()
+ if got, want := q.Len(), 0; got != want {
+ t.Errorf("After Reset() Len() = %d, want %d", got, want)
+ }
+ if got, want := q.Cap(), 5; got != want {
+ t.Errorf("After Reset() Cap() = %d, want %d", got, want)
+ }
+}
+
func TestPopAll(t *testing.T) {
+ t.Parallel()
+
q := From([]int{1, 2, 3})
got := make([]int, 0, q.Len())
for x := range q.PopAll() {
@@ -256,3 +273,27 @@ func TestPopAll(t *testing.T) {
t.Errorf("PopAll() returned values %d, want %d", got, want)
}
}
+
+func TestAvailableBuffer(t *testing.T) {
+ t.Parallel()
+
+ const cap = 10
+ q := WithCapacity[byte](cap)
+ q.PushBack(append(q.AvailableBuffer(), []byte(" ")...)...)
+ q.PushBack(fmt.Appendf(q.AvailableBuffer(), "%d", 12345)...)
+ for range 5 {
+ q.PopFront()
+ }
+ q.PushBack(fmt.Appendf(q.AvailableBuffer(), "%d", 67890)...)
+ if got, want := q.Cap(), cap; got != want {
+ t.Errorf("Cap() = %d, want %d", got, want)
+ }
+ got := make([]byte, q.Len())
+ for i, x := range q.All() {
+ got[i] = x
+ }
+ want := []byte("1234567890")
+ if !bytes.Equal(got, want) {
+ t.Errorf("Incorrect content after appending to AvailableBuffer, got %d want %d", got, want)
+ }
+}