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  }