1 /++
2  + Authors: Stephan Dilly (@extrawurst), lastname dot firstname at gmail dot com
3  + Copyright: Stephan Dilly
4  + License: MIT
5  +/
6 module unecht.core.staticRingBuffer;
7 
8 @safe @nogc:
9 
10 /// @nogc @safe ringbuffer using static memory block
11 struct StaticRingBuffer(size_t size, T)
12 {
13 	///
14 	enum StaticSize = size;
15 
16 	private T[size] data;
17 	private size_t spaceUsed;
18 
19 	/// append operator
20 	ref auto opOpAssign(string op)(T v) @trusted nothrow if (op == "~")
21 	{
22 		if (spaceUsed < StaticSize)
23 		{
24 			data[spaceUsed++] = v;
25 		}
26 		else
27 		{
28 			import core.stdc..string : memmove;
29 
30 			memmove(data.ptr, data.ptr + 1, (StaticSize - 1) * T.sizeof);
31 			data[StaticSize - 1] = v;
32 		}
33 
34 		return this;
35 	}
36 
37 	///
38 	unittest
39 	{
40 		StaticRingBuffer!(2, int) foo;
41 
42 		// append operator
43 		foo ~= 1;
44 		foo ~= 2;
45 
46 		assert(foo[0] == 1);
47 		assert(foo[1] == 2);
48 	}
49 
50 	/// random access operator
51 	auto ref opIndex(size_t idx)
52 	{
53 		static immutable exc = new Exception("idx out of range");
54 
55 		if (idx >= spaceUsed)
56 			throw exc;
57 
58 		return data[idx];
59 	}
60 
61 	///
62 	unittest
63 	{
64 		StaticRingBuffer!(2, int) foo;
65 
66 		foo ~= 1;
67 
68 		assert(foo[0] == 1);
69 
70 		foo[0] = 2;
71 
72 		assert(foo[0] == 2);
73 	}
74 
75 	/// current amount of elements used in the buffer
76 	@property size_t length() const nothrow
77 	{
78 		return spaceUsed;
79 	}
80 
81 	///
82 	unittest
83 	{
84 		StaticRingBuffer!(2, int) foo;
85 
86 		assert(foo.length == 0);
87 
88 		foo ~= 1;
89 
90 		assert(foo.length == 1);
91 
92 		foo ~= 1;
93 
94 		assert(foo.length == 2);
95 
96 		// append but let first element drop out
97 		foo ~= 1;
98 
99 		assert(foo.length == 2);
100 	}
101 
102 	///
103 	@property T* ptr() nothrow
104 	{
105 		return &data[0];
106 	}
107 }
108 
109 ///
110 unittest
111 {
112 	StaticRingBuffer!(2, int) foo;
113 	assert(foo.length == 0);
114 
115 	foo ~= 1;
116 
117 	assert(foo.length == 1);
118 	assert(foo[0] == 1);
119 
120 	foo ~= 2;
121 
122 	assert(foo.length == 2);
123 	assert(foo[0] == 1);
124 	assert(foo[1] == 2);
125 
126 	foo ~= 3;
127 
128 	assert(foo.length == 2);
129 	assert(foo[0] == 2);
130 	assert(foo[1] == 3);
131 }