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  }