1 /*
2 Boost Software License - Version 1.0 - August 17th, 2003
3 
4 Copyright (c) 2019 Clipsey
5 
6 Permission is hereby granted, free of charge, to any person or organization
7 obtaining a copy of the software and accompanying documentation covered by
8 this license (the "Software") to use, reproduce, display, distribute,
9 execute, and transmit the Software, and to prepare derivative works of the
10 Software, and to permit third-parties to whom the Software is furnished to
11 do so, all subject to the following:
12 
13 The copyright notices in the Software and this entire statement, including
14 the above license grant, this restriction and the following disclaimer,
15 must be included in all copies of the Software, in whole or in part, and
16 all derivative works of the Software, unless such copies or derivative
17 works are solely in the form of machine-executable object code generated by
18 a source language processor.
19 
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
23 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
24 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
25 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 DEALINGS IN THE SOFTWARE.
27 */
28 module containers.list;
29 
30 /**
31     An array-based list implementation
32 */
33 struct List(T) {
34 private:
35     T[] data;
36 
37     /// front element id
38     size_t frontElm;
39 
40 public:
41     /// Constructs a list of specified length
42     this(size_t length) {
43         data = new T[](length);
44     }
45 
46     /// Constructs a list with specified data
47     this(T[] data) {
48         this.data = data;
49     }
50 
51     /// Constructs a list with specified data
52     this(List!T data) {
53         this.data = data.toArray;
54     }
55 
56     /// Assignment overload for list
57     void opAssign(T rhs) {
58         this.data = [rhs];
59     }
60 
61     /// Assignment overload for list
62     void opAssign(T[] rhs) {
63         this.data = rhs;
64     }
65 
66     /// Assignment overload for list at index
67     T opIndexAssign(T value, size_t index) {
68         data[index] = value;
69         return value;
70     }
71 
72     /// Assignment overload for list append
73     T opOpAssign(string op = "~")(T value) {
74         add(value);
75         return value;
76     }
77 
78     /// Assignment overload for list append
79     T opOpAssign(string op = "~")(T[] value) {
80         addRange(value);
81         return value;
82     }
83 
84     /// Assignment overload for list append
85     T opOpAssign(string op = "~")(List!T value) {
86         addRange(value);
87         return value;
88     }
89 
90     /// Index overload for list
91     T opIndex(size_t index) {
92         return data[index];
93     }
94 
95     int opApply(int delegate(ref T) operations) {
96         int result = 0;
97 
98         for (size_t i = 0; i < data.length; ++i) {
99             result = operations(data[i]);
100 
101             if (result) break;
102         }
103 
104         return result;
105     }
106 
107     int opApply(int delegate(ref size_t, ref T) operations) {
108         int result = 0;
109 
110         for (size_t i = 0; i < data.length; ++i) {
111             result = operations(i, data[i]);
112 
113             if (result) break;
114         }
115 
116         return result;
117     }
118 
119     int opApplyReverse(int delegate(ref T) operations) {
120         int result = 0;
121 
122         for (ptrdiff_t i = data.length-1; i >= 0; i--) {
123             result = operations(data[i]);
124 
125             if (result) break;
126         }
127 
128         return result;
129     }
130 
131     int opApplyReverse(int delegate(ref ptrdiff_t, ref T) operations) {
132         int result = 0;
133 
134         for (ptrdiff_t i = data.length-1; i >= 0; i--) {
135             result = operations(i, data[i]);
136 
137             if (result) break;
138         }
139 
140         return result;
141     }
142 
143     /// Returns the count of items in the list
144     @property size_t count() {
145         return data.length;
146     }
147 
148     /// Returns wether the list is empty (has no items)
149     bool empty() {
150         return data.length != 0;
151     }
152 
153     /// Add item to list
154     void add(T item) {
155         data ~= item;
156     }
157 
158     /// Add range of items to list
159     void addRange(List!T items) {
160         data ~= items.toArray();
161     }
162 
163     /// Add range of items to list
164     void addRange(T[] items) {
165         data ~= items;
166     }
167 
168     /// Clears the list
169     void clear() {
170         data = [];
171     }
172 
173     /// Returns true if the list contains the item
174     bool contains(T item) {
175         foreach(srch; data) {
176             if (srch == item) return true;
177         }
178         return false;
179     }
180 
181     /// copy elements (starting from start) to array.
182     void copyTo(T[] arr, size_t start) {
183         arr[start..start+count()] = data;
184     }
185 
186     /++
187         Returns the index of the first occurence of value.
188         Returns -1 if nothing was found
189     +/
190     ptrdiff_t indexOf(T item) {
191         foreach(i, srch; data) {
192             if (srch == item) return i;
193         }
194         return -1;
195     }
196 
197     /++
198         Returns the index of the last occurence of value.
199         Returns -1 if nothing was found
200     +/
201     ptrdiff_t lastIndexOf(T item) {
202         foreach_reverse(i, srch; data) {
203             if (srch == item) return i;
204         }
205         return -1;
206     }
207 
208     /// Inserts item in to list at index
209     void insert(size_t index, T item) {
210         data.length++;
211         // First, move stuff 1 step ahead
212         data[index+1..$] = data[index+1..$-1];
213 
214         // Then insert the item
215         data[index] = item;
216     }
217 
218     /// Inserts item range in to list at index
219     void insertRange(size_t index, List!T items) {
220         insertRange(index, items.toArray);
221     }
222 
223     /// Inserts item range in to list at index
224     void insertRange(size_t index, T[] items) {
225         data.length += items.length;
226 
227         // First, move stuff x steps ahead
228         data[index+items.length..$] = data[index+items.length..$-1];
229 
230         // Then insert the item range
231         data[index..index+items.length] = items[0..items.length];
232     }
233 
234     /// Remove item from list
235     void remove(T item) {
236         // Get the index
237         size_t index = indexOf(item);
238         removeAt(index);
239     }
240 
241     /// Removes the element at index from the list
242     void removeAt(size_t index) {
243         // Slice it outta there.
244         data = data[0..index] ~ data[index+1..$];
245     }
246 
247     /// Removes a range of items from the list
248     void removeRange(size_t index, size_t count) {
249         size_t end = index+count;
250 
251         // Slice it outta there.
252         data = data[0..index] ~ data[end..$];
253     }
254     
255     /// Reverses the contents of the list
256     void reverse() {
257         /// Store the old state temporarily.
258         T[] tmp = toArray();
259         foreach_reverse(i, srch; tmp) {
260             data[(data.length-1)-i] = srch;
261         }
262     }
263 
264     /// Returns a copy of the internal data of the list as an array
265     T[] toArray() {
266         T[] output = new T[](data.length);
267         /// Make a copy, by making the LEFT HAND side a slice.
268         output[] = data;
269         return output;
270     }
271 
272     /// Gets string representation of list
273     string toString() {
274         import std.conv : text;
275         return data.text;
276     }
277 }