1 // Written in the D programming language. 2 3 /** 4 DLANGUI library. 5 6 This module implements array based collection. 7 8 Synopsis: 9 10 ---- 11 import dlangui.core.collections; 12 13 // add 14 Collection!Widget widgets; 15 widgets ~= new Widget("id1"); 16 widgets ~= new Widget("id2"); 17 Widget w3 = new Widget("id3"); 18 widgets ~= w3; 19 20 // remove by index 21 widgets.remove(1); 22 23 // foreach 24 foreach(w; widgets) 25 writeln("widget: ", w.id); 26 27 // remove by value 28 widgets -= w3; 29 writeln(widgets[0].id); 30 31 32 ---- 33 34 Copyright: Vadim Lopatin, 2014 35 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 36 Authors: $(WEB coolreader.org, Vadim Lopatin) 37 */ 38 module dlangui.core.collections; 39 40 import std.algorithm; 41 42 /// array based collection of items 43 /// retains item order when during add/remove operations 44 struct Collection(T) { 45 private T[] _items; 46 private size_t _len; 47 /// returns number of items in collection 48 @property size_t length() { return _len; } 49 /// returns currently allocated capacity (may be more than length) 50 @property size_t size() { return _items.length; } 51 /// change capacity (e.g. to reserve big space to avoid multiple reallocations) 52 @property void size(size_t newSize) { 53 if (_len > newSize) 54 length = newSize; // shrink 55 _items.length = newSize; 56 } 57 /// returns number of items in collection 58 @property void length(size_t newSize) { 59 if (newSize < _len) { 60 // shrink 61 static if (is(T == class) || is(T == struct)) { 62 // clear items 63 for (size_t i = newSize; i < _len; i++) 64 _items[i] = T.init; 65 } 66 } else if (newSize > _len) { 67 // expand 68 if (_items.length < newSize) 69 _items.length = newSize; 70 } 71 _len = newSize; 72 } 73 /// access item by index 74 ref T opIndex(size_t index) { 75 assert(index < _len); 76 return _items[index]; 77 } 78 /// insert new item in specified position 79 void add(T item, size_t index = size_t.max) { 80 if (index > _len) 81 index = _len; 82 if (_items.length >= _len) { 83 if (_items.length < 4) 84 _items.length = 4; 85 else 86 _items.length = _items.length * 2; 87 } 88 if (index < _len) { 89 for (size_t i = _len; i > index; i--) 90 _items[i] = _items[i - 1]; 91 } 92 _items[index] = item; 93 _len++; 94 } 95 /// support for appending (~=, +=) and removing by value (-=) 96 ref Collection opOpAssign(string op)(T item) { 97 static if (op.equal("~") || op.equal("+")) { 98 // append item to end of collection 99 add(item); 100 return this; 101 } else if (op.equal("-")) { 102 // remove item from collection, if present 103 removeValue(item); 104 return this; 105 } else { 106 assert(false, "not supported opOpAssign " ~ op); 107 } 108 } 109 /// returns index of first occurence of item, size_t.max if not found 110 size_t indexOf(T item) { 111 for (size_t i = 0; i < _len; i++) 112 if (_items[i] == item) 113 return i; 114 return size_t.max; 115 } 116 /// remove single item, returning removed item 117 T remove(size_t index) { 118 assert(index < _len); 119 T result = _items[index]; 120 for (size_t i = index; i + 1 < _len; i++) 121 _items[i] = _items[i + 1]; 122 _items[_len] = T.init; 123 _len--; 124 return result; 125 } 126 /// remove single item by value - if present in collection, returning true if item was found and removed 127 bool removeValue(T value) { 128 size_t index = indexOf(value); 129 if (index == size_t.max) 130 return false; 131 remove(index); 132 return true; 133 } 134 /// support of foreach with reference 135 int opApply(int delegate(ref T param) op) { 136 int result = 0; 137 for (size_t i = 0; i < _len; i++) { 138 result = op(_items[i]); 139 if (result) 140 break; 141 } 142 return result; 143 } 144 /// remove all items 145 void clear() { 146 static if (is(T == class) || is(T == struct)) { 147 /// clear references 148 for(size_t i = 0; i < _len; i++) 149 _items[i] = T.init; 150 } 151 _len = 0; 152 _items = null; 153 } 154 ~this() { 155 clear(); 156 } 157 } 158