comparison dynamin/core/list.d @ 83:3cfc83a99cbc

Add List.opIndexAssign and switch to one callback for change notification. Also, update controls to work with the new API.
author Jordan Miner <jminer7@gmail.com>
date Sun, 18 Jul 2010 22:20:50 -0500
parents de94552446ab
children 7653269724db
comparison
equal deleted inserted replaced
82:e52546f41851 83:3cfc83a99cbc
35 // MUST use (high + low) >>> 1 to find the average 35 // MUST use (high + low) >>> 1 to find the average
36 // TODO: Search() 36 // TODO: Search()
37 // TODO: QuickSort() 37 // TODO: QuickSort()
38 // TODO: HeapSort() 38 // TODO: HeapSort()
39 // TODO: Sort() - calls HeapSort() so stable sort is default 39 // TODO: Sort() - calls HeapSort() so stable sort is default
40 class List(T, bool hasDelegates = false) { 40
41 /// Represents the ways items can be changed in a list.
42 enum ListChangeType {
43 /// An item was added to the list.
44 Added,
45 /// An item was removed from the list.
46 Removed,
47 /// An item was replaced with another item.
48 Replaced
49 }
50
51 class List(T, bool changeNotification = false) {
41 protected: 52 protected:
42 T[] _data; 53 T[] _data;
43 uint _count; 54 uint _count;
44 static if(hasDelegates) { 55 static if(changeNotification)
45 void delegate(T, int) whenAdded; 56 void delegate(ListChangeType, T, T, uint) whenChanged;
46 void delegate(T, int) whenRemoved;
47 }
48 const int DefaultCapacity = 16; 57 const int DefaultCapacity = 16;
49 public: 58 public:
50 static if(hasDelegates) { 59 static if(changeNotification) {
51 /// whenAdded or whenRemoved is called right after an item is added 60 /// whenChanged is called right after an item is added, removed, or replaced
52 /// or removed 61 this(void delegate(ListChangeType, T, T, uint) whenChanged) {
53 this(void delegate(T, int) whenAdded, 62 this(DefaultCapacity, whenChanged);
54 void delegate(T, int) whenRemoved) {
55 this(DefaultCapacity, whenAdded, whenRemoved);
56 } 63 }
57 this(uint capacity, 64 this(uint capacity,
58 void delegate(T, int) whenAdded, 65 void delegate(ListChangeType, T, T, uint) whenChanged) {
59 void delegate(T, int) whenRemoved) {
60 _data = new T[capacity]; 66 _data = new T[capacity];
61 this.whenAdded = whenAdded; 67 this.whenChanged = whenChanged;
62 this.whenRemoved = whenRemoved;
63 } 68 }
64 } else { 69 } else {
65 this() { 70 this() {
66 this(DefaultCapacity); 71 this(DefaultCapacity);
67 } 72 }
103 return; 108 return;
104 _data.length = max(neededCap, (capacity+1)*2); 109 _data.length = max(neededCap, (capacity+1)*2);
105 } 110 }
106 T opIndex(uint index) { 111 T opIndex(uint index) {
107 return _data[0.._count][index]; 112 return _data[0.._count][index];
113 }
114 void opIndexAssign(T item, uint index) {
115 T oldItem = _data[0.._count][index];
116 _data[0.._count][index] = item;
117 static if(changeNotification)
118 whenChanged(ListChangeType.Replaced, oldItem, item, index);
108 } 119 }
109 void push(T item) { 120 void push(T item) {
110 add(item); 121 add(item);
111 } 122 }
112 T pop() { 123 T pop() {
115 T item = _data[_count-1]; 126 T item = _data[_count-1];
116 // must null out to allow to be collected 127 // must null out to allow to be collected
117 static if(is(T == class) || is(T == interface)) 128 static if(is(T == class) || is(T == interface))
118 _data[_count-1] = cast(T)null; 129 _data[_count-1] = cast(T)null;
119 --_count; 130 --_count;
120 static if(hasDelegates) 131 static if(changeNotification)
121 whenRemoved(item, _count); 132 whenChanged(ListChangeType.Removed, item, T.init, _count);
122 return item; 133 return item;
123 } 134 }
124 void add(T item) { 135 void add(T item) {
125 insert(item, _count); 136 insert(item, _count);
126 } 137 }
138 // must null out to allow to be collected 149 // must null out to allow to be collected
139 static if(is(T == class) || is(T == interface)) 150 static if(is(T == class) || is(T == interface))
140 _data[_count-1] = cast(T)null; 151 _data[_count-1] = cast(T)null;
141 --_count; 152 --_count;
142 153
143 static if(hasDelegates) 154 static if(changeNotification)
144 whenRemoved(item, index); 155 whenChanged(ListChangeType.Removed, item, T.init, index);
145 } 156 }
146 void insert(T item, uint index) { 157 void insert(T item, uint index) {
147 maybeEnlarge(_count+1); 158 maybeEnlarge(_count+1);
148 arrayCopy!(T)(_data, index, _data, index+1, _count - index); 159 arrayCopy!(T)(_data, index, _data, index+1, _count - index);
149 _data[index] = item; 160 _data[index] = item;
150 ++_count; 161 ++_count;
151 static if(hasDelegates) 162 static if(changeNotification)
152 whenAdded(item, index); 163 whenChanged(ListChangeType.Added, T.init, item, index);
153 } 164 }
154 void clear() { 165 void clear() {
155 for(; _count > 0; --_count) { 166 for(; _count > 0; --_count) {
156 static if(hasDelegates) 167 static if(changeNotification)
157 whenRemoved(_data[_count-1], _count-1); 168 whenChanged(ListChangeType.Removed, _data[_count-1], T.init, _count-1);
158 // must null out to allow to be collected 169 // must null out to allow to be collected
159 static if(is(T == class) || is(T == interface)) 170 static if(is(T == class) || is(T == interface))
160 data[_count-1] = cast(T)null; 171 data[_count-1] = cast(T)null;
161 } 172 }
162 } 173 }
208 list.removeAt(1); 219 list.removeAt(1);
209 assert(list.data == "eo!, Ma"); 220 assert(list.data == "eo!, Ma");
210 list.clear(); 221 list.clear();
211 assert(list.data == ""); 222 assert(list.data == "");
212 223
213 int a = 0, r = 0; 224 int a = 0, r = 0, r2 = 0;
214 void added(string, int) { a++; }; 225 void changed(ListChangeType t, string o, string n, uint) {
215 void removed(string, int) { r++; }; 226 if(t == ListChangeType.Added) {
216 auto list2 = new List!(string, true)(&added, &removed); 227 a++;
217 assert(a == 0 && r == 0); 228 assert(o == "" && n != "");
229 }
230 if(t == ListChangeType.Removed) {
231 r++;
232 assert(n == "" && o != "");
233 }
234 if(t == ListChangeType.Replaced) {
235 r2++;
236 }
237 };
238 auto list2 = new List!(string, true)(&changed);
239 assert(a == 0 && r == 0 && r2 == 0);
218 list2.add("hello"); 240 list2.add("hello");
219 assert(a == 1 && r == 0); 241 assert(a == 1 && r == 0 && r2 == 0);
220 assert(list2.pop() == "hello"); 242 assert(list2.pop() == "hello");
221 assert(a == 1 && r == 1); 243 assert(a == 1 && r == 1 && r2 == 0);
222 244
223 list2.add("Hi"); 245 list2.add("Hi");
224 list2.add("Jacob!"); 246 list2.add("Jacob");
225 assert(a == 3 && r == 1); 247 assert(a == 3 && r == 1 && r2 == 0);
248 list2[1] = "Matt";
249 assert(a == 3 && r == 1 && r2 == 1);
250 list2.insert("John", 1);
251 list2.insert("Pete", 3);
252 assert(list2.data == ["Hi", "John", "Matt", "Pete"]);
253 assert(a == 5 && r == 1 && r2 == 1);
254 list2.removeAt(0);
255 assert(list2.data == ["John", "Matt", "Pete"]);
256 assert(a == 5 && r == 2 && r2 == 1);
226 list2.clear(); 257 list2.clear();
227 assert(a == 3 && r == 3); 258 assert(a == 5 && r == 5 && r2 == 1);
228 } 259 }
229 260