1 module dkh.container.stackpayload;
2 
3 /**
4 Stack Payload
5 
6 If you don't need dark speed, you should use dkh.container.stack
7  */
8 struct StackPayload(T, size_t MINCAP = 4) if (MINCAP >= 1) {
9     import core.exception : RangeError;
10 
11     private T* _data;
12     private uint len, cap;
13 
14     @property bool empty() const { return len == 0; }
15     @property size_t length() const { return len; }
16     alias opDollar = length;
17 
18     /**
19     Data Slice
20     Warning: Return value points same place with stackpayload
21      */
22     inout(T)[] data() inout { return (_data) ? _data[0..len] : null; }
23     
24     ref inout(T) opIndex(size_t i) inout {
25         version(assert) if (len <= i) throw new RangeError();
26         return _data[i];
27     } ///
28     ref inout(T) front() inout { return this[0]; } ///
29     ref inout(T) back() inout { return this[$-1]; } ///
30 
31     void reserve(size_t newCap) {
32         import core.memory : GC;
33         import core.stdc.string : memcpy;
34         import std.conv : to;
35         if (newCap <= cap) return;
36         void* newData = GC.malloc(newCap * T.sizeof);
37         cap = newCap.to!uint;
38         if (len) memcpy(newData, _data, len * T.sizeof);
39         _data = cast(T*)(newData);
40     } ///
41     void free() {
42         import core.memory : GC;
43         GC.free(_data);
44     } ///
45     /// This method don't release memory
46     void clear() {
47         len = 0;
48     }
49 
50     void insertBack(T item) {
51         import std.algorithm : max;
52         if (len == cap) reserve(max(cap * 2, MINCAP));
53         _data[len++] = item;
54     } ///
55     alias opOpAssign(string op : "~") = insertBack; /// ditto
56     void removeBack() {
57         assert(!empty, "StackPayload.removeBack: Stack is empty");
58         len--;
59     } ///
60 }
61 
62 unittest {
63     import std.algorithm : equal;
64     auto u = StackPayload!int();
65     u ~= 4; u ~= 5;
66     assert(equal(u.data, [4, 5]));
67 }