1*627f7eb2Smrg /**
2*627f7eb2Smrg * Array container for internal usage.
3*627f7eb2Smrg *
4*627f7eb2Smrg * Copyright: Copyright Martin Nowak 2013.
5*627f7eb2Smrg * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
6*627f7eb2Smrg * Authors: Martin Nowak
7*627f7eb2Smrg */
8*627f7eb2Smrg module rt.util.container.array;
9*627f7eb2Smrg
10*627f7eb2Smrg static import common = rt.util.container.common;
11*627f7eb2Smrg
12*627f7eb2Smrg import core.exception : onOutOfMemoryErrorNoGC;
13*627f7eb2Smrg
Array(T)14*627f7eb2Smrg struct Array(T)
15*627f7eb2Smrg {
16*627f7eb2Smrg nothrow:
17*627f7eb2Smrg @disable this(this);
18*627f7eb2Smrg
19*627f7eb2Smrg ~this()
20*627f7eb2Smrg {
21*627f7eb2Smrg reset();
22*627f7eb2Smrg }
23*627f7eb2Smrg
24*627f7eb2Smrg void reset()
25*627f7eb2Smrg {
26*627f7eb2Smrg length = 0;
27*627f7eb2Smrg }
28*627f7eb2Smrg
29*627f7eb2Smrg @property size_t length() const
30*627f7eb2Smrg {
31*627f7eb2Smrg return _length;
32*627f7eb2Smrg }
33*627f7eb2Smrg
34*627f7eb2Smrg @property void length(size_t nlength)
35*627f7eb2Smrg {
36*627f7eb2Smrg import core.checkedint : mulu;
37*627f7eb2Smrg
38*627f7eb2Smrg bool overflow = false;
39*627f7eb2Smrg size_t reqsize = mulu(T.sizeof, nlength, overflow);
40*627f7eb2Smrg if (!overflow)
41*627f7eb2Smrg {
42*627f7eb2Smrg if (nlength < _length)
43*627f7eb2Smrg foreach (ref val; _ptr[nlength .. _length]) common.destroy(val);
44*627f7eb2Smrg _ptr = cast(T*)common.xrealloc(_ptr, reqsize);
45*627f7eb2Smrg if (nlength > _length)
46*627f7eb2Smrg foreach (ref val; _ptr[_length .. nlength]) common.initialize(val);
47*627f7eb2Smrg _length = nlength;
48*627f7eb2Smrg }
49*627f7eb2Smrg else
50*627f7eb2Smrg onOutOfMemoryErrorNoGC();
51*627f7eb2Smrg
52*627f7eb2Smrg }
53*627f7eb2Smrg
54*627f7eb2Smrg @property bool empty() const
55*627f7eb2Smrg {
56*627f7eb2Smrg return !length;
57*627f7eb2Smrg }
58*627f7eb2Smrg
59*627f7eb2Smrg @property ref inout(T) front() inout
60*627f7eb2Smrg in { assert(!empty); }
61*627f7eb2Smrg body
62*627f7eb2Smrg {
63*627f7eb2Smrg return _ptr[0];
64*627f7eb2Smrg }
65*627f7eb2Smrg
66*627f7eb2Smrg @property ref inout(T) back() inout
67*627f7eb2Smrg in { assert(!empty); }
68*627f7eb2Smrg body
69*627f7eb2Smrg {
70*627f7eb2Smrg return _ptr[_length - 1];
71*627f7eb2Smrg }
72*627f7eb2Smrg
73*627f7eb2Smrg ref inout(T) opIndex(size_t idx) inout
74*627f7eb2Smrg in { assert(idx < length); }
75*627f7eb2Smrg body
76*627f7eb2Smrg {
77*627f7eb2Smrg return _ptr[idx];
78*627f7eb2Smrg }
79*627f7eb2Smrg
80*627f7eb2Smrg inout(T)[] opSlice() inout
81*627f7eb2Smrg {
82*627f7eb2Smrg return _ptr[0 .. _length];
83*627f7eb2Smrg }
84*627f7eb2Smrg
85*627f7eb2Smrg inout(T)[] opSlice(size_t a, size_t b) inout
86*627f7eb2Smrg in { assert(a < b && b <= length); }
87*627f7eb2Smrg body
88*627f7eb2Smrg {
89*627f7eb2Smrg return _ptr[a .. b];
90*627f7eb2Smrg }
91*627f7eb2Smrg
92*627f7eb2Smrg alias length opDollar;
93*627f7eb2Smrg
94*627f7eb2Smrg void insertBack()(auto ref T val)
95*627f7eb2Smrg {
96*627f7eb2Smrg import core.checkedint : addu;
97*627f7eb2Smrg
98*627f7eb2Smrg bool overflow = false;
99*627f7eb2Smrg size_t newlength = addu(length, 1, overflow);
100*627f7eb2Smrg if (!overflow)
101*627f7eb2Smrg {
102*627f7eb2Smrg length = newlength;
103*627f7eb2Smrg back = val;
104*627f7eb2Smrg }
105*627f7eb2Smrg else
106*627f7eb2Smrg onOutOfMemoryErrorNoGC();
107*627f7eb2Smrg }
108*627f7eb2Smrg
109*627f7eb2Smrg void popBack()
110*627f7eb2Smrg {
111*627f7eb2Smrg length = length - 1;
112*627f7eb2Smrg }
113*627f7eb2Smrg
114*627f7eb2Smrg void remove(size_t idx)
115*627f7eb2Smrg in { assert(idx < length); }
116*627f7eb2Smrg body
117*627f7eb2Smrg {
118*627f7eb2Smrg foreach (i; idx .. length - 1)
119*627f7eb2Smrg _ptr[i] = _ptr[i+1];
120*627f7eb2Smrg popBack();
121*627f7eb2Smrg }
122*627f7eb2Smrg
123*627f7eb2Smrg void swap(ref Array other)
124*627f7eb2Smrg {
125*627f7eb2Smrg auto ptr = _ptr;
126*627f7eb2Smrg _ptr = other._ptr;
127*627f7eb2Smrg other._ptr = ptr;
128*627f7eb2Smrg immutable len = _length;
129*627f7eb2Smrg _length = other._length;
130*627f7eb2Smrg other._length = len;
131*627f7eb2Smrg }
132*627f7eb2Smrg
133*627f7eb2Smrg invariant
134*627f7eb2Smrg {
135*627f7eb2Smrg assert(!_ptr == !_length);
136*627f7eb2Smrg }
137*627f7eb2Smrg
138*627f7eb2Smrg private:
139*627f7eb2Smrg T* _ptr;
140*627f7eb2Smrg size_t _length;
141*627f7eb2Smrg }
142*627f7eb2Smrg
143*627f7eb2Smrg unittest
144*627f7eb2Smrg {
145*627f7eb2Smrg Array!size_t ary;
146*627f7eb2Smrg
147*627f7eb2Smrg assert(ary[] == []);
148*627f7eb2Smrg ary.insertBack(5);
149*627f7eb2Smrg assert(ary[] == [5]);
150*627f7eb2Smrg assert(ary[$-1] == 5);
151*627f7eb2Smrg ary.popBack();
152*627f7eb2Smrg assert(ary[] == []);
153*627f7eb2Smrg ary.insertBack(0);
154*627f7eb2Smrg ary.insertBack(1);
155*627f7eb2Smrg assert(ary[] == [0, 1]);
156*627f7eb2Smrg assert(ary[0 .. 1] == [0]);
157*627f7eb2Smrg assert(ary[1 .. 2] == [1]);
158*627f7eb2Smrg assert(ary[$ - 2 .. $] == [0, 1]);
159*627f7eb2Smrg size_t idx;
160*627f7eb2Smrg foreach (val; ary) assert(idx++ == val);
161*627f7eb2Smrg foreach_reverse (val; ary) assert(--idx == val);
162*627f7eb2Smrg foreach (i, val; ary) assert(i == val);
163*627f7eb2Smrg foreach_reverse (i, val; ary) assert(i == val);
164*627f7eb2Smrg
165*627f7eb2Smrg ary.insertBack(2);
166*627f7eb2Smrg ary.remove(1);
167*627f7eb2Smrg assert(ary[] == [0, 2]);
168*627f7eb2Smrg
169*627f7eb2Smrg assert(!ary.empty);
170*627f7eb2Smrg ary.reset();
171*627f7eb2Smrg assert(ary.empty);
172*627f7eb2Smrg ary.insertBack(0);
173*627f7eb2Smrg assert(!ary.empty);
174*627f7eb2Smrg destroy(ary);
175*627f7eb2Smrg assert(ary.empty);
176*627f7eb2Smrg
177*627f7eb2Smrg // not copyable
178*627f7eb2Smrg static assert(!__traits(compiles, { Array!size_t ary2 = ary; }));
179*627f7eb2Smrg Array!size_t ary2;
180*627f7eb2Smrg static assert(!__traits(compiles, ary = ary2));
181*627f7eb2Smrg static void foo(Array!size_t copy) {}
182*627f7eb2Smrg static assert(!__traits(compiles, foo(ary)));
183*627f7eb2Smrg
184*627f7eb2Smrg ary2.insertBack(0);
185*627f7eb2Smrg assert(ary.empty);
186*627f7eb2Smrg assert(ary2[] == [0]);
187*627f7eb2Smrg ary.swap(ary2);
188*627f7eb2Smrg assert(ary[] == [0]);
189*627f7eb2Smrg assert(ary2.empty);
190*627f7eb2Smrg }
191*627f7eb2Smrg
192*627f7eb2Smrg unittest
193*627f7eb2Smrg {
194*627f7eb2Smrg alias RC = common.RC!();
195*627f7eb2Smrg Array!RC ary;
196*627f7eb2Smrg
197*627f7eb2Smrg size_t cnt;
198*627f7eb2Smrg assert(cnt == 0);
199*627f7eb2Smrg ary.insertBack(RC(&cnt));
200*627f7eb2Smrg assert(cnt == 1);
201*627f7eb2Smrg ary.insertBack(RC(&cnt));
202*627f7eb2Smrg assert(cnt == 2);
203*627f7eb2Smrg ary.back = ary.front;
204*627f7eb2Smrg assert(cnt == 2);
205*627f7eb2Smrg ary.popBack();
206*627f7eb2Smrg assert(cnt == 1);
207*627f7eb2Smrg ary.popBack();
208*627f7eb2Smrg assert(cnt == 0);
209*627f7eb2Smrg }
210*627f7eb2Smrg
211*627f7eb2Smrg unittest
212*627f7eb2Smrg {
213*627f7eb2Smrg import core.exception;
214*627f7eb2Smrg try
215*627f7eb2Smrg {
216*627f7eb2Smrg // Overflow ary.length.
217*627f7eb2Smrg auto ary = Array!size_t(cast(size_t*)0xdeadbeef, -1);
218*627f7eb2Smrg ary.insertBack(0);
219*627f7eb2Smrg }
catch(OutOfMemoryError)220*627f7eb2Smrg catch (OutOfMemoryError)
221*627f7eb2Smrg {
222*627f7eb2Smrg }
223*627f7eb2Smrg try
224*627f7eb2Smrg {
225*627f7eb2Smrg // Overflow requested memory size for common.xrealloc().
226*627f7eb2Smrg auto ary = Array!size_t(cast(size_t*)0xdeadbeef, -2);
227*627f7eb2Smrg ary.insertBack(0);
228*627f7eb2Smrg }
catch(OutOfMemoryError)229*627f7eb2Smrg catch (OutOfMemoryError)
230*627f7eb2Smrg {
231*627f7eb2Smrg }
232*627f7eb2Smrg }
233