1 module dvector;
2 
3 version(LDC){
4     pragma(LDC_no_moduleinfo);
5 }
6 
7 import core.stdc.stdlib;
8 import core.stdc.string;
9 
10 private enum CAPACITY = 4;
11 
12 struct Dvector(T) {
13     private T* chunks;
14     size_t total;
15     size_t capacity;
16 
17     @property T front() @nogc nothrow {
18         return chunks[0];
19     }
20 
21     @property T back() @nogc nothrow {
22         return chunks[length-1];
23     }
24 
25     size_t length() @nogc nothrow {
26         return total;
27     }
28     
29     @property bool empty() const @nogc nothrow {
30         return total == 0;
31     }
32 
33     void popFront() @nogc nothrow {
34         remove(0);
35     }
36 
37     void popBack() @nogc nothrow {
38         remove(length-1);
39     }
40 
41     /** !!! WARNING !!!
42     Use it carefully with the standard library.
43     Be sure that the standard library functions don't implicitly copy it.
44     But, it is Ok if the standard library functions return a handle of copied range
45     so that you can free it manually. Otherwise, you leak memory.
46     */
47     Dvector!T save() const @nogc nothrow {
48         T* cc_chunks = cast(T*)malloc(T.sizeof * this.capacity);
49         memcpy(cc_chunks, chunks, capacity * T.sizeof);
50         return Dvector!T(cc_chunks, this.total, this.capacity);
51     }
52 
53     this(T* chunks, size_t total, size_t capacity) @nogc nothrow {
54         this.chunks = chunks;
55         this.total = total;
56         this.capacity = capacity;
57     }
58     
59     void pushBack(T elem) @nogc nothrow {
60         allocIfneeded();
61         if (capacity == total)
62             resize(capacity * 2);
63         chunks[total++] = elem;
64     }
65     
66     alias pBack = pushBack;
67 
68     ref T opIndex(size_t i) @nogc nothrow {
69         return chunks[i];
70     }
71     
72     void opIndexAssign(T elem, size_t i) @nogc nothrow {
73         chunks[i] = elem;
74     }
75     
76     void remove(size_t index) @nogc nothrow {
77         for (size_t i = index; i < total - 1; i++) {
78             chunks[i] = chunks[i + 1];
79         }
80 
81         total--;
82 
83         if (total > 0 && total == capacity / 4){
84             resize(capacity / 2);
85         }
86     }
87     
88     void allocIfneeded() @nogc nothrow {
89         if(chunks is null){
90             capacity = CAPACITY;
91             T* _chunks = cast(T*)malloc(T.sizeof * CAPACITY);
92             this.chunks = _chunks;
93         }
94     }
95 
96     void resize(size_t capacity) @nogc nothrow {
97         version(Debug){
98             import core.stdc.stdio;
99             printf("resize: %d to %d\n", this.capacity, capacity);
100         }
101 
102         T* chunks = cast(T*)realloc(this.chunks, T.sizeof * capacity);
103         if (chunks) {
104             this.chunks = chunks;
105             this.capacity = capacity;
106         }
107     }
108 
109     void free() @nogc nothrow {
110         total = 0;
111         capacity = CAPACITY;
112         core.stdc.stdlib.free(chunks);
113         chunks = null;
114     }
115     
116     int opApply(int delegate(ref T) @nogc nothrow dg) @nogc nothrow{
117         int result = 0;
118 
119         for (size_t k = 0; k < total; ++k) {
120             result = dg(chunks[k]);
121 
122             if (result) {
123                 break;
124             }
125         }
126         return result;
127     }
128     
129     int opApply(int delegate(size_t i, ref T) @nogc nothrow dg) @nogc nothrow{
130         int result = 0;
131 
132         for (size_t k = 0; k < total; ++k) {
133             result = dg(k, chunks[k]);
134 
135             if (result) {
136                 break;
137             }
138         }
139         return result;
140     }
141     
142     // overloads for gc usages:
143     int opApply(int delegate(ref T) dg){
144         int result = 0;
145 
146         for (size_t k = 0; k < total; ++k) {
147             result = dg(chunks[k]);
148 
149             if (result) {
150                 break;
151             }
152         }
153         return result;
154     }
155     
156     int opApply(int delegate(size_t i, ref T) dg){
157         int result = 0;
158 
159         for (size_t k = 0; k < total; ++k) {
160             result = dg(k, chunks[k]);
161 
162             if (result) {
163                 break;
164             }
165         }
166         return result;
167     }
168     
169     Dvector!T opBinary(string op)(ref Dvector!T rhs) @nogc nothrow{
170         static if (op == "~"){
171             allocIfneeded();
172             foreach(elem; rhs)
173                 pushBack(elem);
174             return this;
175         } 
176         else static assert(0, "Operator "~op~" not implemented");
177     }
178     
179     Dvector!T opBinary(string op)(T rhs) @nogc nothrow {
180         static if (op == "~"){
181             allocIfneeded();
182             pushBack(rhs);
183             return this;
184         } 
185         else static assert(0, "Operator "~op~" not implemented");
186     }
187 
188     @nogc nothrow Dvector!T opOpAssign(string op)(ref Dvector!T rhs) if (op == "~"){
189         allocIfneeded();
190         foreach(elem; rhs)
191             pushBack(elem);
192         return this;
193     }
194 
195     @nogc nothrow Dvector!T opOpAssign(string op)(ref T rhs) if (op == "~"){
196         allocIfneeded();
197         pushBack(rhs);
198         return this;
199     }
200 
201     void pushFront(T elem) @nogc nothrow{
202         allocIfneeded();
203         pushBack(T.init);
204 
205         for(size_t i = length-1; i > 0; i--){
206             chunks[i] = chunks[i - 1];
207         }
208         chunks[0] = elem;
209     }
210     
211     void insert(T elem, size_t position) @nogc nothrow{
212         allocIfneeded();
213         pushBack(T.init);
214 
215         for (size_t k = length-1; k > position; k--)
216             chunks[k] = chunks[k - 1];
217         chunks[position] = elem;
218     }
219     
220     T[] slice() @nogc nothrow{
221         return chunks[0..length];
222     }
223 }
224 
225 unittest {
226     import core.stdc.stdio;
227     struct Person { string name; uint score;}
228     
229     Dvector!(Person) prs1;
230     
231     auto p1 = Person("ferhat", 5);
232     auto p2 = Person("Mike", 3);
233     auto p3 = Person("Rajneesh", 1);
234     auto p4 = Person("Ce", 2);
235     
236     prs1 ~= p1;
237     prs1 ~= p2;
238     prs1 ~= p3;
239     prs1 ~= p4;
240 
241     Dvector!(Person) prs2;
242     auto s1 = Person("Ezgi", 15);
243     auto s2 = Person("Emine", 36);
244     
245     prs2 ~= s1;
246     prs2 ~= s2;
247     
248     auto comb = prs1 ~ prs2;
249     
250     comb.remove(2);
251     
252     assert(comb[2].name == "Ce");
253     
254     auto cn = Person("Chuck", 100);
255     comb.pushFront(cn);
256     
257     assert(comb[0].name == "Chuck");
258     
259     auto srv = Person("SRV", 100);
260     comb.insert(srv, 3);
261     
262     assert(comb[3].name == "SRV");
263     
264     foreach(i, p; comb){
265         printf("%d: %s \n", i, p.name.ptr);
266     }
267     
268     comb.free;
269     prs2.free;
270 }