PageRenderTime 41ms CodeModel.GetById 8ms app.highlight 30ms RepoModel.GetById 1ms app.codeStats 0ms

/data/list.d

http://github.com/wilkie/djehuty
D | 429 lines | 336 code | 72 blank | 21 comment | 52 complexity | ec167d10f728616d74ea023cbc7d3104 MD5 | raw file
  1/*
  2 * list.d
  3 *
  4 * This module implements a simple list interface and many useful list
  5 * operations inspired by functional programming.
  6 *
  7 * Author: Dave Wilkinson
  8 * Originated: September 10th, 2009
  9 *
 10 */
 11
 12module data.list;
 13
 14import djehuty;
 15
 16public import data.iterable;
 17
 18class List(T) : Iterable!(T) {
 19	this() {
 20		_data.length = 10;
 21		_data = new T[_data.length];
 22		_count = 0;
 23	}
 24
 25	this(int size) {
 26		_data.length = size;
 27		_data = new T[_data.length];
 28		_count = 0;
 29	}
 30
 31	this(T[] list) {
 32		_data = list.dup;
 33		_count = list.length;
 34	}
 35
 36	this(Iterable!(T) list) {
 37		_data = list.array();
 38		_count = list.length();
 39	}
 40
 41	template add(R) {
 42		void add(R item) {
 43			synchronized(this) {
 44				if (_count >= _data.length) {
 45					_resize();
 46				}
 47				static if (IsArray!(R) && IsArray!(T)) {
 48					_data[_count] = item.dup;
 49				}
 50				else {
 51					_data[_count] = cast(T)item;
 52				}
 53				_count++;
 54			}
 55		}
 56	}
 57
 58	template addList(R) {
 59		void addList(R list) {
 60			synchronized(this) {
 61				while (_count + list.length > _data.length) {
 62					_resize();
 63				}
 64				static if (IsArray!(IterableType!(R)) && IsArray!(IterableType!(T))) {
 65					foreach(item; list) {
 66						_data[_count] = item.dup;
 67						_count++;
 68					}
 69				}
 70				else {
 71					foreach(item; list) {
 72						_data[_count] = cast(T)item;
 73						_count++;
 74					}
 75				}
 76			}
 77		}
 78	}
 79
 80	template addAt(R) {
 81		void addAt(R item, size_t idx) {
 82			synchronized(this) {
 83				if (_count >= _data.length) {
 84					_resize();
 85				}
 86
 87				if (idx >= _count) {
 88					throw new DataException.OutOfBounds(this.classinfo.name);
 89				}
 90
 91				if (_count == 0) {
 92					idx = 0;
 93				}
 94				else if (idx == 0) {
 95					_data = [_data[idx]] ~ _data[idx..$];
 96				}
 97				else if (_count != idx) {
 98					_data = _data[0..idx] ~ [_data[idx]] ~ _data[idx..$];
 99				}
100
101				static if (IsArray!(R)) {
102					_data[idx] = item.dup;
103				}
104				else {
105					_data[idx] = cast(T)item;
106				}
107				_count++;
108			}
109		}
110	}
111
112	T remove() {
113		synchronized(this) {
114			if (this.empty()) {
115				return _nullValue();
116			}
117			_count--;
118			return _data[_count];
119		}
120	}
121
122	T remove(T value) {
123		synchronized(this) {
124			foreach(size_t index, item; _data[0.._count]) {
125				if (value == item) {
126					scope(exit) _data = _data[0..index] ~ _data[index+1..$];
127					return _data[index];
128				}
129			}
130			return _nullValue();
131		}
132	}
133
134	T removeAt(size_t index) {
135		synchronized(this) {
136			if (index >= _count) {
137				throw new DataException.OutOfBounds(this.classinfo.name);
138			}
139
140			if (this.empty()) {
141				throw new DataException.OutOfElements(this.classinfo.name);
142			}
143
144			_count--;
145			scope(exit) _data = _data[0..index] ~ _data[index+1..$];
146			return _data[index];
147		}
148	}
149
150	T peek() {
151		synchronized(this) {
152			if (this.empty()) {
153				throw new DataException.OutOfElements(this.classinfo.name);
154			}
155
156			return _data[_count-1];
157		}
158	}
159
160	T peekAt(size_t index) {
161		synchronized(this) {
162			if (index >= _count) {
163				throw new DataException.OutOfBounds(this.classinfo.name);
164			}
165
166			if (this.empty()) {
167				throw new DataException.OutOfElements(this.classinfo.name);
168			}
169
170			return _data[index];
171		}
172	}
173
174	template set(R) {
175		void set(R value) {
176			synchronized(this) {
177				if (this.empty()) {
178					throw new DataException.OutOfElements(this.classinfo.name);
179				}
180
181				if (_count > 0) {
182					_data[_count-1] = cast(T)value;
183				}
184			}
185		}
186	}
187
188	template setAt(R) {
189		void setAt(size_t index, R value) {
190			synchronized(this) {
191				if (index >= _count) {
192					throw new DataException.OutOfBounds(this.classinfo.name);
193				}
194
195				if (this.empty()) {
196					throw new DataException.OutOfElements(this.classinfo.name);
197				}
198
199				_data[index] = cast(T)value;
200			}
201		}
202	}
203
204	template apply(R, S) {
205		void apply(R delegate(S) func) {
206			foreach(ref item; _data[0.._count]) {
207				item = cast(T)func(item);
208			}
209		}
210	}
211
212	template contains(R) {
213		bool contains(R value) {
214			synchronized(this) {
215				foreach(item; _data[0.._count]) {
216					if (value == item) {
217						return true;
218					}
219				}
220			}
221			return false;
222		}
223	}
224
225	bool empty() {
226		return (this.length() == 0);
227	}
228
229	void clear() {
230		synchronized(this) {
231			_data = new T[_data.length];
232			_count = 0;
233		}
234	}
235
236	// Properties
237
238	T[] array() {
239		return _data[0.._count].dup;
240	}
241
242	List!(T) dup() {
243		synchronized(this) {
244			List!(T) ret = new List!(T);
245			ret._data = _data[0.._count].dup;
246			ret._count = ret._data.length;
247
248			return ret;
249		}
250	}
251
252	List!(T) slice(size_t start, size_t end) {
253		synchronized(this) {
254			List!(T) ret = new List!(T);
255			ret._data = _data[start..end].dup;
256			ret._count = ret._data.length;
257
258			return ret;
259		}
260	}
261
262	List!(T) reverse() {
263		synchronized(this) {
264			List!(T) ret = new List!(T);
265
266			ret._data = _data[0.._count].reverse;
267			ret._count = ret._data.length;
268
269			return ret;
270		}
271	}
272
273	size_t length() {
274		return _count;
275	}
276
277	// Operator Overrides (Using Generic Functions)
278
279	T opIndex(size_t i1) {
280		return peekAt(i1);
281	}
282
283	template opIndexAssign(R) {
284		size_t opIndexAssign(R value, size_t i1) {
285			setAt(i1, value);
286			return i1;
287		}
288    }
289
290	List!(T) opSlice() {
291		return this.dup;
292	}
293
294	List!(T) opSlice(size_t start, size_t end) {
295		return this.slice(start,end);
296	}
297
298	int opApply(int delegate(ref T) loopFunc) {
299		synchronized(this) {
300			int ret;
301
302			for(int i = 0; i < _count; i++) {
303				ret = loopFunc(_data[i]);
304				if (ret) { break; }
305			}
306
307			return ret;
308		}
309	}
310
311	int opApply(int delegate(ref size_t, ref T) loopFunc) {
312		synchronized(this) {
313			int ret;
314
315			for(size_t i = 0; i < _count; i++) {
316				ret = loopFunc(i,_data[i]);
317				if (ret) { break; }
318			}
319
320			return ret;
321		}
322	}
323
324	int opApplyReverse(int delegate(ref T) loopFunc) {
325		synchronized(this) {
326			int ret;
327
328			for(size_t i = _count; ; ) {
329				if (i == 0) { break; }
330				i--;
331				ret = loopFunc(_data[i]);
332				if (ret) { break; }
333			}
334
335			return ret;
336		}
337	}
338
339	int opApplyReverse(int delegate(ref size_t, ref T) loopFunc) {
340		synchronized(this) {
341			int ret;
342
343			for(size_t i = _count; ; ) {
344				if (i == 0) { break; }
345				i--;
346				ret = loopFunc(i,_data[i]);
347				if (ret) { break; }
348			}
349			return ret;
350		}
351	}
352
353	void opCatAssign(T[] list) {
354		addList(list);
355	}
356
357	void opCatAssign(Iterable!(T) list) {
358		addList(list);
359	}
360
361	void opCatAssign(T item) {
362		add(item);
363	}
364
365	Iterable!(T) opCat(T[] list) {
366		List!(T) ret = this.dup();
367		ret.addList(list);
368		return ret;
369	}
370
371	Iterable!(T) opCat(Iterable!(T) list) {
372		List!(T) ret = this.dup();
373		ret.addList(list);
374		return ret;
375	}
376
377	Iterable!(T) opCat(T item) {
378		List!(T) ret = this.dup();
379		ret.add(item);
380		return ret;
381	}
382
383	override string toString() {
384		string ret = "[";
385
386		synchronized(this) {
387			foreach(i, item; this) {
388				ret ~= toStr(item);
389				if (i != this.length() - 1) {
390					ret ~= ",";
391				}
392			}
393		}
394
395		ret ~= "]";
396
397		return ret;
398	}
399
400protected:
401
402	T _nullValue() {
403		T val;
404		return val;
405/*		static if (IsArray!(T) || IsClass!(T)) {
406			return null;
407		}
408		else static if (IsStruct!(T)) {
409			return *(new T);
410		}
411		else {
412			return 0;
413		}*/
414	}
415
416	void _resize() {
417		T[] temp = _data;
418		if (_data.length == 0) {
419			_data = new T[10];
420		}
421		else {
422			_data = new T[_data.length*2];
423		}
424		_data[0..temp.length] = temp[0..$];
425	}
426
427	T[] _data;
428	size_t _count;
429}