1 module modbus.cbuffer; 2 3 import std.exception; 4 import std.algorithm : equal; 5 6 struct CBuffer 7 { 8 private ubyte[] buf; 9 private size_t s, e; 10 11 private this(inout(ubyte)[] buf, size_t s, size_t e) pure inout 12 { 13 this.buf = buf; 14 this.s = s; 15 this.e = e; 16 } 17 18 this(size_t n) { buf = new ubyte[](n+1); } 19 20 invariant 21 { 22 assert(s >= 0); 23 assert(e >= 0); 24 assert(s < buf.length); 25 assert(e < buf.length); 26 } 27 28 @nogc pure 29 { 30 const @property 31 { 32 bool empty() { return s == e; } 33 bool full() { return e == (capacity + s - 1) % capacity; } 34 35 size_t length() 36 { 37 if (s <= e) return e - s; 38 else return capacity - (s - e); 39 } 40 41 size_t capacity() { return buf.length; } 42 } 43 44 void put(ubyte val) 45 { 46 assert(!full, "no space"); 47 buf[e] = val; 48 e = (e + 1) % capacity; 49 } 50 51 void put(const(void)[] data) 52 { 53 assert(data.length < capacity - length, "no space"); 54 foreach (i, v; cast(ubyte[])data) put(v); 55 } 56 57 void clear() { s = e; } 58 59 @property inout 60 { 61 ref inout(ubyte) front() 62 { 63 assert(!empty, "empty"); 64 return buf[s]; 65 } 66 67 ref inout(ubyte) back() 68 { 69 assert(!empty, "empty"); 70 return buf[e-1]; 71 } 72 } 73 74 void popFront() { popFrontN(1); } 75 76 size_t popFrontN(size_t n) 77 { 78 assert(!empty, "empty"); 79 long ns = s + n; 80 long el = e < s ? e + capacity : e; 81 auto df = el - ns; 82 if (df < 0) n += df; 83 s = (s + n) % capacity; 84 return n; 85 } 86 87 void popBack() 88 { 89 assert(!empty, "empty"); 90 e = (capacity + (cast(ptrdiff_t)e) - 1) % capacity; 91 } 92 93 ref inout(ubyte) opIndex(size_t n) inout 94 { 95 auto idx = (s+n) % capacity; 96 return buf[idx]; 97 } 98 99 void[] fill(void[] buffer) 100 { 101 assert(buffer.length >= length, "no space"); 102 103 if (empty) return buffer[0..0]; 104 105 if (s < e) 106 { 107 buffer[0..length] = buf[s..e]; 108 return buffer[0..length]; 109 } 110 else 111 { 112 buffer[0..capacity-s] = buf[s..$]; 113 buffer[capacity-s..length] = buf[0..e]; 114 return buffer[0..length]; 115 } 116 } 117 } 118 119 inout(CBuffer) opSlice(size_t a, size_t b) inout 120 { 121 enforce(a <= b, new Exception("range: a must be <= b")); 122 enforce(b-a <= length, new Exception("range: b-a must be <= length")); 123 124 auto idx_s = (s + a) % capacity; 125 auto idx_e = (s + b) % capacity; 126 127 return inout CBuffer(buf, idx_s, idx_e); 128 } 129 130 CBuffer dup() const @property 131 { return CBuffer(buf.dup, s, e); } 132 133 ubyte[] getData(size_t a, size_t b) inout 134 { 135 enforce(a <= b, new Exception("range: a must be <= b")); 136 enforce(b-a <= length, new Exception("range: b-a must be <= length")); 137 138 if (a == b) return []; 139 140 auto idx_s = (s + a) % capacity; 141 auto idx_e = (s + b) % capacity; 142 143 if (idx_s < idx_e) return buf[idx_s..idx_e].dup; 144 else return buf[idx_s..$].dup ~ buf[0..idx_e]; 145 } 146 147 ubyte[] getData() inout { return getData(0, length); } 148 } 149 150 class CBufferCls 151 { 152 CBuffer s; 153 alias s this; 154 this(size_t n) { s = CBuffer(n); } 155 } 156 157 unittest 158 { 159 auto buf = CBuffer(10); 160 assert(buf.empty); 161 assert(!buf.full); 162 assert(buf.length == 0); 163 buf.put(12); 164 assert(!buf.empty); 165 assert(!buf.full); 166 assert(buf.length == 1); 167 assert(buf.front == 12); 168 assert(buf.back == 12); 169 buf.put(cast(ubyte[])[42, 15]); 170 assert(buf.length == 3); 171 assert(buf.front == 12); 172 assert(buf.back == 15); 173 buf.popFront(); 174 assert(buf.length == 2); 175 assert(buf.front == 42); 176 assert(buf.back == 15); 177 buf.popBack(); 178 assert(buf.length == 1); 179 assert(buf.front == 42); 180 assert(buf.back == 42); 181 assert(buf.s == 1); 182 assert(buf.e == 2); 183 buf.put(cast(ubyte[])[1,2,3,4,5]); 184 assert(!buf.empty); 185 assert(!buf.full); 186 assert(buf.length == 6); 187 assert(buf.s == 1); 188 assert(buf.e == 7); 189 buf.popFront(); 190 buf.popFront(); 191 buf.popFront(); 192 assert(!buf.empty); 193 assert(!buf.full); 194 assert(buf.length == 3); 195 buf.put(cast(ubyte[])[11,12,13,14]); 196 assert(!buf.empty); 197 assert(!buf.full); 198 assert(buf.length == 7); 199 buf.put(cast(ubyte[])[21,22]); 200 assert(!buf.empty); 201 assert(!buf.full); 202 assert(buf.length == 9); 203 buf.put(cast(ubyte[])[31]); 204 assert(buf.back == 31); 205 assert(!buf.empty); 206 assert(buf.full); 207 assert(buf.length == 10); 208 assertThrown!Throwable(buf.put(42)); 209 buf.popBack; 210 assert(buf.back == 22); 211 assert(!buf.empty); 212 assert(!buf.full); 213 assert(buf.length == 9); 214 foreach (i; 0 .. 5) buf.popFront; 215 assert(buf.back == 22); 216 assert(buf.front == 13); 217 assert(!buf.empty); 218 assert(!buf.full); 219 assert(buf.length == 4); 220 buf.popFront; 221 buf.popFront; 222 buf.popBack; 223 buf.popBack; 224 assert(buf.empty); 225 assert(!buf.full); 226 assert(buf.length == 0); 227 buf.put(cast(ubyte[])[1,2,3,4,5,6,7,8,9,10]); 228 assert(!buf.empty); 229 assert(buf.full); 230 assert(buf.length == 10); 231 foreach (i; 0 .. 5) buf.popFront; 232 foreach (i; 0 .. 5) buf.popBack; 233 assert(buf.empty); 234 assert(!buf.full); 235 assert(buf.length == 0); 236 buf.put(200); 237 assert(buf.front == 200); 238 assert(buf.back == 200); 239 assert(!buf.empty); 240 assert(!buf.full); 241 assert(buf.length == 1); 242 assert(buf.s == 5); 243 assert(buf.e == 6); 244 } 245 246 unittest 247 { 248 auto buf = CBuffer(10); 249 buf.put(cast(ubyte[])[1,2,3,4,5,6,8,9]); 250 foreach (i; 0..7) buf.popFront; 251 buf.put(cast(ubyte[])[1,2,3,4,5,6]); 252 assert(buf.getData() == [9, 1, 2, 3, 4, 5, 6]); 253 auto buf2 = buf.dup; 254 foreach (i; 0..5) buf.popFront; 255 assert(buf.length == 2); 256 assert(buf.front == 5); 257 assert(buf.back == 6); 258 assert(buf.getData() == [5, 6]); 259 foreach (i; 0..5) buf2.popBack; 260 assert(buf2.length == 2); 261 assert(buf2.front == 9); 262 assert(buf2.back == 1); 263 assert(buf2.getData() == [9, 1]); 264 } 265 266 unittest 267 { 268 auto buf = CBuffer(10); 269 buf.put(cast(ubyte[])[1,2,3,4,5,6,8,9]); 270 foreach (i; 0..7) buf.popFront; 271 buf.put(cast(ubyte[])[1,2,3,4,5,6]); 272 assert(buf.getData() == [9, 1, 2, 3, 4, 5, 6]); 273 auto buf2 = buf[2..6]; 274 assert(buf2.getData() == [2, 3, 4, 5]); 275 assert(buf.buf == buf2.buf); 276 buf2.clear(); 277 assert(buf2.empty); 278 assert(buf2.length == 0); 279 assert(buf2.getData() == []); 280 assert(buf.getData() == [9, 1, 2, 3, 4, 5, 6]); 281 } 282 283 unittest 284 { 285 auto buf = CBuffer(10); 286 buf.put(cast(ubyte[])[1,2,3,4,5,6,8,9]); 287 foreach (i; 0..7) buf.popFront; 288 buf.put(cast(ubyte[])[1,2,3,4,5,6]); 289 ubyte[] res; 290 foreach (v; buf) res ~= v; 291 assert(res == [9, 1, 2, 3, 4, 5, 6]); 292 } 293 294 unittest 295 { 296 auto buf = new CBufferCls(10); 297 buf.put(cast(ubyte[])[1,2,3,4,5,6,8,9]); 298 foreach (i; 0..7) buf.popFront; 299 buf.put(cast(ubyte[])[1,2,3,4,5,6]); 300 ubyte[] res; 301 buf[0] = 12; 302 buf[5] = 55; 303 assert(buf[0] == 12); 304 foreach (v; buf) res ~= v; 305 assert(res == [12, 1, 2, 3, 4, 55, 6]); 306 } 307 308 unittest 309 { 310 auto buf = new CBufferCls(10); 311 buf.put(cast(ubyte[])[1,2,3,4,5,6,8,9]); 312 buf.popFrontN(7); 313 buf.put(cast(ubyte[])[1,2,3,4,5,6]); 314 ubyte[] res; 315 buf[0] = 12; 316 buf[5] = 55; 317 assert(buf[0] == 12); 318 foreach (v; buf) res ~= v; 319 assert(res == [12, 1, 2, 3, 4, 55, 6]); 320 } 321 322 unittest 323 { 324 auto buf = new CBufferCls(10); 325 buf.put(cast(ubyte[])[1,2,3,4,5,6,7,8]); 326 assert(buf.popFrontN(2) == 2); 327 assert(equal(buf.dup, [3,4,5,6,7,8])); 328 assert(buf.popFrontN(2) == 2); 329 assert(equal(buf.dup, [5,6,7,8])); 330 assert(buf.popFrontN(2) == 2); 331 assert(equal(buf.dup, [7,8])); 332 assert(buf.popFrontN(2) == 2); 333 assert(equal(buf.dup, cast(ubyte[])[])); 334 assert(buf.empty); 335 } 336 337 unittest 338 { 339 auto buf = new CBufferCls(10); 340 buf.put(cast(ubyte[])[1,2,3,4,5,6]); 341 assert(buf.popFrontN(10) == 6); 342 buf.put(cast(ubyte[])[1,2,3,4,5,6,7,8]); 343 assert(buf.popFrontN(6) == 6); 344 assert(equal(buf.dup, [7,8])); 345 } 346 347 unittest 348 { 349 auto buf = new CBufferCls(10); 350 buf.put(cast(ubyte[])[1,2,3,4,5,6]); 351 assert(buf.popFrontN(10) == 6); 352 buf.put(cast(ubyte[])[1,2,3,4,5,6,7,8]); 353 assert(buf.popFrontN(10) == 8); 354 assert(buf.empty); 355 } 356 357 unittest 358 { 359 auto buf = CBuffer(6); 360 buf.put(cast(ubyte[])[1,2,3,4,5,6]); 361 assert(buf.popFrontN(10) == 6); 362 buf.put(cast(ubyte[])[1,2,3,4]); 363 assert(buf.popFrontN(10) == 4); 364 assert(buf.empty); 365 } 366 367 unittest 368 { 369 auto buf = new CBufferCls(10); 370 buf.put(cast(ubyte[])[1,2,3,4,5,6]); 371 assert(buf.popFrontN(10) == 6); 372 buf.put(cast(ubyte[])[1,2,3,4,5,6,7,8]); 373 ubyte[12] data; 374 auto res = buf.fill(data[]); 375 assert(res.ptr == data[].ptr); 376 assert(res.length == buf.length); 377 assert(equal(cast(ubyte[])res, [1,2,3,4,5,6,7,8])); 378 } 379 380 unittest 381 { 382 auto buf = new CBufferCls(10); 383 buf.put(cast(ubyte[])[1,2,3,4,5,6]); 384 assert(buf.popFrontN(2) == 2); 385 ubyte[12] data; 386 auto res = buf.fill(data[]); 387 assert(res.length == buf.length); 388 assert(equal(cast(ubyte[])res, [3,4,5,6])); 389 }