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 }