1 module artemisd.utils.bag;
2 
3 final class Bag(E)
4 {
5     this() 
6     {
7         this(64);
8     }
9 
10     this(int capacity)
11     {
12         data = new E[capacity];
13     }
14     
15     E remove(size_t index) 
16     {
17         assert(index >= 0 && index < size);
18         E e = data[index]; // make copy of element to remove so it can be returned
19         data[index] = data[--size_]; // overwrite item to remove with last element
20         return e;
21     }
22 
23     E removeLast() 
24     {
25         assert(size > 0);
26         E e = data[--size_];
27         return e;
28     }
29 
30     bool remove(E e) 
31     {
32         for (size_t i = 0; i < size; i++) 
33         {
34             E e2 = data[i];
35 
36             if (e == e2) 
37             {
38                 data[i] = data[--size_]; // overwrite item to remove with last element
39                 return true;
40             }
41         }
42 
43         return false;
44     }
45  
46     bool contains(E e) 
47     {
48         for(size_t i = 0; size > i; i++) 
49         {
50             if(e == data[i]) 
51             {
52                 return true;
53             }
54         }
55         return false;
56     }
57 
58     bool removeAll(Bag!E bag)
59     {
60         bool modified = false;
61 
62         for (size_t i = 0; i < bag.size(); i++) 
63         {
64             E e1 = bag.get(i);
65 
66             for (size_t j = 0; j < size; j++) 
67             {
68                 E e2 = data[j];
69 
70                 if (e1 == e2) 
71                 {
72                     remove(j);
73                     j--;
74                     modified = true;
75                     break;
76                 }
77             }
78         }
79 
80         return modified;
81     }
82 
83     E get(size_t index) 
84     {
85         assert(index >=0 && index < data.length);
86         return data[index];
87     }
88 
89     @property size_t size() 
90     {
91         return size_;
92     }
93 
94     @property void size(int size) 
95     {
96         size_ = size;
97     }
98     
99     size_t getCapacity() 
100     {
101         return data.length;
102     }
103     
104     bool isIndexWithinBounds(int index) 
105     {
106         return index < getCapacity();
107     }
108 
109     bool isEmpty() 
110     {
111         return size == 0;
112     }
113 
114     void add(E e) 
115     {
116         if (size == data.length) 
117         {
118             grow();
119         }
120 
121         data[size_++] = e;
122     }
123 
124     void set(int index, E e) 
125     {
126         if(index >= data.length) 
127         {
128             grow(index*2);
129         }
130         size = index+1;
131         data[index] = e;
132     }
133     
134     void ensureCapacity(int index) 
135     {
136         if(index >= data.length) 
137         {
138             grow(index*2);
139         }
140     }
141 
142     void clear() 
143     {
144         data.length = 0;
145         size = 0;
146     }
147 
148     void addAll(Bag!E items) 
149     {
150         for(size_t i = 0; items.size() > i; i++) 
151         {
152             add(items.get(i));
153         }
154     }
155 
156     override string toString()
157     {
158         import std.conv;
159         import std.array;
160         auto s = appender!string;
161         s.put("[");
162         for(size_t i = 0; size > i; i++)
163         {
164             if( i > 0 )
165                 s.put(",");
166             s.put(to!string(data[i]));
167         }
168         s.put("]");
169         return s.data; 
170     }
171 private:
172 
173     void grow() 
174     {
175         size_t newCapacity = (data.length * 3) / 2 + 1;
176         grow(newCapacity);
177     }
178     
179     void grow(size_t newCapacity) 
180     {
181         data.length = newCapacity;
182     }
183     
184     E[] data;
185     int size_;
186 }