1 module anansi.container.list;
2 
3 import std.algorithm, std.conv, std.range, std.stdio, std.traits, std.typecons;
4 
5 /**
6  * A doubley-linked list with a deliberately leaky abstraction. This container
7  * is explicitly for use with the anansi graph classes.
8  */
9 public struct List(T) {
10 private:
11     this(size_t s, Node* f, Node* b) {
12         _size = s;
13         _front = f;
14         _back = b;
15     }
16 
17 public:
18     this(this) {
19         auto chain = copyChain(_front, _back);
20         _front = chain[0];
21         _back = chain[1];
22     }
23 
24 public:
25     /**
26      * The internal data storage object
27      */
28     static struct Node {
29         protected this(T v, Node* p, Node* n) {
30             value = v;
31             p = prev;
32             n = next;
33         }
34 
35         public @property inout(Node*) nextNode() inout {
36             return next;
37         }
38 
39         protected Node* prev;
40         protected Node* next;
41         public T value;
42 
43         public @property ref inout(T) valueRef() inout {
44             return value;
45         }
46     }
47 
48     static struct ConstRange {
49         public this(const(Node)* front, const(Node)* back) {
50             _front = front;
51             _back = back;
52         }
53 
54         @property bool empty() const {
55             return (_front is null);
56         }
57 
58         @property ref const(T) front() const
59         in {
60             assert (_front !is null);
61         }
62         body {
63             return (_front.value);
64         }
65 
66         void popFront()
67         in {
68             assert (_front !is null);
69         }
70         body {
71             if (_front is _back)
72                 _front = _back = null;
73             else
74                 _front = _front.next;
75         }
76 
77         @property ConstRange save() { return this; }
78 
79         public @property const(Node)* frontNode() {
80             return _front;
81         }
82 
83     private:
84         const(Node)* _front;
85         const(Node)* _back;
86     }
87 
88     static struct Range {
89         public this(Node* front, Node* back) {
90             _front = front;
91             _back = back;
92         }
93 
94         @property bool empty() const {
95             return (_front is null);
96         }
97 
98         @property ref T front()
99         in {
100             assert (_front !is null);
101         }
102         body {
103             return _front.value;
104         }
105 
106         void popFront()
107         in {
108             assert (_front !is null);
109         }
110         body {
111             if (_front is _back)
112                 _front = _back = null;
113             else
114                 _front = _front.next;
115         }
116 
117         @property Range save() { return this; }
118 
119         public @property Node* frontNode() { return _front; }
120 
121     private:
122         Node* _front;
123         Node* _back;
124     }
125 
126     invariant() {
127         assert (_size >= 0, "Size must remain positive.");
128     }
129 
130     this(Stuff)(Stuff stuff) if(isInputRange!Stuff &&
131                                 isImplicitlyConvertible!(ElementType!Range, T)) {
132         foreach(s; stuff)
133             insertBack(s);
134     }
135 
136     Range opSlice() { return Range(_front, _back); }
137     ConstRange opSlice() const { return ConstRange(_front, _back); }
138 
139     Node* insertBack(T value)
140     out(result) {
141         assert (result !is null);
142     }
143     body {
144         auto newNode = new Node(value, null, null);
145         if (empty) {
146             _front = _back = newNode;
147         }
148         else {
149             newNode.prev = _back;
150             _back.next = newNode;
151             _back = newNode;
152         }
153 
154         _size += 1;
155         return newNode;
156     }
157 
158     void remove(Node* node)
159     in {
160         assert (node !is null);
161         assert (_size > 0);
162     }
163     out {
164         assert (_size >= 0);
165     }
166     body {
167         if (node is _front && node is _back) {
168             _front = _back = null;
169         }
170         else if (node is _front) {
171             _front = _front.next;
172             _front.prev = null;
173         }
174         else if (node is _back) {
175             _back = _back.prev;
176             _back.next = null;
177         }
178         else {
179             node.next.prev = node.prev;
180             node.prev.next = node.next;
181         }
182         --_size;
183     }
184 
185     ref inout(T) front() inout
186     in {
187         assert (_front !is null);
188     }
189     body {
190         return _front.value;
191     }
192 
193     @property inout(Node*) frontNode() inout { return _front; }
194 
195     ref inout(T) back() inout
196     in {
197         assert (_back !is null);
198     }
199     body {
200         return _back.value;
201     }
202 
203     @property inout(Node*) backNode() inout { return _back; }
204 
205     @property size_t length() const {
206         return _size;
207     }
208 
209     @property bool empty() const {
210         return _back is null;
211     }
212 
213     @property List dup() {
214         auto newChain = copyChain(_front, _back);
215 
216         return List(_size, newChain[0], newChain[1]);
217     }
218 
219 private:
220     static auto copyChain(Node* front, Node* back) {
221         Node* newFront = null;
222         Node* newBack = null;
223 
224         if (front !is null) {
225             newFront = newBack = new Node(front.value, null, null);
226             for(auto n = front.next; n != null; n = n.next) {
227                 auto newNode = new Node(n.value, newBack, null);
228                 newBack.next = newNode;
229                 newBack = newNode;
230             }
231         }
232 
233         return tuple(newFront, newBack);
234     }
235 
236 private:
237     Node* _front;
238     Node* _back;
239     size_t _size;
240 }
241 
242 unittest {
243     writeln("List: default construction.");
244     List!int l;
245     assert (l.length == 0);
246 }
247 
248 unittest {
249     writeln("List: construct from a Range.");
250     auto data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
251     auto list = List!int(data);
252     assert (list.length == data.length,
253     "Bad length value, expected: " ~ to!string(data.length) ~
254     ", got: " ~ to!string(list.length));
255 
256     foreach(x; zip(data, list[])) {
257         assert(x[0] == x[1],
258             "Bad list value, expected: " ~ to!string(x[0]) ~
259             ", got: " ~ to!string(x[1]));
260     }
261 }
262 
263 unittest {
264     writeln("List: empty range correctly marked as empty.");
265     List!int l;
266     assert(l[].empty, "An empty range should return empty == true");
267 }
268 
269 unittest {
270     writeln("List: remove only element in list.");
271     List!char l;
272     auto pn = l.insertBack('a');
273     l.remove(pn);
274 
275     assert (l.length == 0,
276         "Length must be 0 after removing the only element.");
277 
278     size_t count;
279     foreach(c; l[])
280     ++count;
281 
282     assert(count == 0,
283         "Iterting over an empty list should never invoke loop body.");
284 }
285 
286 unittest {
287     writeln("List: remove first element in list.");
288     List!int l;
289     auto n0 = l.insertBack(0);
290     auto n1 = l.insertBack(1);
291     auto n2 = l.insertBack(2);
292 
293     l.remove(n0);
294 
295     assert (l.length == 2);
296 
297     foreach(x; zip([1, 2], l[])) {
298         assert(x[0] == x[1],
299             "Bad list value, expected: " ~ to!string(x[0]) ~
300             ", got: " ~ to!string(x[1]));
301     }
302 }
303 
304 unittest {
305     writeln("List: remove last element in list.");
306     List!int l;
307     auto n0 = l.insertBack(0);
308     auto n1 = l.insertBack(1);
309     auto n2 = l.insertBack(2);
310 
311     l.remove(n2);
312 
313     assert (l.length == 2);
314 
315     foreach(x; zip([0, 1], l[])) {
316         assert(x[0] == x[1],
317             "Bad list value, expected: " ~ to!string(x[0]) ~
318             ", got: " ~ to!string(x[1]));
319     }
320 }
321 
322 unittest {
323     writeln("List: remove middle element in list.");
324     List!int l;
325     auto n0 = l.insertBack(0);
326     auto n1 = l.insertBack(1);
327     auto n2 = l.insertBack(2);
328 
329     l.remove(n1);
330 
331     assert (l.length == 2);
332 
333     foreach(x; zip([0, 2], l[])) {
334     assert(x[0] == x[1],
335         "Bad list value, expected: " ~ to!string(x[0]) ~
336         ", got: " ~ to!string(x[1]));
337     }
338 
339     assert (l.front() == 0);
340     assert (l.back() == 2);
341 }
342 
343 unittest {
344     writeln("List: remove all-but-one element in a list.");
345     List!int l;
346     auto n0 = l.insertBack(0);
347     auto n1 = l.insertBack(1);
348     auto n2 = l.insertBack(2);
349 
350     l.remove(n1);
351     l.remove(n2);
352 
353     assert (l.length == 1);
354 
355     foreach(x; zip([0], l[])) {
356         assert(x[0] == x[1],
357             "Bad list value, expected: " ~ to!string(x[0]) ~
358             ", got: " ~ to!string(x[1]));
359     }
360 }
361 
362 unittest {
363     writeln("List: remove all elements in a list.");
364     List!int l;
365     auto n0 = l.insertBack(0);
366     auto n1 = l.insertBack(1);
367     auto n2 = l.insertBack(2);
368 
369     l.remove(n1);
370     l.remove(n2);
371     l.remove(n0);
372 
373     assert (l.length == 0);
374     size_t count = 0;
375     foreach(_; l[]) {
376         ++count;
377     }
378 
379     assert (count == 0,
380         "iterating over an empty range should never hit the loop body.");
381 }