github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/pkg/container/queue/iterator.go (about) 1 // Copyright 2022 PingCAP, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package queue 15 16 // ChunkQueueIterator is the iterator type of ChunkQueue. Iterating ChunkQueue 17 // by iterators is not thread-safe. Manipulating invalid iterators may incur 18 // panics. Don't use an iterator of an element that has already been dequeued. 19 // Instead, use with checks and in loop. E.g. 20 // 21 // for it := someQueue.First(); it.Valid(); it.Next() { 22 // ... // operations cannot pop element 23 // } 24 // 25 // Note: Begin() and First() are interchangeable 26 // for it := someQueue.Begin(); it.Valid(); { // forwards 27 // 28 // it.Next() 29 // q.Pop() // can pop element 30 // } 31 // 32 // for it := someQueue.Last(); it.Valid(); it.Next() { // backwards 33 // 34 // ... 35 // } 36 // 37 // for it := someQueue.End(); it.Prev(); { // backwards 38 // 39 // ... 40 // } 41 type ChunkQueueIterator[T any] struct { 42 idxInChunk int 43 chunk *chunk[T] 44 } 45 46 // First returns the iterator of the first element. The iterator is valid for a 47 // non-empty queue, and invalid otherwise. 48 func (q *ChunkQueue[T]) First() *ChunkQueueIterator[T] { 49 return &ChunkQueueIterator[T]{ 50 chunk: q.firstChunk(), 51 idxInChunk: q.firstChunk().l, 52 } 53 } 54 55 // Last returns the iterator of the last element. The iterator is valid for a 56 // non-empty queue, and invalid otherwise. 57 func (q *ChunkQueue[T]) Last() *ChunkQueueIterator[T] { 58 return &ChunkQueueIterator[T]{ 59 chunk: q.lastChunk(), 60 idxInChunk: q.lastChunk().r - 1, 61 } 62 } 63 64 // Begin is an alias of First(), for convenient 65 func (q *ChunkQueue[T]) Begin() *ChunkQueueIterator[T] { 66 return q.First() 67 } 68 69 // End returns a special iterator of the queue representing the end. The end 70 // iterator is not valid since it's not in the queue. Its predecessor is Last() 71 func (q *ChunkQueue[T]) End() *ChunkQueueIterator[T] { 72 return &ChunkQueueIterator[T]{ 73 chunk: q.lastChunk(), 74 idxInChunk: q.chunkLength, 75 } 76 } 77 78 // GetIterator returns an iterator of a given index. Nil for invalid indices 79 func (q *ChunkQueue[T]) GetIterator(idx int) *ChunkQueueIterator[T] { 80 if idx < 0 || idx >= q.size { 81 return nil 82 } 83 idx += q.chunks[q.head].l 84 return &ChunkQueueIterator[T]{ 85 chunk: q.chunks[q.head+idx/q.chunkLength], 86 idxInChunk: idx % q.chunkLength, 87 } 88 } 89 90 // Valid indicates if the element of the iterator is in queue 91 func (it *ChunkQueueIterator[T]) Valid() bool { 92 return it.chunk != nil && it.idxInChunk >= it.chunk.l && it.idxInChunk < it.chunk.r 93 } 94 95 // Value returns the element value of a valid iterator which is in queue. 96 // It's meaningless and may panic otherwise. 97 func (it *ChunkQueueIterator[T]) Value() T { 98 return it.chunk.data[it.idxInChunk] 99 } 100 101 // Set replaces the element of the valid iterator. Panic for invalid iterators 102 func (it *ChunkQueueIterator[T]) Set(v T) { 103 it.chunk.data[it.idxInChunk] = v 104 } 105 106 // Index returns the index of a valid iterator, and -1 otherwise. 107 // Attention: The time complexity is O(N). Please avoid using this method 108 func (it *ChunkQueueIterator[T]) Index() int { 109 if !it.Valid() { 110 return -1 111 } 112 q := it.chunk.queue 113 idx := 0 114 for i := q.head; i < q.tail; i++ { 115 if q.chunks[i] != it.chunk { 116 idx += q.chunks[i].len() 117 } else { 118 idx += it.idxInChunk - it.chunk.l 119 break 120 } 121 } 122 return idx 123 } 124 125 // Next updates the current iterator to its next iterator. It returns true if 126 // the next iterator is still in queue, and false otherwise. Calling Next for 127 // an invalid iterator is meaningless, and using invalid iterators may panic. 128 func (it *ChunkQueueIterator[T]) Next() bool { 129 if it.chunk == nil { 130 return false 131 } 132 133 it.idxInChunk++ 134 if it.idxInChunk < it.chunk.r { 135 return true 136 } 137 138 c, q := it.chunk, it.chunk.queue 139 if it.idxInChunk == q.chunkLength && c.next != nil && !c.empty() { 140 it.idxInChunk, it.chunk = 0, c.next 141 return true 142 } 143 144 it.idxInChunk = q.chunkLength 145 return false 146 } 147 148 // Prev updates the current to its previous iterator. It returns true if the 149 // next iterator is in queue, and false otherwise. The Prev of an end iterator 150 // points to the last element of the queue if the queue is not empty. 151 // The return boolean value is useful for backwards iteration. E.g. 152 // `for it := someQueue.Last(); it.Valid(); it.Next() {...}` 153 // `for it := someQueue.End(); it.Prev; {...} ` 154 func (it *ChunkQueueIterator[T]) Prev() bool { 155 if !it.Valid() { 156 if c := it.chunk; c != nil && c.queue != nil && it.idxInChunk == len(c.data) { 157 lc := c.queue.lastChunk() 158 it.chunk, it.idxInChunk = lc, lc.r-1 159 return it.Valid() 160 } 161 return false 162 } 163 164 it.idxInChunk-- 165 if it.idxInChunk >= it.chunk.l { 166 return true 167 } 168 169 c := it.chunk 170 if c.prev != nil { 171 it.chunk, it.idxInChunk = c.prev, c.prev.r-1 172 return true 173 } 174 it.idxInChunk = -1 175 return false 176 }