github.com/cilium/ebpf@v0.15.1-0.20240517100537-8079b37aa138/internal/deque.go (about) 1 package internal 2 3 import "math/bits" 4 5 // Deque implements a double ended queue. 6 type Deque[T any] struct { 7 elems []T 8 read, write uint64 9 mask uint64 10 } 11 12 // Reset clears the contents of the deque while retaining the backing buffer. 13 func (dq *Deque[T]) Reset() { 14 var zero T 15 16 for i := dq.read; i < dq.write; i++ { 17 dq.elems[i&dq.mask] = zero 18 } 19 20 dq.read, dq.write = 0, 0 21 } 22 23 func (dq *Deque[T]) Empty() bool { 24 return dq.read == dq.write 25 } 26 27 // Push adds an element to the end. 28 func (dq *Deque[T]) Push(e T) { 29 dq.Grow(1) 30 dq.elems[dq.write&dq.mask] = e 31 dq.write++ 32 } 33 34 // Shift returns the first element or the zero value. 35 func (dq *Deque[T]) Shift() T { 36 var zero T 37 38 if dq.Empty() { 39 return zero 40 } 41 42 index := dq.read & dq.mask 43 t := dq.elems[index] 44 dq.elems[index] = zero 45 dq.read++ 46 return t 47 } 48 49 // Pop returns the last element or the zero value. 50 func (dq *Deque[T]) Pop() T { 51 var zero T 52 53 if dq.Empty() { 54 return zero 55 } 56 57 dq.write-- 58 index := dq.write & dq.mask 59 t := dq.elems[index] 60 dq.elems[index] = zero 61 return t 62 } 63 64 // Grow the deque's capacity, if necessary, to guarantee space for another n 65 // elements. 66 func (dq *Deque[T]) Grow(n int) { 67 have := dq.write - dq.read 68 need := have + uint64(n) 69 if need < have { 70 panic("overflow") 71 } 72 if uint64(len(dq.elems)) >= need { 73 return 74 } 75 76 // Round up to the new power of two which is at least 8. 77 // See https://jameshfisher.com/2018/03/30/round-up-power-2/ 78 capacity := 1 << (64 - bits.LeadingZeros64(need-1)) 79 if capacity < 8 { 80 capacity = 8 81 } 82 83 elems := make([]T, have, capacity) 84 pivot := dq.read & dq.mask 85 copied := copy(elems, dq.elems[pivot:]) 86 copy(elems[copied:], dq.elems[:pivot]) 87 88 dq.elems = elems[:capacity] 89 dq.mask = uint64(capacity) - 1 90 dq.read, dq.write = 0, have 91 }