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