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