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  }