@@ -47,10 +47,14 @@ struct RingBuffer(T, size_t N = 0, bool INITIALIZE = true) {
47
47
// / Constructs a new rung buffer with given capacity (only if `N == 0`).
48
48
this (size_t capacity ) { m_buffer = new T[capacity ]; }
49
49
50
- this (this )
51
- {
52
- if (m_buffer.length)
53
- m_buffer = m_buffer.dup ;
50
+ static if (isCopyable! T) {
51
+ this (this )
52
+ {
53
+ if (m_buffer.length)
54
+ m_buffer = m_buffer.dup ;
55
+ }
56
+ } else {
57
+ @disable this (this );
54
58
}
55
59
56
60
~this ()
@@ -120,10 +124,19 @@ struct RingBuffer(T, size_t N = 0, bool INITIALIZE = true) {
120
124
m_start = 0 ;
121
125
}
122
126
127
+ // / Adds an element to the front of the buffer.
128
+ void putFront (T itm)
129
+ {
130
+ assert (m_fill < m_buffer.length);
131
+ m_start = mod(m_start + m_buffer.length - 1 );
132
+ m_fill++ ;
133
+ m_buffer[m_start] = move(itm);
134
+ }
135
+
123
136
// / Adds elements to the back of the buffer.
124
- void put ()(T itm) { assert (m_fill < m_buffer.length); move(itm, m_buffer[mod(m_start + m_fill++ )]); }
137
+ void putBack ()(T itm) { assert (m_fill < m_buffer.length); move(itm, m_buffer[mod(m_start + m_fill++ )]); }
125
138
// / ditto
126
- void put (TC : T)(scope TC [] itms)
139
+ void putBack (TC : T)(scope TC [] itms)
127
140
{
128
141
if (! itms.length) return ;
129
142
assert (m_fill + itms.length <= m_buffer.length);
@@ -137,6 +150,8 @@ struct RingBuffer(T, size_t N = 0, bool INITIALIZE = true) {
137
150
}
138
151
m_fill += itms.length;
139
152
}
153
+ // / ditto
154
+ alias put = putBack;
140
155
141
156
/* * Adds elements to the back of the buffer without overwriting the buffer.
142
157
@@ -145,7 +160,9 @@ struct RingBuffer(T, size_t N = 0, bool INITIALIZE = true) {
145
160
slice that can be directly written to, followed by calling `popFrontN`
146
161
with the number of elements that were written to the slice.
147
162
*/
148
- void putN (size_t n) { assert (m_fill+ n <= m_buffer.length); m_fill += n; }
163
+ void putBackN (size_t n) { assert (m_fill+ n <= m_buffer.length); m_fill += n; }
164
+ // / ditto
165
+ alias putN = putBackN;
149
166
150
167
// / Removes the first element from the buffer.
151
168
void removeFront ()
@@ -342,6 +359,10 @@ struct RingBuffer(T, size_t N = 0, bool INITIALIZE = true) {
342
359
343
360
@property ref inout (T) front() inout return { assert (! empty); return m_buffer[m_start]; }
344
361
362
+ @property size_t length() const { return m_length; }
363
+
364
+ @property Range save() { return this ; }
365
+
345
366
void popFront ()
346
367
{
347
368
assert (! empty);
@@ -350,6 +371,39 @@ struct RingBuffer(T, size_t N = 0, bool INITIALIZE = true) {
350
371
if (m_start >= m_buffer.length)
351
372
m_start = 0 ;
352
373
}
374
+
375
+ @property ref inout (T) back()
376
+ inout return {
377
+ assert (! empty);
378
+ auto idx = m_start + m_length - 1 ;
379
+ if (idx >= m_buffer.length)
380
+ idx -= m_buffer.length;
381
+ return m_buffer[idx];
382
+ }
383
+
384
+ void popBack ()
385
+ {
386
+ assert (! empty);
387
+ m_length-- ;
388
+ }
389
+
390
+
391
+ size_t opDollar () const { return m_length; }
392
+
393
+ ref inout (T) opIndex (size_t index)
394
+ inout {
395
+ assert (index < m_length);
396
+ index += m_start;
397
+ if (index >= m_buffer.length)
398
+ index -= m_buffer.length;
399
+ return m_buffer[index];
400
+ }
401
+
402
+ Range opSlice (size_t from, size_t to)
403
+ {
404
+ assert (from <= to && to <= length);
405
+ return Range (m_buffer, m_start + from, to - from);
406
+ }
353
407
}
354
408
355
409
static if (N == 0 ) {
@@ -362,7 +416,8 @@ struct RingBuffer(T, size_t N = 0, bool INITIALIZE = true) {
362
416
}
363
417
364
418
@safe unittest {
365
- import std.range : isInputRange, isOutputRange;
419
+ import std.range : isInputRange, isOutputRange, retro;
420
+ import std.algorithm.comparison : equal;
366
421
367
422
static assert (isInputRange! (RingBuffer! int .Range ) && isOutputRange! (RingBuffer! int , int ));
368
423
@@ -396,6 +451,29 @@ struct RingBuffer(T, size_t N = 0, bool INITIALIZE = true) {
396
451
foreach (i, item; buf) {
397
452
assert (i == item);
398
453
}
454
+
455
+ // test range interface
456
+ assert (buf[].equal([0 , 1 , 2 , 3 , 4 ]));
457
+ assert (buf[].retro.equal([4 , 3 , 2 , 1 , 0 ]));
458
+ assert (buf[1 .. $- 1 ].equal([1 , 2 , 3 ]));
459
+ assert (buf[1 .. $- 1 ].retro.equal([3 , 2 , 1 ]));
460
+
461
+ assert (buf[].length == 5 );
462
+ assert (buf[][0 ] == 0 );
463
+ assert (buf[][2 ] == 2 );
464
+ assert (buf[][$- 1 ] == 4 );
465
+
466
+ assert (buf[1 .. $- 1 ].length == 3 );
467
+ assert (buf[1 .. $- 1 ][0 ] == 1 );
468
+ assert (buf[1 .. $- 1 ][2 ] == 3 );
469
+ assert (buf[1 .. $- 1 ][$- 1 ] == 3 );
470
+
471
+ assert (buf[1 .. $- 1 ][1 .. 2 ].length == 1 );
472
+ assert (buf[1 .. $- 1 ][1 .. 2 ].equal([2 ]));
473
+
474
+ buf.removeBack();
475
+ buf.putFront(- 1 );
476
+ assert (buf[].equal([- 1 , 0 , 1 , 2 , 3 ]));
399
477
}
400
478
401
479
@safe unittest {
@@ -443,3 +521,20 @@ struct RingBuffer(T, size_t N = 0, bool INITIALIZE = true) {
443
521
}
444
522
assert (* pcnt == 0 );
445
523
}
524
+
525
+ @safe unittest { // non-copyable struct
526
+ static struct S {
527
+ int i;
528
+ @disable this (this );
529
+ void move () {}
530
+ }
531
+
532
+ RingBuffer! S buf;
533
+ buf.capacity = 4 ;
534
+ buf.put(S(0 ));
535
+ buf.put(S(1 ));
536
+ assert (buf.front.i == 0 );
537
+ assert (buf[1 ].i == 1 );
538
+ buf.removeFrontN(2 );
539
+ assert (buf.length == 0 );
540
+ }
0 commit comments