github.com/maypok86/otter@v1.2.1/internal/queue/growable.go (about) 1 // Copyright (c) 2024 Alexey Mayshev. All rights reserved. 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 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package queue 16 17 import ( 18 "sync" 19 20 "github.com/maypok86/otter/internal/xmath" 21 ) 22 23 type Growable[T any] struct { 24 mutex sync.Mutex 25 notEmpty sync.Cond 26 notFull sync.Cond 27 buf []T 28 head int 29 tail int 30 count int 31 minCap int 32 maxCap int 33 } 34 35 func NewGrowable[T any](minCap, maxCap uint32) *Growable[T] { 36 minCap = xmath.RoundUpPowerOf2(minCap) 37 maxCap = xmath.RoundUpPowerOf2(maxCap) 38 39 g := &Growable[T]{ 40 buf: make([]T, minCap), 41 minCap: int(minCap), 42 maxCap: int(maxCap), 43 } 44 45 g.notEmpty = *sync.NewCond(&g.mutex) 46 g.notFull = *sync.NewCond(&g.mutex) 47 48 return g 49 } 50 51 func (g *Growable[T]) Push(item T) { 52 g.mutex.Lock() 53 for g.count == g.maxCap { 54 g.notFull.Wait() 55 } 56 g.push(item) 57 g.mutex.Unlock() 58 } 59 60 func (g *Growable[T]) push(item T) { 61 g.grow() 62 g.buf[g.tail] = item 63 g.tail = g.next(g.tail) 64 g.count++ 65 g.notEmpty.Signal() 66 } 67 68 func (g *Growable[T]) Pop() T { 69 g.mutex.Lock() 70 for g.count == 0 { 71 g.notEmpty.Wait() 72 } 73 item := g.pop() 74 g.mutex.Unlock() 75 return item 76 } 77 78 func (g *Growable[T]) pop() T { 79 var zero T 80 81 item := g.buf[g.head] 82 g.buf[g.head] = zero 83 84 g.head = g.next(g.head) 85 g.count-- 86 87 g.notFull.Signal() 88 89 return item 90 } 91 92 func (g *Growable[T]) Clear() { 93 g.mutex.Lock() 94 for g.count > 0 { 95 g.pop() 96 } 97 g.mutex.Unlock() 98 } 99 100 func (g *Growable[T]) grow() { 101 if g.count != len(g.buf) { 102 return 103 } 104 g.resize() 105 } 106 107 func (g *Growable[T]) resize() { 108 newBuf := make([]T, g.count<<1) 109 if g.tail > g.head { 110 copy(newBuf, g.buf[g.head:g.tail]) 111 } else { 112 n := copy(newBuf, g.buf[g.head:]) 113 copy(newBuf[n:], g.buf[:g.tail]) 114 } 115 116 g.head = 0 117 g.tail = g.count 118 g.buf = newBuf 119 } 120 121 func (g *Growable[T]) next(i int) int { 122 return (i + 1) & (len(g.buf) - 1) 123 }