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