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