1 /*
2  * Copyright (c) 2012-2019 The ANTLR Project. All rights reserved.
3  * Use of this file is governed by the BSD 3-clause license that
4  * can be found in the LICENSE.txt file in the project root.
5  */
6 
7 module antlr.v4.runtime.misc.IntegerList;
8 
9 import antlr.v4.runtime.IllegalArgumentException;
10 import std.conv;
11 import std.format;
12 import std.range;
13 import std.typecons;
14 
15 /**
16  * A buffert list of interger values
17  */
18 class IntegerList
19 {
20 
21     /**
22      * @uml
23      * @read
24      */
25     public int[] data_;
26 
27     public this()
28     {
29     }
30 
31     public this(int capacity)
32     {
33         if (capacity < 0)
34         {
35             throw new IllegalArgumentException("Capacity can't be a negativ value!");
36         }
37         if (capacity)
38         {
39             data_.reserve(capacity);
40         }
41     }
42 
43     public this(IntegerList list)
44     {
45         data_ = list.data;
46         //size_ = list.size;
47     }
48 
49     public this(int[] list)
50     {
51         foreach (value; list)
52         {
53             add(value);
54         }
55     }
56 
57     /**
58      * @uml
59      * @final
60      */
61     public final void add(int value)
62     {
63         data_ ~= value;
64     }
65 
66     /**
67      * @uml
68      * @final
69      */
70     public final void addAll(int[] array)
71     {
72         foreach (value; array)
73         {
74             add(value);
75         }
76     }
77 
78     public void addAll(IntegerList list)
79     {
80         foreach (value; list.data)
81         {
82             add(value);
83         }
84     }
85 
86     /**
87      * @uml
88      * @final
89      */
90     public final int get(int index)
91     in
92     {
93         assert(index >= 0 || index < data_.length);
94     }
95     do
96     {
97         return data_[index];
98     }
99 
100     /**
101      * @uml
102      * @final
103      */
104     public final bool contains(int value)
105     {
106         import std.algorithm.searching : canFind;
107 
108         return data_.canFind(value);
109     }
110 
111     /**
112      * @uml
113      * @final
114      */
115     public final int set(int index, int value)
116     in
117     {
118         assert(index >= 0 || index < data_.length);
119     }
120     do
121     {
122         int previous = data_[index];
123         data_[index] = value;
124         return previous;
125     }
126 
127     /**
128      * @uml
129      * @final
130      */
131     public final int removeAt(int index)
132     {
133         int value = get(index);
134         import std.algorithm.mutation : remove;
135 
136         data_ = remove(data_, index);
137         return value;
138     }
139 
140     /**
141      * @uml
142      * @final
143      */
144     public final void removeRange(int fromIndex, int toIndex)
145     in
146     {
147         assert(fromIndex >= 0 || toIndex >= 0 || fromIndex <= data_.length || toIndex <= data_.length, "IndexOutOfBoundsException");
148         assert(fromIndex <= toIndex, "IllegalArgumentException");
149     }
150     do
151     {
152         import std.algorithm.mutation : remove;
153 
154         data_ = remove(data_, tuple(fromIndex, toIndex + 1));
155     }
156 
157     /**
158      * @uml
159      * @final
160      */
161     public final bool isEmpty()
162     {
163         return data_.length == 0;
164     }
165 
166     /**
167      * @uml
168      * @final
169      */
170     public final int size()
171     {
172         return to!int(data_.length);
173     }
174 
175     /**
176      * @uml
177      * @final
178      * @property
179      */
180     public final @property void clear()
181     {
182         data_.length = 0;
183     }
184 
185     /**
186      * @uml
187      * @final
188      * @property
189      */
190     public final @property int[] toArray()
191     {
192         return data_;
193     }
194 
195     public void sort()
196     {
197         import std.algorithm.sorting : sort;
198 
199         data_.sort;
200     }
201 
202     /**
203      * Compares the specified object with this list for equality.  Returns
204      * {@code true} if and only if the specified object is also an {@link IntegerList},
205      * both lists have the same size, and all corresponding pairs of elements in
206      * the two lists are equal.  In other words, two lists are defined to be
207      * equal if they contain the same elements in the same order.
208      * <p>
209      * This implementation first checks if the specified object is this
210      * list. If so, it returns {@code true}; if not, it checks if the
211      * specified object is an {@link IntegerList}. If not, it returns {@code false};
212      * if so, it checks the size of both lists. If the lists are not the same size,
213      * it returns {@code false}; otherwise it iterates over both lists, comparing
214      * corresponding pairs of elements.  If any comparison returns {@code false},
215      * this method returns {@code false}.
216      *
217      *  @param o the object to be compared for equality with this list
218      *  @return {@code true} if the specified object is equal to this list
219      * @uml
220      * @override
221      */
222     public override bool opEquals(Object o)
223     {
224         if (o is this)
225         {
226             return true;
227         }
228 
229         if (!cast(IntegerList) o)
230         {
231             return false;
232         }
233 
234         IntegerList other = cast(IntegerList) o;
235         if (data_.length != other.size)
236         {
237             return false;
238         }
239         import std.algorithm.comparison : equal;
240 
241         return data_.equal(other.data);
242     }
243 
244     /**
245      * Returns the hash code value for this list.
246      *
247      * <p>This implementation uses exactly the code that is used to define the
248      * list hash function in the documentation for the {@link List#hashCode}
249      * method.</p>
250      *
251      *  @return the hash code value for this list
252      * @uml
253      * @override
254      * @safe
255      * @nothrow
256      */
257     public override size_t toHash() @safe nothrow
258     {
259         int hashCode = 1;
260         for (int i = 0; i < data_.length; i++)
261         {
262             hashCode = 31 * hashCode + data_[i];
263         }
264         return hashCode;
265     }
266 
267     /**
268      * Returns a string representation of this list.
269      * @uml
270      * @override
271      */
272     public override string toString()
273     {
274         return format("%s", data_);
275     }
276 
277     public final int[] data()
278     {
279         return this.data_.dup;
280     }
281 
282 }
283 
284 version (unittest)
285 {
286     import dshould : be, equal, not, should;
287     import dshould.thrown;
288     import unit_threaded;
289 
290     class Test
291     {
292 
293         @Tags("IntegerList")
294         @("TestEmpty")
295         unittest
296         {
297             auto il = new IntegerList;
298             il.should.not.be(null);
299             il.isEmpty.should.equal(true);
300             il.toArray.should.equal([]);
301         }
302 
303         @Tags("IntegerList")
304         @("Capacity")
305         unittest
306         {
307             auto il = new IntegerList(20);
308             il.should.not.be(null);
309             il.addAll([3, 17, 55, 12, 1, 7]);
310             il.toArray.should.equal([3, 17, 55, 12, 1, 7]);
311             il.toString.should.equal("[3, 17, 55, 12, 1, 7]");
312             (new IntegerList(-3)).should.throwAn!IllegalArgumentException.where.msg.should.equal(
313                     "Capacity can't be a negativ value!");
314         }
315 
316         @Tags("IntegerList")
317         @("SetGet")
318         unittest
319         {
320             auto il = new IntegerList([7, 2, 5, 15, 40]);
321             il.contains(3).should.equal(false);
322             il.contains(5).should.equal(true);
323             il.get(2).should.equal(5);
324             il.sort;
325             il.toString.should.equal("[2, 5, 7, 15, 40]");
326             il.set(3, 2);
327             il.toString.should.equal("[2, 5, 7, 2, 40]");
328         }
329 
330         @Tags("IntegerList")
331         @("Hash")
332         unittest
333         {
334             auto il = new IntegerList([7, 5, 15, 40]);
335             auto il1 = new IntegerList;
336             il1.addAll(il);
337             il.toHash.should.equal(1137368);
338             il1.toHash.should.equal(1137368);
339         }
340 
341         @Tags("IntegerList")
342         @("Remove")
343         unittest
344         {
345             auto il = new IntegerList([7, 5, 15, 40]);
346             il.toString.should.equal("[7, 5, 15, 40]");
347             il.removeAt(2);
348             il.toString.should.equal("[7, 5, 40]");
349             il.removeAt(2);
350             il.toString.should.equal("[7, 5]");
351             il.removeRange(0, 1);
352             il.isEmpty.should.equal(true);
353             il.addAll([4, 2, 1, 33, 22, 11, 13]);
354             il.removeRange(2, 4);
355             il.toString.should.equal("[4, 2, 11, 13]");
356         }
357 
358         @Tags("IntegerList")
359         @("Compare")
360         unittest
361         {
362             auto il = new IntegerList([7, 2, 5, 15, 40]);
363             il.contains(3).should.equal(false);
364             il.contains(5).should.equal(true);
365             il.opEquals(il).should.equal(true);
366             il.get(2).should.equal(5);
367             auto il1 = new IntegerList(il);
368             il1.should.not.be(null);
369             il.toString.should.equal("[7, 2, 5, 15, 40]");
370             il1.toString.should.equal("[7, 2, 5, 15, 40]");
371             il.should.equal(il1);
372             il.sort;
373             il.toString.should.equal("[2, 5, 7, 15, 40]");
374             il.should.not.equal(il1);
375             il.clear;
376             il.toString.should.equal("[]");
377             il.should.not.equal(il1);
378             class A
379             {
380             }
381 
382             auto a = new A;
383             il.should.not.equal(a);
384         }
385     }
386 }