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 (AntlrUnittest)
285 {
286     import dshould;
287 
288     @("TestEmpty")
289     unittest
290     {
291         auto il = new IntegerList;
292         il.should.not.be(null);
293         il.isEmpty.should.equal(true);
294         il.toArray.should.equal([]);
295     }
296 
297     @("Capacity")
298     unittest
299     {
300         auto il = new IntegerList(20);
301         il.should.not.be(null);
302         il.addAll([3, 17, 55, 12, 1, 7]);
303         il.toArray.should.equal([3, 17, 55, 12, 1, 7]);
304         il.toString.should.equal("[3, 17, 55, 12, 1, 7]");
305         (new IntegerList(-3)).should.throwAn!IllegalArgumentException.where.msg.should.equal(
306                 "Capacity can't be a negativ value!");
307     }
308 
309     @("SetGet")
310     unittest
311     {
312         auto il = new IntegerList([7, 2, 5, 15, 40]);
313         il.contains(3).should.equal(false);
314         il.contains(5).should.equal(true);
315         il.get(2).should.equal(5);
316         il.sort;
317         il.toString.should.equal("[2, 5, 7, 15, 40]");
318         il.set(3, 2);
319         il.toString.should.equal("[2, 5, 7, 2, 40]");
320     }
321 
322     @("Hash")
323     unittest
324     {
325         auto il = new IntegerList([7, 5, 15, 40]);
326         auto il1 = new IntegerList;
327         il1.addAll(il);
328         il.toHash.should.equal(1137368);
329         il1.toHash.should.equal(1137368);
330     }
331 
332     @("Remove")
333     unittest
334     {
335         auto il = new IntegerList([7, 5, 15, 40]);
336         il.toString.should.equal("[7, 5, 15, 40]");
337         il.removeAt(2);
338         il.toString.should.equal("[7, 5, 40]");
339         il.removeAt(2);
340         il.toString.should.equal("[7, 5]");
341         il.removeRange(0, 1);
342         il.isEmpty.should.equal(true);
343         il.addAll([4, 2, 1, 33, 22, 11, 13]);
344         il.removeRange(2, 4);
345         il.toString.should.equal("[4, 2, 11, 13]");
346     }
347 
348     @("Compare")
349     unittest
350     {
351         auto il = new IntegerList([7, 2, 5, 15, 40]);
352         il.contains(3).should.equal(false);
353         il.contains(5).should.equal(true);
354         il.opEquals(il).should.equal(true);
355         il.get(2).should.equal(5);
356         auto il1 = new IntegerList(il);
357         il1.should.not.be(null);
358         il.toString.should.equal("[7, 2, 5, 15, 40]");
359         il1.toString.should.equal("[7, 2, 5, 15, 40]");
360         il.should.equal(il1);
361         il.sort;
362         il.toString.should.equal("[2, 5, 7, 15, 40]");
363         il.should.not.equal(il1);
364         il.clear;
365         il.toString.should.equal("[]");
366         il.should.not.equal(il1);
367         class A
368         {
369         }
370 
371         auto a = new A;
372         il.should.not.equal(a);
373     }
374 }