1 /*
2     License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
3     Authors:   Adam Búš
4 */
5 module btl.vector.storage;
6 
7 
8 
9 
10 package template Storage(T, size_t N, bool allowHeap){
11 
12     struct Storage{
13         public alias Inline = InlineStorage!(T, N);
14 
15         public alias Heap = HeapStorage!(T, allowHeap);
16 
17         public enum size_t minimalCapacity = Inline.capacity;
18 
19         public enum size_t maximalCapacity = allowHeap ? size_t.max : N;
20 
21         public size_t length;
22 
23         union{
24             static if(N > 0){
25                 private Inline _inline;
26                 private Heap _heap;
27             }
28             else{
29                 private Heap _heap;
30                 private Inline _inline;
31             }
32         }
33 
34         pragma(inline, true){
35             public static size_t heapCapacity(size_t new_capacity)pure nothrow @safe @nogc{
36                 new_capacity |= heapFlag;
37                 assert(new_capacity > minimalCapacity);
38                 assert(new_capacity <= maximalCapacity);
39 
40                 return new_capacity;
41             }
42 
43             public void reset()pure nothrow @trusted @nogc{
44                 this.length = 0;
45 
46 
47                 static if(N){
48                     this._inline.reset();
49                 }
50                 else static if(allowHeap){
51                     this._heap.capacity = 0;
52                     this._heap.ptr = null;
53 
54                 }
55             }
56 
57             public @property ref inout(Inline) inline()inout pure nothrow @trusted @nogc{
58                 return this._inline;
59             }
60 
61             public @property ref inout(Heap) heap()inout pure nothrow @trusted @nogc{
62                 return this._heap;
63             }
64             public @property void heap(Heap h)pure nothrow @trusted @nogc{
65                 static if(allowHeap){
66                     assert(this.length <= h.capacity);
67                     this._heap.capacity = h.capacity;
68                     assert(this.external);
69                     this._heap.ptr = h.ptr;
70                 }
71                 else{
72                     assert(0, "no impl");
73                 }
74             }
75 
76             public @property size_t capacity()scope const pure nothrow @safe @nogc{
77                 return this.external
78                     ? this.heap.capacity
79                     : this.inline.capacity;
80             }
81 
82             public @property inout(T)* ptr()scope inout pure nothrow @trusted @nogc{
83                 return this.external
84                     ? this.heap.ptr
85                     : this.inline.ptr;
86             }
87 
88             public @property inout(T)[] elements()scope inout pure nothrow @trusted @nogc{
89                 return this.external
90                     ? this.heap.elements(this.length)
91                     : this.inline.elements(this.length);
92             }
93 
94             public @property inout(T)[] allocatedElements()inout return pure nothrow @trusted @nogc{
95                 return this.external
96                     ? this.heap.allocatedElements()
97                     : this.inline.allocatedElements();
98             }
99 
100             public @property bool external()const scope pure nothrow @trusted @nogc{
101                 static if(allowHeap && N)
102                     return (this._inline.flag & heapFlag);
103                 else
104                     return allowHeap;
105             }
106             public @property void external(bool x)scope pure nothrow @trusted @nogc{
107                 static if(allowHeap && N)
108                     this._inline.flag = x ? heapFlag : 0;
109                 else
110                     assert(0, "no impl");
111             }
112 
113             public @property bool small()const pure nothrow @trusted @nogc{
114                 static if(allowHeap){
115                     static if(N == 0)
116                         return (this._heap.capacity == 0);
117                     else
118                         return !this.external;
119                 }
120                 else
121                     return true;
122             }
123         }
124 
125     }
126 
127     enum ubyte heapFlag = allowHeap
128         ? 0x1   //heap capacity must be odd
129         : 0;
130 }
131 
132 private struct InlineStorage(T, size_t N){
133     public enum size_t capacity = N;   //max(N, 2);
134 
135     static if(N){
136         public align(T.alignof)ubyte flag = 0;
137         public void[capacity * T.sizeof] storage;
138     }
139     else{
140         public enum ubyte flag = 0;
141         public enum void[] storage = null;
142     }
143 
144 
145     pragma(inline, true){
146         public void reset()pure nothrow @safe @nogc{
147             static if(N)
148                 this.flag = 0;
149         }
150 
151         public @property inout(T)* ptr()inout pure nothrow @system @nogc{
152             return cast(inout(T)*)storage.ptr;
153         }
154 
155         public @property inout(void)[] data()inout pure nothrow @system @nogc{
156             return storage[];
157         }
158 
159         public @property inout(T)[] elements(size_t length)inout pure nothrow @system @nogc{
160             assert(length <= capacity);
161             return ptr[0 .. length];
162         }
163 
164         public @property inout(T)[] allocatedElements()inout pure nothrow @system @nogc{
165             return ptr[0 .. capacity];
166         }
167     }
168 }
169 
170 private struct HeapStorage(T, bool allowHeap){
171 
172     static if(allowHeap){
173         public size_t capacity;
174         public T* ptr;
175     }
176     else{
177         public @property size_t capacity()const pure nothrow @safe @nogc{return 0;}
178         public @property void capacity(size_t)pure nothrow @safe @nogc{assert(0, "no impl");}
179 
180         public @property inout(T)* ptr()inout pure nothrow @safe @nogc{return null;}
181         public @property void ptr(T*)pure nothrow @safe @nogc{assert(0, "no impl");}
182     }
183 
184     pragma(inline, true){
185 
186         public @property inout(void)[] data()inout pure nothrow @trusted @nogc{
187             return (cast(inout void*)ptr)[0 .. capacity * T.sizeof];
188         }
189 
190         public @property inout(T)[] elements(size_t length)inout pure nothrow @system @nogc{
191             assert(length <= capacity);
192             return ptr[0 .. length];
193         }
194 
195         public @property inout(T)[] allocatedElements()inout pure nothrow @system @nogc{
196             return ptr[0 .. capacity];
197         }
198     }
199 }