1 // This file is part of Visual D
2 //
3 // Visual D integrates the D programming language into Visual Studio
4 // Copyright (c) 2010 by Rainer Schuetze, All Rights Reserved
5 //
6 // Distributed under the Boost Software License, Version 1.0.
7 // See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt
8 
9 // simple double linked list
10 
11 module c2d.dlist;
12 
13 struct DListNode(T)
14 {
15 	T data;
16 
17 	DListNode!(T)* _next;
18 	DListNode!(T)* _prev;
19 }
20 
21 class DList(T)
22 {
23 	DListNode!(T) root;
24 
25 	this()
26 	{
27 		root._next = &root;
28 		root._prev = &root;
29 	}
30 
31 	bool empty()
32 	{
33 		return root._next == &root;
34 	}
35 
36 	int count()
37 	{
38 		int cnt = 0;
39 		for(auto p = root._next; p != &root; p = p._next)
40 			cnt++;
41 		return cnt;
42 	}
43 
44 	void append(T item)
45 	{
46 		insertBefore(item, &root);
47 	}
48 
49 	void prepend(T item)
50 	{
51 		insertAfter(item, &root);
52 	}
53 
54 	DListNode!(T)* insertBefore(T data, DListNode!(T)* ins)
55 	{
56 		DListNode!(T) *node = new DListNode!(T);
57 		node.data = data;
58 		insertBefore(node, ins);
59 		return node;
60 	}
61 
62 	DListNode!(T)* insertAfter(T data, DListNode!(T)* ins)
63 	{
64 		DListNode!(T) *node = new DListNode!(T);
65 		node.data = data;
66 		insertAfter(node, ins);
67 		return node;
68 	}
69 
70 	void insertAfter(DListNode!(T)* node, DListNode!(T)* ins)
71 	{
72 		insertBefore(node, ins._next);
73 	}
74 
75 	void insertBefore(DListNode!(T) *node, DListNode!(T)* ins)
76 	{
77 		node._next = ins;
78 		node._prev = ins._prev;
79 		ins._prev._next = node;
80 		ins._prev = node;
81 	}
82 
83 	void remove(DListNode!(T)* node)
84 	{
85 		node._prev._next = node._next;
86 		node._next._prev = node._prev;
87 		node._next = null;
88 		node._prev = null;
89 	}
90 
91 	// removes entries from list
92 	void appendList(DList!(T) list)
93 	{
94 		insertListAfter(root._prev, list);
95 	}
96 
97 	// removes entries from list
98 	void insertListAfter(DListNode!(T)* node, DList!(T) list)
99 	{
100 		if(list.empty())
101 			return;
102 
103 		DListNode!(T)* first = list.root._next;
104 		DListNode!(T)* last  = list.root._prev;
105 		
106 		// wipe the list
107 		list.root._next = &list.root;
108 		list.root._prev = &list.root;
109 
110 		node._next._prev = last;
111 		last._next = node._next;
112 		first._prev = node;
113 		node._next = first;
114 	}
115 
116 	// insert entries to list, return node to beginning of inserted list
117 	DListNode!(T)* insertListBefore(DListNode!(T)* node, DList!(T) list)
118 	{
119 		if(node is &root)
120 		{
121 			insertListAfter(node._prev, list);
122 			return &root;
123 		}
124 		else
125 		{
126 			DListNode!(T)* _prev = node._prev;
127 			insertListAfter(node._prev, list);
128 			return _prev._next;
129 		}
130 	}
131 
132 	void insertListAfter(ref DListIterator!(T) it, DList!(T) list)
133 	{
134 		assert(it._list is this);
135 		insertListAfter(it._pos, list);
136 	}
137 
138 	void insertListBefore(ref DListIterator!(T) it, DList!(T) list)
139 	{
140 		assert(it._list is this);
141 		insertListBefore(it._pos, list);
142 	}
143 
144 	DList!(T) remove(DListNode!(T)* from, DListNode!(T)* to)
145 	{
146 		DList!(T) list = new DList!(T);
147 		if (from is to)
148 			return list;
149 		
150 		assert(from != &root);
151 
152 		DListNode!(T)* last = to._prev;
153 
154 		from._prev._next = to;
155 		to._prev = from._prev;
156 		
157 		list.root._next = from;
158 		list.root._prev = last;
159 
160 		from._prev = &list.root;
161 		last._next = &list.root;
162 
163 		return list;
164 	}
165 
166 	DList!(T) remove(ref DListIterator!(T) from, ref DListIterator!(T) to)
167 	{
168 		DList!(T) list = remove(from._pos, to._pos);
169 		from._pos = to._pos;
170 		return list;
171 	}
172 
173 	DListIterator!(T) find(T data)
174 	{
175 		DListIterator!(T) it = begin();
176 		while(!it.atEnd())
177 		{
178 			if(*it == data)
179 				break;
180 			it.advance();
181 		}
182 		return it;
183 	}
184 
185 	DListIterator!(T) begin()
186 	{
187 		DListIterator!(T) it = DListIterator!(T)(this);
188 		it._pos = root._next;
189 		return it;
190 	}
191 
192 	DListIterator!(T) end()
193 	{
194 		DListIterator!(T) it = DListIterator!(T)(this);
195 		it._pos = &root;
196 		return it;
197 	}
198 
199 	ref T opIndex(int idx)
200 	{
201 		DListIterator!(T) it = begin();
202 		it += idx;
203 		return *it;
204 	}
205 }
206 
207 struct DListIterator(T)
208 {
209 	DListNode!(T)* _pos;
210 	DList!(T) _list;
211 
212 	this(DList!(T) list)
213 	{
214 		_list = list;
215 	}
216 
217 	bool valid() const 
218 	{
219 		return _list !is null;
220 	}
221 
222 	void setList(DList!(T) list)
223 	{
224 		_list = list;
225 	}
226 
227 	DList!(T) getList()
228 	{
229 		return _list;
230 	}
231 
232 version(none) // opDot deprecated
233 {
234 	alias opStar this;
235 
236 	// https://issues.dlang.org/show_bug.cgi?id=16657 need to define opEquals with alias this
237 	bool opEquals(const typeof(this) other) const
238 	{
239 		return _pos == other._pos; // no need to compare lists, nodes belong to only one list
240 	}
241 }
242 else version(all) // alias this too broken with operator overloads
243 {
244 	ref auto opDispatch(string op, ARGS...)(auto ref ARGS args) if (ARGS.length == 0)
245 	{
246 		enum sym = "_pos.data." ~ op;
247 		return mixin(sym);
248 	}
249 	auto opDispatch(string op, ARGS...)(auto ref ARGS args) if (ARGS.length == 1) // could be field = value
250 	{
251 		enum sym = "_pos.data." ~ op;
252 		static if (__traits(compiles, mixin(sym) = args[0]))
253 			return mixin(sym) = args[0];
254 		else
255 			return mixin(sym)(args);
256 	}
257 	auto opDispatch(string op, ARGS...)(auto ref ARGS args) if (ARGS.length > 1)
258 	{
259 		enum sym = "_pos.data." ~ op;
260 		return mixin(sym)(args);
261 	}
262 }
263 else
264 {
265 	ref T opDot()
266 	{
267 		return _pos.data;
268 	}
269 }
270 
271 	ref T opUnary(string op)() if(op == "*")
272 	{
273 		return _pos.data;
274 	}
275 
276 	void opUnary(string op)() if(op == "++")
277 	{
278 		advance();
279 	}
280 
281 	void opUnary(string op)() if(op == "--")
282 	{
283 		retreat();
284 	}
285 
286 	ref T opIndex(int idx)
287 	{
288 		DListIterator!(T) it = this;
289 		it += idx;
290 		return *it;
291 	}
292 
293 	DListIterator!(T) opBinary(string op)(int cnt) if(op == "+")
294 	{
295 		DListIterator!(T) it = this;
296 		it += cnt;
297 		return it;
298 	}
299 
300 	DListIterator!(T) opBinary(string op)(int cnt) if(op == "-")
301 	{
302 		DListIterator!(T) it = this;
303 		it += -cnt;
304 		return it;
305 	}
306 
307 	void advance()
308 	{
309 		assert(_pos !is &_list.root);
310 		_pos = _pos._next;
311 	}
312 	void retreat()
313 	{
314 		_pos = _pos._prev;
315 		assert(_pos !is &_list.root);
316 	}
317 
318 	bool atEnd()
319 	{
320 		return _pos is &_list.root;
321 	}
322 	bool atBegin()
323 	{
324 		return _pos is _list.root._next;
325 	}
326 
327 	void opOpAssign(string op)(int cnt) if(op == "+")
328 	{
329 		while(cnt > 0)
330 		{
331 			advance();
332 			cnt--;
333 		}
334 		while(cnt < 0)
335 		{
336 			retreat();
337 			cnt++;
338 		}
339 	}
340 	void opOpAssign(string op)(int cnt) if(op == "-")
341 	{
342 		opOpAssign!"+"(-cnt);
343 	}
344 
345 	void insertAfter(T data)
346 	{
347 		_list.insertAfter(data, _pos);
348 	}
349 	void insertBefore(T data)
350 	{
351 		_list.insertBefore(data, _pos);
352 	}
353 
354 	// insert entries to list, return iterator to beginning of inserted list
355 	DListIterator!(T) insertListBefore(DList!(T) list)
356 	{
357 		DListNode!(T)* beg = _list.insertListBefore(_pos, list);
358 		DListIterator!(T) begIt = DListIterator!(T)(_list);
359 		begIt._pos = beg;
360 		return begIt;
361 	}
362 
363 	// moves iterator to _next entry
364 	void erase()
365 	{
366 		assert(_pos !is &_list.root);
367 	
368 		DListNode!(T)* pos = _pos;
369 		advance();
370 		_list.remove(pos);
371 	}
372 
373 	DList!(T) eraseUntil(DListIterator!(T) end)
374 	{
375 		assert(_pos !is &_list.root);
376 		assert(_list is end._list);
377 	
378 		DListNode!(T)* pos = _pos;
379 		_pos = end._pos;
380 		return _list.remove(pos, _pos);
381 	}
382 }
383 
384 unittest
385 {
386 	DList!(int) list = new DList!(int);
387 
388 	list.append(1);
389 	list.append(2);
390 	list.prepend(0);
391 	list.append(3);
392 
393 	DListIterator!(int) it = list.begin();
394 	assert(*it == 0);
395 	assert(it[2] == 2);
396 	it.advance();
397 	assert(*it == 1);
398 	it.advance();
399 	assert(*it == 2);
400 	it.advance();
401 	assert(*it == 3);
402 	assert(it[-1] == 2);
403 	++it;
404 	assert(it == list.end());
405 	--it;
406 	it.retreat();
407 	assert(*it == 2);
408 	it.erase();
409 	assert(*it == 3);
410 	--it;
411 	assert(*it == 1);
412 }
413 
414 unittest
415 {
416 	DList!(int) list = new DList!(int);
417 
418 	list.append(1);
419 	list.append(2);
420 	list.prepend(0);
421 	list.append(3);
422 
423 	DListIterator!(int) it1 = list.begin();
424 	it1 += 1;
425 	DListIterator!(int) it2 = it1;
426 	it2 += 2;
427 
428 	DList!(int) slice = list.remove(it1, it2);
429 	assert(*it1 == 3);
430 	--it1;
431 	assert(*it1 == 0);
432 
433 	assert(*slice.begin() == 1);
434 	DListIterator!(int) it3 = slice.end();
435 	--it3;
436 	assert(*it3 == 2);
437 	--it3;
438 	assert(*it3 == 1);
439 
440 }