github.com/asynkron/protoactor-go@v0.0.0-20240308120642-ef91a6abee75/internal/queue/goring/queue.go (about) 1 package goring 2 3 import ( 4 "sync" 5 "sync/atomic" 6 ) 7 8 type ringBuffer struct { 9 buffer []interface{} 10 head int64 11 tail int64 12 mod int64 13 } 14 15 type Queue struct { 16 len int64 17 content *ringBuffer 18 lock sync.Mutex 19 } 20 21 func New(initialSize int64) *Queue { 22 return &Queue{ 23 content: &ringBuffer{ 24 buffer: make([]interface{}, initialSize), 25 head: 0, 26 tail: 0, 27 mod: initialSize, 28 }, 29 len: 0, 30 } 31 } 32 33 func (q *Queue) Push(item interface{}) { 34 q.lock.Lock() 35 c := q.content 36 c.tail = (c.tail + 1) % c.mod 37 if c.tail == c.head { 38 var fillFactor int64 = 2 39 // we need to resize 40 41 newLen := c.mod * fillFactor 42 newBuff := make([]interface{}, newLen) 43 44 for i := int64(0); i < c.mod; i++ { 45 buffIndex := (c.tail + i) % c.mod 46 newBuff[i] = c.buffer[buffIndex] 47 } 48 // set the new buffer and reset head and tail 49 newContent := &ringBuffer{ 50 buffer: newBuff, 51 head: 0, 52 tail: c.mod, 53 mod: newLen, 54 } 55 q.content = newContent 56 } 57 atomic.AddInt64(&q.len, 1) 58 q.content.buffer[q.content.tail] = item 59 q.lock.Unlock() 60 } 61 62 func (q *Queue) Length() int64 { 63 return atomic.LoadInt64(&q.len) 64 } 65 66 func (q *Queue) Empty() bool { 67 return q.Length() == 0 68 } 69 70 // single consumer 71 func (q *Queue) Pop() (interface{}, bool) { 72 if q.Empty() { 73 return nil, false 74 } 75 // as we are a single consumer, no other thread can have poped the items there are guaranteed to be items now 76 77 q.lock.Lock() 78 c := q.content 79 c.head = (c.head + 1) % c.mod 80 res := c.buffer[c.head] 81 c.buffer[c.head] = nil 82 atomic.AddInt64(&q.len, -1) 83 q.lock.Unlock() 84 return res, true 85 } 86 87 func (q *Queue) PopMany(count int64) ([]interface{}, bool) { 88 if q.Empty() { 89 return nil, false 90 } 91 92 q.lock.Lock() 93 c := q.content 94 95 if count >= q.len { 96 count = q.len 97 } 98 atomic.AddInt64(&q.len, -count) 99 100 buffer := make([]interface{}, count) 101 for i := int64(0); i < count; i++ { 102 pos := (c.head + 1 + i) % c.mod 103 buffer[i] = c.buffer[pos] 104 c.buffer[pos] = nil 105 } 106 c.head = (c.head + count) % c.mod 107 108 q.lock.Unlock() 109 return buffer, true 110 }