github.com/searKing/golang/go@v1.2.74/exp/container/queue/queue.go (about)

     1  // Copyright 2022 The searKing Author. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package queue
     6  
     7  // A Queue is a queue of FIFO, not a deque.
     8  type Queue[E any] struct {
     9  	// This is a queue, not a deque.
    10  	// It is split into two stages - head[headPos:] and tail.
    11  	// PopFront is trivial (headPos++) on the first stage, and
    12  	// PushBack is trivial (append) on the second stage.
    13  	// If the first stage is empty, PopFront can swap the
    14  	// first and second stages to remedy the situation.
    15  	//
    16  	// This two-stage split is analogous to the use of two lists
    17  	// in Okasaki's purely functional queue but without the
    18  	// overhead of reversing the list when swapping stages.
    19  	head    []E
    20  	headPos int
    21  	tail    []E
    22  }
    23  
    24  // New returns an initialized list.
    25  func New[E any]() *Queue[E] { return new(Queue[E]) }
    26  
    27  // Len returns the number of items in the queue.
    28  func (q *Queue[E]) Len() int {
    29  	n := 0
    30  	if q != nil {
    31  		n = len(q.head) - q.headPos + len(q.tail)
    32  	}
    33  	return n
    34  }
    35  
    36  // PushBack adds w to the back of the queue.
    37  func (q *Queue[E]) PushBack(w E) {
    38  	q.tail = append(q.tail, w)
    39  }
    40  
    41  // PopFront removes and returns the item at the front of the queue.
    42  func (q *Queue[E]) PopFront() E {
    43  	v, _ := q.popFront()
    44  	return v
    45  }
    46  
    47  // Front returns the item at the front of the queue without removing it.
    48  func (q *Queue[E]) Front() E {
    49  	v, _ := q.front()
    50  	return v
    51  }
    52  
    53  // Next reports whether there are more iterations to execute.
    54  // Every call to PopFront, even the first one, must be preceded by a call to Next.
    55  func (q *Queue[E]) Next() bool {
    56  	return q.Len() > 0
    57  }
    58  
    59  func (q *Queue[E]) popFront() (E, bool) {
    60  	if q.headPos >= len(q.head) {
    61  		if len(q.tail) == 0 {
    62  			var zeroE E
    63  			return zeroE, false
    64  		}
    65  		// Pick up tail as new head, clear tail.
    66  		q.head, q.headPos, q.tail = q.tail, 0, q.head[:0]
    67  	}
    68  	w := q.head[q.headPos]
    69  	var zeroE E
    70  	q.head[q.headPos] = zeroE
    71  	q.headPos++
    72  	return w, true
    73  }
    74  
    75  func (q *Queue[E]) front() (E, bool) {
    76  	if q.headPos < len(q.head) {
    77  		return q.head[q.headPos], true
    78  	}
    79  	if len(q.tail) > 0 {
    80  		return q.tail[0], true
    81  	}
    82  	var zeroE E
    83  	return zeroE, false
    84  }
    85  
    86  // PushBackQueue inserts a copy of another queue at the back of queue l.
    87  // The queues l and other may be the same. They must not be nil.
    88  func (q *Queue[E]) PushBackQueue(other *Queue[E]) {
    89  	other.Do(func(a E) {
    90  		q.PushBack(a)
    91  	})
    92  }
    93  
    94  // Do calls function f on each element of the queue without removing it, in forward order.
    95  // The behavior of Do is undefined if f changes *q.
    96  func (q *Queue[E]) Do(f func(E)) {
    97  	if q != nil {
    98  		for i := q.headPos; i < len(q.head); i++ {
    99  			f(q.head[i])
   100  		}
   101  		for i := 0; i < len(q.tail); i++ {
   102  			f(q.tail[i])
   103  		}
   104  	}
   105  }
   106  
   107  // ShrinkToFit requests the removal of unused capacity.
   108  func (q *Queue[E]) ShrinkToFit() {
   109  	if q.headPos >= len(q.head) { // empty head
   110  		if len(q.tail) == 0 { // empty tail
   111  			q.head = nil
   112  			q.headPos = 0
   113  			return
   114  		}
   115  		// Pick up tail as new head, clear tail.
   116  		q.head, q.headPos, q.tail = q.tail, 0, nil
   117  		return
   118  	}
   119  	// shrink slice head actually
   120  	if len(q.head) > 1 {
   121  		q.head = append([]E{}, q.head[q.headPos:]...)
   122  		q.headPos = 0
   123  	}
   124  	return
   125  }
   126  
   127  // TrimFrontFunc pops all leading elem that satisfying f(c) from the head of the
   128  // queue, reporting whether any were popped.
   129  func (q *Queue[E]) TrimFrontFunc(f func(e E) bool) (cleaned bool) {
   130  	for q.Next() {
   131  		if !f(q.Front()) {
   132  			return cleaned
   133  		}
   134  		q.PopFront()
   135  		cleaned = true
   136  	}
   137  	return cleaned
   138  }