1 /*
  2  * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 
 26 package org.openjdk.bench.valhalla.sandbox.corelibs;
 27 
 28 import java.util.Arrays;
 29 import java.util.ConcurrentModificationException;
 30 import java.util.NoSuchElementException;
 31 import java.util.Objects;
 32 import java.util.function.Consumer;
 33 import java.util.function.IntConsumer;
 34 import java.util.function.Predicate;
 35 import java.util.function.UnaryOperator;
 36 
 37 /**
 38  * Resizable-array implementation like {@code ArrayList<int>}.
 39  */
 40 public class ArrayListInt
 41 //        extends AbstractList<E>
 42 //        implements List<int>, RandomAccess, Cloneable, java.io.Serializable
 43 {
 44     @java.io.Serial
 45     private static final long serialVersionUID = 8683452581122892189L;
 46 
 47     /**
 48      *new ()   initial capacity.
 49      */
 50     private static final int DEFAULT_CAPACITY = 10;
 51 
 52     /**
 53      * Shared empty array instance used for empty instances.
 54      */
 55     private static final int[] EMPTY_ELEMENTDATA = {};
 56 
 57     /**
 58      * Shared empty array instance used for default sized empty instances. We
 59      * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
 60      * first element is added.
 61      */
 62     private static final int[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = new int[0];
 63 
 64     /**
 65      * The array buffer into which the elements of the ArrayList are stored.
 66      * The capacity of the ArrayList is the length of this array buffer. Any
 67      * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
 68      * will be expanded to DEFAULT_CAPACITY when the first element is added.
 69      */
 70     transient int[] elementData; // non-private to simplify nested class access
 71 
 72     protected transient int modCount = 0;
 73 
 74     /**
 75      * The size of the ArrayList (the number of elements it contains).
 76      *
 77      * @serial
 78      */
 79     private int size;
 80 
 81     /**
 82      * Constructs an empty list with the specified initial capacity.
 83      *
 84      * @param  initialCapacity  the initial capacity of the list
 85      * @throws IllegalArgumentException if the specified initial capacity
 86      *         is negative
 87      */
 88     public ArrayListInt(int initialCapacity) {
 89         if (initialCapacity > 0) {
 90             this.elementData = new int[initialCapacity];
 91         } else if (initialCapacity == 0) {
 92             this.elementData = EMPTY_ELEMENTDATA;
 93         } else {
 94             throw new IllegalArgumentException("Illegal Capacity: "+
 95                                                initialCapacity);
 96         }
 97     }
 98 
 99     /**
100      * Constructs an empty list with an initial capacity of ten.
101      */
102     public ArrayListInt() {
103         this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
104     }
105 
106     /**
107      * Trims the capacity of this {@code ArrayList} instance to be the
108      * list's current size.  An application can use this operation to minimize
109      * the storage of an {@code ArrayList} instance.
110      */
111     public void trimToSize() {
112         modCount++;
113         if (size < elementData.length) {
114             elementData = (size == 0)
115               ? EMPTY_ELEMENTDATA
116               : Arrays.copyOf(elementData, size);
117         }
118     }
119 
120     /**
121      * Increases the capacity of this {@code ArrayList} instance, if
122      * necessary, to ensure that it can hold at least the number of elements
123      * specified by the minimum capacity argument.
124      *
125      * @param minCapacity the desired minimum capacity
126      */
127     public void ensureCapacity(int minCapacity) {
128         if (minCapacity > elementData.length
129             && !(elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
130                  && minCapacity <= DEFAULT_CAPACITY)) {
131             modCount++;
132             grow(minCapacity);
133         }
134     }
135 
136     /**
137      * Increases the capacity to ensure that it can hold at least the
138      * number of elements specified by the minimum capacity argument.
139      *
140      * @param minCapacity the desired minimum capacity
141      * @throws OutOfMemoryError if minCapacity is less than zero
142      */
143     private int[] grow(int minCapacity) {
144         int oldCapacity = elementData.length;
145         if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
146             int newCapacity = newLength(oldCapacity,
147                     minCapacity - oldCapacity, /* minimum growth */
148                     oldCapacity >> 1           /* preferred growth */);
149             return elementData = Arrays.copyOf(elementData, newCapacity);
150         } else {
151             return elementData = new int[Math.max(DEFAULT_CAPACITY, minCapacity)];
152         }
153     }
154 
155     private int[] grow() {
156         return grow(size + 1);
157     }
158 
159     /**
160      * Returns the number of elements in this list.
161      *
162      * @return the number of elements in this list
163      */
164     public int size() {
165         return size;
166     }
167 
168     /**
169      * Returns {@code true} if this list contains no elements.
170      *
171      * @return {@code true} if this list contains no elements
172      */
173     public boolean isEmpty() {
174         return size == 0;
175     }
176 
177     /**
178      * Returns {@code true} if this list contains the specified element.
179      * More formally, returns {@code true} if and only if this list contains
180      * at least one element {@code e} such that
181      * {@code Objects.equals(o, e)}.
182      *
183      * @param o element whose presence in this list is to be tested
184      * @return {@code true} if this list contains the specified element
185      */
186     public boolean contains(int o) {
187         return indexOf(o) >= 0;
188     }
189 
190     /**
191      * Returns the index of the first occurrence of the specified element
192      * in this list, or -1 if this list does not contain the element.
193      * More formally, returns the lowest index {@code i} such that
194      * {@code Objects.equals(o, get(i))},
195      * or -1 if there is no such index.
196      */
197     public int indexOf(int o) {
198         return indexOfRange(o, 0, size);
199     }
200 
201     int indexOfRange(int o, int start, int end) {
202         int[] es = elementData;
203         for (int i = start; i < end; i++) {
204             if (o == es[i]) {
205                 return i;
206             }
207         }
208         return -1;
209     }
210 
211     /**
212      * Returns the index of the last occurrence of the specified element
213      * in this list, or -1 if this list does not contain the element.
214      * More formally, returns the highest index {@code i} such that
215      * {@code Objects.equals(o, get(i))},
216      * or -1 if there is no such index.
217      */
218     public int lastIndexOf(int o) {
219         return lastIndexOfRange(o, 0, size);
220     }
221 
222     int lastIndexOfRange(int o, int start, int end) {
223         int[] es = elementData;
224             {
225             for (int i = end - 1; i >= start; i--) {
226                 if (o == es[i]) {
227                     return i;
228                 }
229             }
230         }
231         return -1;
232     }
233 
234     /**
235      * Returns an array containing all of the elements in this list
236      * in proper sequence (from first to last element).
237      *
238      * <p>The returned array will be "safe" in that no references to it are
239      * maintained by this list.  (In other words, this method must allocate
240      * a new array).  The caller is thus free to modify the returned array.
241      *
242      * <p>This method acts as bridge between array-based and collection-based
243      * APIs.
244      *
245      * @return an array containing all of the elements in this list in
246      *         proper sequence
247      */
248     public int[] toArray() {
249         return Arrays.copyOf(elementData, size);
250     }
251 
252     // Positional Access Operations
253 
254     @SuppressWarnings("unchecked")
255     int elementData(int index) {
256         return (int) elementData[index];
257     }
258 
259     @SuppressWarnings("unchecked")
260     static int elementAt(int[] es, int index) {
261         return es[index];
262     }
263 
264     /**
265      * Returns the element at the specified position in this list.
266      *
267      * @param  index index of the element to return
268      * @return the element at the specified position in this list
269      * @throws IndexOutOfBoundsException {@inheritDoc}
270      */
271     public int get(int index) {
272         Objects.checkIndex(index, size);
273         return elementData(index);
274     }
275 
276     /**
277      * Replaces the element at the specified position in this list with
278      * the specified element.
279      *
280      * @param index index of the element to replace
281      * @param element element to be stored at the specified position
282      * @return the element previously at the specified position
283      * @throws IndexOutOfBoundsException {@inheritDoc}
284      */
285     public int set(int index, int element) {
286         Objects.checkIndex(index, size);
287         int oldValue = elementData(index);
288         elementData[index] = element;
289         return oldValue;
290     }
291 
292     /**
293      * This helper method split out from add(int) to keep method
294      * bytecode size under 35 (the -XX:MaxInlineSize default value),
295      * which helps when add(int) is called in a C1-compiled loop.
296      */
297     private void add(int e, int[] elementData, int s) {
298         if (s == elementData.length)
299             elementData = grow();
300         elementData[s] = e;
301         size = s + 1;
302     }
303 
304     /**
305      * Appends the specified element to the end of this list.
306      *
307      * @param e element to be appended to this list
308      * @return {@code true} (as specified by {@link Collection#add})
309      */
310     public boolean add(int e) {
311         modCount++;
312         add(e, elementData, size);
313         return true;
314     }
315 
316     /**
317      * Inserts the specified element at the specified position in this
318      * list. Shifts the element currently at that position (if any) and
319      * any subsequent elements to the right (adds one to their indices).
320      *
321      * @param index index at which the specified element is to be inserted
322      * @param element element to be inserted
323      * @throws IndexOutOfBoundsException {@inheritDoc}
324      */
325     public void add(int index, int element) {
326         rangeCheckForAdd(index);
327         modCount++;
328         final int s;
329         int[] elementData;
330         if ((s = size) == (elementData = this.elementData).length)
331             elementData = grow();
332         System.arraycopy(elementData, index,
333                          elementData, index + 1,
334                          s - index);
335         elementData[index] = element;
336         size = s + 1;
337     }
338 
339     /**
340      * Removes the element at the specified position in this list.
341      * Shifts any subsequent elements to the left (subtracts one from their
342      * indices).
343      *
344      * @param index the index of the element to be removed
345      * @return the element that was removed from the list
346      * @throws IndexOutOfBoundsException {@inheritDoc}
347      */
348     public int remove(int index) {
349         Objects.checkIndex(index, size);
350         final int[] es = elementData;
351 
352         int oldValue = (int) es[index];
353         fastRemove(es, index);
354 
355         return oldValue;
356     }
357 
358     /**
359      * {@inheritDoc}
360      */
361     public boolean equals(Object o) {
362         if (o == this) {
363             return true;
364         }
365 
366         if (!(o instanceof ArrayListInt)) {
367             return false;
368         }
369 
370         final int expectedModCount = modCount;
371         // ArrayList can be subclassed and given arbitrary behavior, but we can
372         // still deal with the common case where o is ArrayList precisely
373         boolean equal = equalsArrayList((ArrayListInt) o);
374 
375         checkForComodification(expectedModCount);
376         return equal;
377     }
378 
379     private boolean equalsArrayList(ArrayListInt other) {
380         final int otherModCount = other.modCount;
381         final int s = size;
382         boolean equal;
383         if (equal = (s == other.size)) {
384             final int[] otherEs = other.elementData;
385             final int[] es = elementData;
386             if (s > es.length || s > otherEs.length) {
387                 throw new ConcurrentModificationException();
388             }
389             for (int i = 0; i < s; i++) {
390                 if (es[i] != otherEs[i]) {
391                     equal = false;
392                     break;
393                 }
394             }
395         }
396         other.checkForComodification(otherModCount);
397         return equal;
398     }
399 
400     private void checkForComodification(final int expectedModCount) {
401         if (modCount != expectedModCount) {
402             throw new ConcurrentModificationException();
403         }
404     }
405 
406     /**
407      * {@inheritDoc}
408      */
409     public int hashCode() {
410         int expectedModCount = modCount;
411         int hash = hashCodeRange(0, size);
412         checkForComodification(expectedModCount);
413         return hash;
414     }
415 
416     int hashCodeRange(int from, int to) {
417         final int[] es = elementData;
418         if (to > es.length) {
419             throw new ConcurrentModificationException();
420         }
421         int hashCode = 1;
422         for (int i = from; i < to; i++) {
423             int e = es[i];
424             hashCode = 31 * hashCode + e;
425         }
426         return hashCode;
427     }
428 
429     /**
430      * Removes the first occurrence of the specified element from this list,
431      * if it is present.  If the list does not contain the element, it is
432      * unchanged.  More formally, removes the element with the lowest index
433      * {@code i} such that
434      * {@code Objects.equals(o, get(i))}
435      * (if such an element exists).  Returns {@code true} if this list
436      * contained the specified element (or equivalently, if this list
437      * changed as a result of the call).
438      *
439      * @param o element to be removed from this list, if present
440      * @return {@code true} if this list contained the specified element
441      */
442     public boolean removeC(int o) {
443         final int[] es = elementData;
444         final int size = this.size;
445         int i = 0;
446         found:
447         {
448 //            if (o == null) {
449 //                for (; i < size; i++)
450 //                    if (es[i] == null)
451 //                        break found;
452 //            } else
453                 {
454                 for (; i < size; i++)
455                     if (o == es[i])
456                         break found;
457             }
458             return false;
459         }
460         fastRemove(es, i);
461         return true;
462     }
463 
464     /**
465      * Private remove method that skips bounds checking and does not
466      * return the value removed.
467      */
468     private void fastRemove(int[] es, int i) {
469         modCount++;
470         final int newSize;
471         if ((newSize = size - 1) > i)
472             System.arraycopy(es, i + 1, es, i, newSize - i);
473         es[size = newSize] = 0;
474     }
475 
476     /**
477      * Removes all of the elements from this list.  The list will
478      * be empty after this call returns.
479      */
480     public void clear() {
481         modCount++;
482         final int[] es = elementData;
483         for (int to = size, i = size = 0; i < to; i++)
484             es[i] = 0;
485     }
486 
487     /**
488      * Removes from this list all of the elements whose index is between
489      * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.
490      * Shifts any succeeding elements to the left (reduces their index).
491      * This call shortens the list by {@code (toIndex - fromIndex)} elements.
492      * (If {@code toIndex==fromIndex}, this operation has no effect.)
493      *
494      * @throws IndexOutOfBoundsException if {@code fromIndex} or
495      *         {@code toIndex} is out of range
496      *         ({@code fromIndex < 0 ||
497      *          toIndex > size() ||
498      *          toIndex < fromIndex})
499      */
500     protected void removeRange(int fromIndex, int toIndex) {
501         if (fromIndex > toIndex) {
502             throw new IndexOutOfBoundsException(
503                     outOfBoundsMsg(fromIndex, toIndex));
504         }
505         modCount++;
506         shiftTailOverGap(elementData, fromIndex, toIndex);
507     }
508 
509     /** Erases the gap from lo to hi, by sliding down following elements. */
510     private void shiftTailOverGap(int[] es, int lo, int hi) {
511         System.arraycopy(es, hi, es, lo, size - hi);
512         for (int to = size, i = (size -= hi - lo); i < to; i++)
513             es[i] = 0;
514     }
515 
516     /**
517      * A version of rangeCheck used by add and addAll.
518      */
519     private void rangeCheckForAdd(int index) {
520         if (index > size || index < 0)
521             throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
522     }
523 
524     /**
525      * Constructs an IndexOutOfBoundsException detail message.
526      * Of the many possible refactorings of the error handling code,
527      * this "outlining" performs best with both server and client VMs.
528      */
529     private String outOfBoundsMsg(int index) {
530         return "Index: "+index+", Size: "+size;
531     }
532 
533     /**
534      * A version used in checking (fromIndex > toIndex) condition
535      */
536     private static String outOfBoundsMsg(int fromIndex, int toIndex) {
537         return "From Index: " + fromIndex + " > To Index: " + toIndex;
538     }
539 
540     /**
541      * Returns an iterator over the elements in this list in proper sequence.
542      *
543      * <p>The returned iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
544      *
545      * @return an iterator over the elements in this list in proper sequence
546      */
547     public IntItr iterator() {
548         return new IntItr();
549     }
550 
551     /**
552      * An optimized version of AbstractList.Itr
553      */
554     private class IntItr {
555         int cursor;       // index of next element to return
556         int lastRet = -1; // index of last element returned; -1 if no such
557         int expectedModCount = modCount;
558 
559         // prevent creating a synthetic constructor
560         IntItr() {}
561 
562         public boolean hasNext() {
563             return cursor != size;
564         }
565 
566         @SuppressWarnings("unchecked")
567         public int next() {
568             checkForComodification();
569             int i = cursor;
570             if (i >= size)
571                 throw new NoSuchElementException();
572             int[] elementData = ArrayListInt.this.elementData;
573             if (i >= elementData.length)
574                 throw new ConcurrentModificationException();
575             cursor = i + 1;
576             return (int) elementData[lastRet = i];
577         }
578 
579         public void remove() {
580             if (lastRet < 0)
581                 throw new IllegalStateException();
582             checkForComodification();
583 
584             try {
585                 ArrayListInt.this.remove(lastRet);
586                 cursor = lastRet;
587                 lastRet = -1;
588                 expectedModCount = modCount;
589             } catch (IndexOutOfBoundsException ex) {
590                 throw new ConcurrentModificationException();
591             }
592         }
593 
594         public void forEachRemaining(IntConsumer action) {
595             Objects.requireNonNull(action);
596             final int size = ArrayListInt.this.size;
597             int i = cursor;
598             if (i < size) {
599                 final int[] es = elementData;
600                 if (i >= es.length)
601                     throw new ConcurrentModificationException();
602                 for (; i < size && modCount == expectedModCount; i++)
603                     action.accept(elementAt(es, i));
604                 // update once at end to reduce heap write traffic
605                 cursor = i;
606                 lastRet = i - 1;
607                 checkForComodification();
608             }
609         }
610 
611         final void checkForComodification() {
612             if (modCount != expectedModCount)
613                 throw new ConcurrentModificationException();
614         }
615     }
616 
617     static final int MAX_ARRAY_LENGTH = Integer.MAX_VALUE - 8;
618 
619     static int newLength(int oldLength, int minGrowth, int prefGrowth) {
620         // assert oldLength >= 0
621         // assert minGrowth > 0
622 
623         int newLength = Math.max(minGrowth, prefGrowth) + oldLength;
624         if (newLength - MAX_ARRAY_LENGTH <= 0) {
625             return newLength;
626         }
627         return hugeLength(oldLength, minGrowth);
628     }
629 
630     private static int hugeLength(int oldLength, int minGrowth) {
631         int minLength = oldLength + minGrowth;
632         if (minLength < 0) { // overflow
633             throw new OutOfMemoryError("Required array length too large");
634         }
635         if (minLength <= MAX_ARRAY_LENGTH) {
636             return MAX_ARRAY_LENGTH;
637         }
638         return Integer.MAX_VALUE;
639     }
640 }