Skip to content

Commit 5ab0fa6

Browse files
authored
add slice operation functions (#40)
The following functions have been added to operate on slices of values: AppendToSlice(out []T) []T CopyInSlice([]T) CopyOutSlice([]T) int Copy(src Deque[T]) int
1 parent cf96494 commit 5ab0fa6

File tree

2 files changed

+355
-13
lines changed

2 files changed

+355
-13
lines changed

deque.go

Lines changed: 133 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ const minCapacity = 16
3030
//
3131
// d.Grow(1000)
3232
//
33-
// Any values supplied to SetBaseCap and Grow are rounded up to the nearest
33+
// Any values supplied to [SetBaseCap] and [Grow] are rounded up to the nearest
3434
// power of 2, since the Deque grows by powers of 2.
3535
type Deque[T any] struct {
3636
buf []T
@@ -58,8 +58,8 @@ func (q *Deque[T]) Len() int {
5858
}
5959

6060
// PushBack appends an element to the back of the queue. Implements FIFO when
61-
// elements are removed with PopFront, and LIFO when elements are removed with
62-
// PopBack.
61+
// elements are removed with [PopFront], and LIFO when elements are removed with
62+
// [PopBack].
6363
func (q *Deque[T]) PushBack(elem T) {
6464
q.growIfFull()
6565

@@ -80,7 +80,7 @@ func (q *Deque[T]) PushFront(elem T) {
8080
}
8181

8282
// PopFront removes and returns the element from the front of the queue.
83-
// Implements FIFO when used with PushBack. If the queue is empty, the call
83+
// Implements FIFO when used with [PushBack]. If the queue is empty, the call
8484
// panics.
8585
func (q *Deque[T]) PopFront() T {
8686
if q.count <= 0 {
@@ -121,7 +121,7 @@ func (q *Deque[T]) IterPopFront() iter.Seq[T] {
121121
}
122122

123123
// PopBack removes and returns the element from the back of the queue.
124-
// Implements LIFO when used with PushBack. If the queue is empty, the call
124+
// Implements LIFO when used with [PushBack]. If the queue is empty, the call
125125
// panics.
126126
func (q *Deque[T]) PopBack() T {
127127
if q.count <= 0 {
@@ -165,7 +165,8 @@ func (q *Deque[T]) IterPopBack() iter.Seq[T] {
165165
}
166166

167167
// Front returns the element at the front of the queue. This is the element
168-
// that would be returned by PopFront. This call panics if the queue is empty.
168+
// that would be returned by [PopFront]. This call panics if the queue is
169+
// empty.
169170
func (q *Deque[T]) Front() T {
170171
if q.count <= 0 {
171172
panic("deque: Front() called when empty")
@@ -174,7 +175,7 @@ func (q *Deque[T]) Front() T {
174175
}
175176

176177
// Back returns the element at the back of the queue. This is the element that
177-
// would be returned by PopBack. This call panics if the queue is empty.
178+
// would be returned by [PopBack]. This call panics if the queue is empty.
178179
func (q *Deque[T]) Back() T {
179180
if q.count <= 0 {
180181
panic("deque: Back() called when empty")
@@ -184,8 +185,8 @@ func (q *Deque[T]) Back() T {
184185

185186
// At returns the element at index i in the queue without removing the element
186187
// from the queue. This method accepts only non-negative index values. At(0)
187-
// refers to the first element and is the same as Front(). At(Len()-1) refers
188-
// to the last element and is the same as Back(). If the index is invalid, the
188+
// refers to the first element and is the same as [Front]. At(Len()-1) refers
189+
// to the last element and is the same as [Back]. If the index is invalid, the
189190
// call panics.
190191
//
191192
// The purpose of At is to allow Deque to serve as a more general purpose
@@ -201,7 +202,7 @@ func (q *Deque[T]) At(i int) T {
201202
}
202203

203204
// Set assigns the item to index i in the queue. Set indexes the deque the same
204-
// as At but perform the opposite operation. If the index is invalid, the call
205+
// as [At] but perform the opposite operation. If the index is invalid, the call
205206
// panics.
206207
func (q *Deque[T]) Set(i int, item T) {
207208
q.checkRange(i)
@@ -302,6 +303,125 @@ func (q *Deque[T]) Grow(n int) {
302303
}
303304
}
304305

306+
// Copy copies the contents of the given src Deque into this Deque.
307+
//
308+
// n := b.Copy(a)
309+
//
310+
// is an efficient shortcut for
311+
//
312+
// b.Clear()
313+
// n := a.Len()
314+
// b.Grow(n)
315+
// for i := 0; i < n; i++ {
316+
// b.PushBack(a.At(i))
317+
// }
318+
func (q *Deque[T]) Copy(src Deque[T]) int {
319+
q.Clear()
320+
q.Grow(src.Len())
321+
n := src.CopyOutSlice(q.buf)
322+
q.count = n
323+
q.tail = n
324+
q.head = 0
325+
return n
326+
}
327+
328+
// AppendToSlice appends from the Deque to the given slice. If the slice has
329+
// insufficient capacity to store all elements in Deque, then allocate a new
330+
// slice. Returns the resulting slice.
331+
//
332+
// out = q.AppendToSlice(out)
333+
//
334+
// is an efficient shortcut for
335+
//
336+
// for i := 0; i < q.Len(); i++ {
337+
// x = append(out, q.At(i))
338+
// }
339+
func (q *Deque[T]) AppendToSlice(out []T) []T {
340+
if q.count == 0 {
341+
return out
342+
}
343+
344+
head, tail := q.head, q.tail
345+
346+
if head >= tail {
347+
// [DEF....ABC]
348+
out = append(out, q.buf[head:]...)
349+
head = 0
350+
}
351+
return append(out, q.buf[head:tail]...)
352+
}
353+
354+
// CopyInSlice replaces the contents of Deque with all the elements from the
355+
// given slice, in. If len(in) is zero, then this is equivalent to calling
356+
// [Clear].
357+
//
358+
// q.CopyInSlice(in)
359+
//
360+
// is an efficient shortcut for
361+
//
362+
// q.Clear()
363+
// for i := range in {
364+
// q.PushBack(in[i])
365+
// }
366+
func (q *Deque[T]) CopyInSlice(in []T) {
367+
// Allocate new buffer if more space needed.
368+
if len(q.buf) < len(in) {
369+
newCap := len(q.buf)
370+
if newCap == 0 {
371+
newCap = minCapacity
372+
q.minCap = minCapacity
373+
}
374+
for newCap < len(in) {
375+
newCap <<= 1
376+
}
377+
q.buf = make([]T, newCap)
378+
} else if len(q.buf) > len(in) {
379+
q.Clear()
380+
}
381+
n := copy(q.buf, in)
382+
q.count = n
383+
q.tail = n
384+
q.head = 0
385+
}
386+
387+
// CopyOutSlice copies elements from the Deque into the given slice, up to the
388+
// size of the buffer. Returns the number of elements copied, which will be the
389+
// minimum of q.Len() and len(out).
390+
//
391+
// n := q.CopyOutSlice(out)
392+
//
393+
// is an efficient shortcut for
394+
//
395+
// n := min(len(out), q.Len())
396+
// for i := 0; i < n; i++ {
397+
// out[i] = q.At(i)
398+
// }
399+
//
400+
// This function is preferable to one that returns a copy of the internal
401+
// buffer because this allows reuse of memory receiving data, for repeated copy
402+
// operations.
403+
func (q *Deque[T]) CopyOutSlice(out []T) int {
404+
if q.count == 0 || len(out) == 0 {
405+
return 0
406+
}
407+
408+
head, tail := q.head, q.tail
409+
var n int
410+
411+
if head >= tail {
412+
// [DEF....ABC]
413+
n = copy(out, q.buf[head:])
414+
out = out[n:]
415+
if len(out) == 0 {
416+
return n
417+
}
418+
head = 0
419+
}
420+
n += copy(out, q.buf[head:tail])
421+
422+
return n
423+
}
424+
305425
// Rotate rotates the deque n steps front-to-back. If n is negative, rotates
306426
// back-to-front. Having Deque provide Rotate avoids resizing that could happen
307427
// if implementing rotation using only Pop and Push methods. If q.Len() is one
@@ -368,7 +488,7 @@ func (q *Deque[T]) Index(f func(T) bool) int {
368488

369489
// RIndex is the same as Index, but searches from Back to Front. The index
370490
// returned is from Front to Back, where index 0 is the index of the item
371-
// returned by Front().
491+
// returned by [Front].
372492
func (q *Deque[T]) RIndex(f func(T) bool) int {
373493
if q.Len() > 0 {
374494
modBits := len(q.buf) - 1
@@ -420,8 +540,8 @@ func (q *Deque[T]) Insert(at int, item T) {
420540
}
421541

422542
// Remove removes and returns an element from the middle of the queue, at the
423-
// specified index. Remove(0) is the same as PopFront() and Remove(Len()-1) is
424-
// the same as PopBack(). Accepts only non-negative index values, and panics if
543+
// specified index. Remove(0) is the same as [PopFront] and Remove(Len()-1) is
544+
// the same as [PopBack]. Accepts only non-negative index values, and panics if
425545
// index is out of range.
426546
//
427547
// Important: Deque is optimized for O(1) operations at the ends of the queue,

0 commit comments

Comments
 (0)