github.com/cilium/ebpf@v0.10.0/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 func (dq *Deque[T]) remainingCap() int { 28 return len(dq.elems) - int(dq.write-dq.read) 29 } 30 31 // Push adds an element to the end. 32 func (dq *Deque[T]) Push(e T) { 33 if dq.remainingCap() >= 1 { 34 dq.elems[dq.write&dq.mask] = e 35 dq.write++ 36 return 37 } 38 39 elems := dq.linearise(1) 40 elems = append(elems, e) 41 42 dq.elems = elems[:cap(elems)] 43 dq.mask = uint64(cap(elems)) - 1 44 dq.read, dq.write = 0, uint64(len(elems)) 45 } 46 47 // Shift returns the first element or the zero value. 48 func (dq *Deque[T]) Shift() T { 49 var zero T 50 51 if dq.Empty() { 52 return zero 53 } 54 55 index := dq.read & dq.mask 56 t := dq.elems[index] 57 dq.elems[index] = zero 58 dq.read++ 59 return t 60 } 61 62 // Pop returns the last element or the zero value. 63 func (dq *Deque[T]) Pop() T { 64 var zero T 65 66 if dq.Empty() { 67 return zero 68 } 69 70 dq.write-- 71 index := dq.write & dq.mask 72 t := dq.elems[index] 73 dq.elems[index] = zero 74 return t 75 } 76 77 // linearise the contents of the deque. 78 // 79 // The returned slice has space for at least n more elements and has power 80 // of two capacity. 81 func (dq *Deque[T]) linearise(n int) []T { 82 length := dq.write - dq.read 83 need := length + uint64(n) 84 if need < length { 85 panic("overflow") 86 } 87 88 // Round up to the new power of two which is at least 8. 89 // See https://jameshfisher.com/2018/03/30/round-up-power-2/ 90 capacity := 1 << (64 - bits.LeadingZeros64(need-1)) 91 if capacity < 8 { 92 capacity = 8 93 } 94 95 types := make([]T, length, capacity) 96 pivot := dq.read & dq.mask 97 copied := copy(types, dq.elems[pivot:]) 98 copy(types[copied:], dq.elems[:pivot]) 99 return types 100 }