1 
2 module ws.list;
3 
4 import std.conv, ws.io;
5 
6 __gshared:
7 
8 
9 class List(T) {
10 
11 	protected {
12 
13 		struct Node {
14 			T obj;
15 			Node* prev;
16 			Node* next;
17 		}
18 
19 		Node* mBegin;
20 		Node* mEnd;
21 		size_t mLength;
22 
23 		alias Type = T;
24 
25 	}
26 
27 
28 	TList opCast(TList)(){
29 		auto list = new TList;
30 		foreach(e; this)
31 			list ~= cast(TList.Type)e;
32 		return list;
33 	}
34 
35 
36 	Node* checkBegin(){
37 		if(!mBegin){
38 			mBegin = new Node;
39 			mEnd = mBegin;
40 		}
41 		return mBegin;
42 	}
43 
44 	Node* checkEnd(){
45 		checkBegin();
46 		return mEnd;
47 	}
48 
49 	ref T opIndex(size_t idx){
50 		assert(idx < mLength);
51 		Node* it = mBegin;
52 		while(idx--)
53 			it = it.next;
54 		return it.obj;
55 	}
56 	
57 	void opOpAssign(string op)(T e){
58 		static if(op=="~")
59 			push(e);
60 		else static if(op=="-")
61 			remove(e);
62 		else static assert(0, "Operator " ~ op ~ " not implemented");
63 	}
64 	
65 	void push(T e){
66 		if(!mBegin){
67 			mBegin = new Node;
68 			mBegin.obj = e;
69 			mEnd = mBegin;
70 		}else{
71 			mEnd.next = new Node;
72 			mEnd.next.prev = mEnd;
73 			mEnd.next.obj = e;
74 			mEnd = mEnd.next;
75 		}
76 		++mLength;
77 	}
78 	
79 	void pushFront(T e){
80 		if(!mBegin){
81 			mBegin = new Node;
82 			mBegin.obj = e;
83 			mEnd = mBegin;
84 		}else{
85 			mBegin.prev = new Node;
86 			mBegin.prev.next = mBegin;
87 			mBegin.prev.obj = e;
88 			mBegin = mBegin.prev;
89 		}
90 		++mLength;
91 	}
92 
93 
94 	Iterator insert(Iterator where, T obj, bool before = false){
95 		auto node = new Node;
96 		node.next = (before ? where.node : where.node.next);
97 		node.prev = (before ? where.node.prev : where.node);
98 		node.obj = obj;
99 		if(node.next)
100 			node.next.prev = node;
101 		if(node.prev)
102 			node.prev.next = node;
103 		++mLength;
104 		return Iterator(node);
105 	}
106 
107 
108 	ref T popBack(){
109 		assert(mLength, "list is empty");
110 		auto tmp = mEnd;
111 		if(mEnd.prev){
112 			mEnd.prev.next = null;
113 			mEnd = tmp.prev;
114 			--mLength;
115 		}else
116 			clear();
117 		return tmp.obj;
118 	}
119 	
120 	ref T popFront(){
121 		assert(mLength, "list is empty");
122 		auto tmp = mBegin;
123 		if(mBegin.next){
124 			mBegin.next.prev = null;
125 			mBegin = mBegin.next;
126 			--mLength;
127 		}else
128 			clear();
129 		return tmp.obj;
130 	}
131 
132 	void remove(T e){
133 		auto it = mBegin;
134 		while(it){
135 			if(it.obj == e) break;
136 			it = it.next;
137 		}
138 		if(!it)
139 			throw new Exception("element not in list");
140 		remove(Iterator(it));
141 	}
142 
143 
144 	void remove(Iterator it){
145 		if(it.node.prev)
146 			it.node.prev.next = it.node.next;
147 		else
148 			mBegin = it.node.next;
149 		if(it.node.next)
150 			it.node.next.prev = it.node.prev;
151 		else
152 			mEnd = it.node.prev;
153 		--mLength;
154 	}
155 	
156 	
157 	List opBinary(string op)(List other) if(op=="~"){
158 		auto n = new List;
159 		foreach(c; this)
160 			n.push(c);
161 		foreach(c; other)
162 			n.push(c);
163 		return n;
164 	}
165 	
166 	
167 	int opApply(int delegate(Iterator,T) callback){
168 		int result = 0;
169 		auto it = begin();
170 		while(it){
171 			result = callback(it, it.get());
172 			it = it.next;
173 			if(result)
174 				break;
175 		}
176 		return result;
177 	}
178 
179 	int opApply(int delegate(T) cb){
180 		return opApply((i, T e){
181 			return cb(e);
182 		});
183 	}
184 	
185 	
186 	int opApplyReverse(int delegate(T) callback){
187 		int result = 0;
188 		auto it = mEnd;
189 		while(it){
190 			auto obj = it.obj;
191 			it = it.prev;
192 			result = callback(obj);
193 			if(result) break;
194 		}
195 		return result;
196 	}
197 	
198 	
199 	override string toString(){
200 		string tmp = "List!" ~ typeid(T).toString() ~ " = [\n";
201 		auto it = mBegin;
202 		while(it){
203 			tmp ~= "\t" ~ to!string(it.obj) ~ ",\n";
204 			it = it.next;
205 		}
206 		tmp ~= "]";
207 		return tmp;
208 	}
209 	
210 	
211 	@property bool empty() const {
212 		return !mBegin;
213 	}
214 	
215 
216 	void clear(){
217 		mBegin = null;
218 		mEnd = null;
219 		mLength = 0;
220 	}
221 	
222 	
223 	@property ref T front(){
224 		assert(mBegin);
225 		return mBegin.obj;
226 	}
227 
228 	@property void front(ref T f){
229 		assert(mBegin);
230 		mBegin.obj = f;
231 	}
232 	
233 
234 	@property ref T back(){
235 		assert(mEnd);
236 		return mEnd.obj;
237 	}
238 
239 	@property void back(ref T b){
240 		assert(mEnd);
241 		mEnd.obj = b;
242 	}
243 
244 	@property nothrow size_t length(){
245 		return mLength;
246 	}
247 
248 
249 	@property nothrow Iterator begin(){
250 		return Iterator(mBegin);
251 	}
252 	
253 	
254 	@property nothrow Iterator end(){
255 		return Iterator(mEnd);
256 	}
257 	
258 	
259 	struct Iterator {
260 
261 		Node* node;
262 
263 		T get(){
264 			return node.obj;
265 		}
266 
267 		@property Iterator prev(){
268 			return Iterator(node.prev);
269 		}
270 
271 		@property Iterator next(){
272 			return Iterator(node.next);
273 		}
274 
275 		private nothrow this(Node* node){
276 			this.node = node;
277 		}
278 
279 		bool opCast(T)() if(is(T==bool)) {
280 			return node !is null;
281 		}
282 
283 		Iterator opUnary(string s)(){
284 			static if(s == "++"){
285 				if(node.next)
286 					node = node.next;
287 			}else static if(s == "--"){
288 				if(node.prev)
289 					node = node.prev;
290 			}else
291 				assert(false, "Not implemented");
292 			return this;
293 		}
294 
295 	}
296 
297 	
298 	unittest {
299 		auto test = new List!int;
300 		test.push(5);
301 		test.push(10);
302 		assert(test.mLength == 2);
303 		
304 		assert(test[0]*test[1] == 5*10);
305 		
306 		test.remove(5);
307 		assert(test.mLength == 1);
308 		
309 		assert(test[0] == 10);
310 		
311 		test.push(12);
312 		auto it = test.end();
313 		test.insert(it, 11, true);
314 		
315 		assert(test.mLength == 3);
316 		
317 		foreach(i; test)
318 			if(i == 11){
319 				test.remove(i);
320 				test.push(100);
321 			}
322 		
323 		assert(test[0] == 10);
324 		assert(test[1] == 12);
325 		assert(test[2] == 100);
326 		assert(test.mLength == 3);
327 		
328 		test.back *= 5;
329 		assert(test.back == 500);
330 		
331 		foreach(i; test)
332 			test.popFront();
333 		assert(test.mLength == 0);
334 			
335 	}
336 
337 }
338 
339