Skip to content

Commit 2f07fa6

Browse files
authored
Merge pull request #11 from vibe-d/ringbuffer_additions
RingBuffer additions
2 parents e30802f + 9eb75c4 commit 2f07fa6

File tree

1 file changed

+103
-8
lines changed

1 file changed

+103
-8
lines changed

source/vibe/container/ringbuffer.d

+103-8
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,14 @@ struct RingBuffer(T, size_t N = 0, bool INITIALIZE = true) {
4747
/// Constructs a new rung buffer with given capacity (only if `N == 0`).
4848
this(size_t capacity) { m_buffer = new T[capacity]; }
4949

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);
5458
}
5559

5660
~this()
@@ -120,10 +124,19 @@ struct RingBuffer(T, size_t N = 0, bool INITIALIZE = true) {
120124
m_start = 0;
121125
}
122126

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+
123136
/// 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++)]); }
125138
/// ditto
126-
void put(TC : T)(scope TC[] itms)
139+
void putBack(TC : T)(scope TC[] itms)
127140
{
128141
if (!itms.length) return;
129142
assert(m_fill + itms.length <= m_buffer.length);
@@ -137,6 +150,8 @@ struct RingBuffer(T, size_t N = 0, bool INITIALIZE = true) {
137150
}
138151
m_fill += itms.length;
139152
}
153+
/// ditto
154+
alias put = putBack;
140155

141156
/** Adds elements to the back of the buffer without overwriting the buffer.
142157
@@ -145,7 +160,9 @@ struct RingBuffer(T, size_t N = 0, bool INITIALIZE = true) {
145160
slice that can be directly written to, followed by calling `popFrontN`
146161
with the number of elements that were written to the slice.
147162
*/
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;
149166

150167
/// Removes the first element from the buffer.
151168
void removeFront()
@@ -342,6 +359,10 @@ struct RingBuffer(T, size_t N = 0, bool INITIALIZE = true) {
342359

343360
@property ref inout(T) front() inout return { assert(!empty); return m_buffer[m_start]; }
344361

362+
@property size_t length() const { return m_length; }
363+
364+
@property Range save() { return this; }
365+
345366
void popFront()
346367
{
347368
assert(!empty);
@@ -350,6 +371,39 @@ struct RingBuffer(T, size_t N = 0, bool INITIALIZE = true) {
350371
if (m_start >= m_buffer.length)
351372
m_start = 0;
352373
}
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+
}
353407
}
354408

355409
static if (N == 0) {
@@ -362,7 +416,8 @@ struct RingBuffer(T, size_t N = 0, bool INITIALIZE = true) {
362416
}
363417

364418
@safe unittest {
365-
import std.range : isInputRange, isOutputRange;
419+
import std.range : isInputRange, isOutputRange, retro;
420+
import std.algorithm.comparison : equal;
366421

367422
static assert(isInputRange!(RingBuffer!int.Range) && isOutputRange!(RingBuffer!int, int));
368423

@@ -396,6 +451,29 @@ struct RingBuffer(T, size_t N = 0, bool INITIALIZE = true) {
396451
foreach(i, item; buf) {
397452
assert(i == item);
398453
}
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]));
399477
}
400478

401479
@safe unittest {
@@ -443,3 +521,20 @@ struct RingBuffer(T, size_t N = 0, bool INITIALIZE = true) {
443521
}
444522
assert(*pcnt == 0);
445523
}
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

Comments
 (0)