@@ -18,13 +18,9 @@ var _ Queue[any] = (*Blocking[any])(nil)
18
18
// If there are no elements available the retrieve operations wait until
19
19
// elements are added to the queue.
20
20
type Blocking [T comparable ] struct {
21
- // elements queue
22
- elements []T
23
- elementsIndex int
24
-
25
- initialLen int
26
-
27
- capacity * int
21
+ initialElems []T
22
+ elems []T
23
+ capacity * int
28
24
29
25
// synchronization
30
26
lock sync.RWMutex
@@ -45,20 +41,23 @@ func NewBlocking[T comparable](
45
41
o .apply (& options )
46
42
}
47
43
44
+ // Store initial elements
45
+ initialElems := make ([]T , len (elems ))
46
+ copy (initialElems , elems )
47
+
48
48
queue := & Blocking [T ]{
49
- elements : elems ,
50
- elementsIndex : 0 ,
51
- initialLen : len (elems ),
52
- capacity : options .capacity ,
53
- lock : sync.RWMutex {},
49
+ elems : elems ,
50
+ initialElems : initialElems ,
51
+ capacity : options .capacity ,
52
+ lock : sync.RWMutex {},
54
53
}
55
54
56
55
queue .notEmptyCond = sync .NewCond (& queue .lock )
57
56
queue .notFullCond = sync .NewCond (& queue .lock )
58
57
59
58
if queue .capacity != nil {
60
- if len (queue .elements ) > * queue .capacity {
61
- queue .elements = queue .elements [:* queue .capacity ]
59
+ if len (queue .elems ) > * queue .capacity {
60
+ queue .elems = queue .elems [:* queue .capacity ]
62
61
}
63
62
}
64
63
@@ -77,7 +76,7 @@ func (bq *Blocking[T]) OfferWait(elem T) {
77
76
bq .notFullCond .Wait ()
78
77
}
79
78
80
- bq .elements = append (bq .elements , elem )
79
+ bq .elems = append (bq .elems , elem )
81
80
82
81
bq .notEmptyCond .Signal ()
83
82
}
@@ -92,22 +91,21 @@ func (bq *Blocking[T]) Offer(elem T) error {
92
91
return ErrQueueIsFull
93
92
}
94
93
95
- bq .elements = append (bq .elements , elem )
94
+ bq .elems = append (bq .elems , elem )
96
95
97
96
bq .notEmptyCond .Signal ()
98
97
99
98
return nil
100
99
}
101
100
102
- // Reset sets the queue elements index to 0. The queue will be in its initial
103
- // state.
101
+ // Reset sets the queue to its initial state with the original elements.
104
102
func (bq * Blocking [T ]) Reset () {
105
103
bq .lock .Lock ()
106
104
defer bq .lock .Unlock ()
107
105
108
- bq . elementsIndex = 0
109
-
110
- bq .elements = bq .elements [: bq . initialLen ]
106
+ // Restore initial elements
107
+ bq . elems = make ([] T , len ( bq . initialElems ))
108
+ copy ( bq .elems , bq .initialElems )
111
109
112
110
bq .notEmptyCond .Broadcast ()
113
111
}
@@ -117,29 +115,24 @@ func (bq *Blocking[T]) Reset() {
117
115
// GetWait removes and returns the head of the elements queue.
118
116
// If no element is available it waits until the queue
119
117
// has an element available.
120
- //
121
- // It does not actually remove elements from the elements slice, but
122
- // it's incrementing the underlying index.
123
118
func (bq * Blocking [T ]) GetWait () (v T ) {
124
119
bq .lock .Lock ()
125
120
defer bq .lock .Unlock ()
126
121
127
- defer bq .notFullCond . Signal ()
128
-
129
- idx := bq . getNextIndexOrWait ()
122
+ for bq .isEmpty () {
123
+ bq . notEmptyCond . Wait ()
124
+ }
130
125
131
- elem := bq .elements [idx ]
126
+ elem := bq .elems [0 ]
127
+ bq .elems = bq .elems [1 :]
132
128
133
- bq .elementsIndex ++
129
+ bq .notFullCond . Signal ()
134
130
135
131
return elem
136
132
}
137
133
138
134
// Get removes and returns the head of the elements queue.
139
135
// If no element is available it returns an ErrNoElementsAvailable error.
140
- //
141
- // It does not actually remove elements from the elements slice, but
142
- // it's incrementing the underlying index.
143
136
func (bq * Blocking [T ]) Get () (v T , _ error ) {
144
137
bq .lock .Lock ()
145
138
defer bq .lock .Unlock ()
@@ -154,9 +147,9 @@ func (bq *Blocking[T]) Clear() []T {
154
147
155
148
defer bq .notFullCond .Broadcast ()
156
149
157
- removed := bq . elements [ bq .elementsIndex :]
158
-
159
- bq .elementsIndex += len ( removed )
150
+ removed := make ([] T , len ( bq .elems ))
151
+ copy ( removed , bq . elems )
152
+ bq .elems = bq . elems [: 0 ]
160
153
161
154
return removed
162
155
}
@@ -199,9 +192,7 @@ func (bq *Blocking[T]) Peek() (v T, _ error) {
199
192
return v , ErrNoElementsAvailable
200
193
}
201
194
202
- elem := bq .elements [bq .elementsIndex ]
203
-
204
- return elem , nil
195
+ return bq .elems [0 ], nil
205
196
}
206
197
207
198
// PeekWait retrieves but does not return the head of the queue.
@@ -215,7 +206,7 @@ func (bq *Blocking[T]) PeekWait() T {
215
206
bq .notEmptyCond .Wait ()
216
207
}
217
208
218
- elem := bq .elements [ bq . elementsIndex ]
209
+ elem := bq .elems [ 0 ]
219
210
220
211
// send the not empty signal again in case any remove method waits.
221
212
bq .notEmptyCond .Signal ()
@@ -228,16 +219,16 @@ func (bq *Blocking[T]) Size() int {
228
219
bq .lock .RLock ()
229
220
defer bq .lock .RUnlock ()
230
221
231
- return bq .size ( )
222
+ return len ( bq .elems )
232
223
}
233
224
234
225
// Contains returns true if the queue contains the given element.
235
226
func (bq * Blocking [T ]) Contains (elem T ) bool {
236
227
bq .lock .RLock ()
237
228
defer bq .lock .RUnlock ()
238
229
239
- for i := range bq .elements [ bq . elementsIndex :] {
240
- if bq . elements [ i ] == elem {
230
+ for _ , e := range bq .elems {
231
+ if e == elem {
241
232
return true
242
233
}
243
234
}
@@ -255,20 +246,9 @@ func (bq *Blocking[T]) IsEmpty() bool {
255
246
256
247
// ===================================Helpers==================================
257
248
258
- // getNextIndexOrWait returns the next available index of the elements slice.
259
- func (bq * Blocking [T ]) getNextIndexOrWait () int {
260
- if ! bq .isEmpty () {
261
- return bq .elementsIndex
262
- }
263
-
264
- bq .notEmptyCond .Wait ()
265
-
266
- return bq .getNextIndexOrWait ()
267
- }
268
-
269
249
// isEmpty returns true if the queue is empty.
270
250
func (bq * Blocking [T ]) isEmpty () bool {
271
- return bq . elementsIndex >= len (bq .elements )
251
+ return len (bq .elems ) == 0
272
252
}
273
253
274
254
// isFull returns true if the queue is full.
@@ -277,43 +257,37 @@ func (bq *Blocking[T]) isFull() bool {
277
257
return false
278
258
}
279
259
280
- return len (bq .elements ) - bq . elementsIndex >= * bq .capacity
260
+ return len (bq .elems ) >= * bq .capacity
281
261
}
282
262
283
263
func (bq * Blocking [T ]) size () int {
284
- return len (bq .elements ) - bq . elementsIndex
264
+ return len (bq .elems )
285
265
}
286
266
287
267
func (bq * Blocking [T ]) get () (v T , _ error ) {
288
- defer bq .notFullCond .Signal ()
289
-
290
268
if bq .isEmpty () {
291
269
return v , ErrNoElementsAvailable
292
270
}
293
271
294
- elem := bq .elements [bq .elementsIndex ]
272
+ elem := bq .elems [0 ]
273
+ bq .elems = bq .elems [1 :]
295
274
296
- bq .elementsIndex ++
275
+ bq .notFullCond . Signal ()
297
276
298
277
return elem , nil
299
278
}
300
279
301
280
// MarshalJSON serializes the Blocking queue to JSON.
302
281
func (bq * Blocking [T ]) MarshalJSON () ([]byte , error ) {
303
282
bq .lock .RLock ()
283
+ defer bq .lock .RUnlock ()
304
284
305
- if bq .IsEmpty () {
306
- bq .lock .RUnlock ()
285
+ if bq .isEmpty () {
307
286
return []byte ("[]" ), nil
308
287
}
309
288
310
- // Extract elements from `elements` starting at `elementsIndex`.
311
- elements := bq .elements [bq .elementsIndex :]
312
-
313
- bq .lock .RUnlock ()
314
-
315
289
// Marshal the slice of elements into JSON.
316
- data , err := json .Marshal (elements )
290
+ data , err := json .Marshal (bq . elems )
317
291
if err != nil {
318
292
return nil , fmt .Errorf ("failed to marshal blocking queue: %w" , err )
319
293
}
0 commit comments