IntList.java
001 /*
002  * Java Genetic Algorithm Library (jenetics-5.1.0).
003  * Copyright (c) 2007-2019 Franz Wilhelmstötter
004  *
005  * Licensed under the Apache License, Version 2.0 (the "License");
006  * you may not use this file except in compliance with the License.
007  * You may obtain a copy of the License at
008  *
009  *      http://www.apache.org/licenses/LICENSE-2.0
010  *
011  * Unless required by applicable law or agreed to in writing, software
012  * distributed under the License is distributed on an "AS IS" BASIS,
013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014  * See the License for the specific language governing permissions and
015  * limitations under the License.
016  *
017  * Author:
018  *    Franz Wilhelmstötter (franz.wilhelmstoetter@gmail.com)
019  */
020 package io.jenetics.ext.internal;
021 
022 import static java.lang.Math.max;
023 import static java.lang.String.format;
024 import static java.lang.System.arraycopy;
025 import static java.util.Arrays.copyOf;
026 import static java.util.Objects.requireNonNull;
027 
028 import java.util.Arrays;
029 import java.util.function.IntConsumer;
030 import java.util.stream.IntStream;
031 
032 /**
033  * Resizable-int array implementation
034  *
035  @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
036  @version 4.3
037  @since 4.1
038  */
039 public final class IntList {
040 
041     private static final int MAX_SIZE = Integer.MAX_VALUE - 8;
042     private static final int DEFAULT_CAPACITY = 10;
043     private static final int[] EMPTY_ARRAY = {};
044     private static final int[] DEFAULT_EMPTY_ARRAY = {};
045 
046     private int[] _data;
047     private int _size;
048 
049     /**
050      * Constructs an empty list with the specified initial capacity.
051      *
052      @param  capacity  the initial capacity of the list
053      @throws IllegalArgumentException if the specified initial capacity
054      *         is negative
055      */
056     public IntList(final int capacity) {
057         if (capacity > 0) {
058             _data = new int[capacity];
059         else if (capacity == 0) {
060             _data = EMPTY_ARRAY;
061         else {
062             throw new IllegalArgumentException("Illegal Capacity: "+ capacity);
063         }
064     }
065 
066     /**
067      * Constructs an empty list with an initial capacity of ten.
068      */
069     public IntList() {
070         _data = DEFAULT_EMPTY_ARRAY;
071     }
072 
073     /**
074      * Returns the element at the specified position in this list.
075      *
076      @param  index index of the element to return
077      @return the element at the specified position in this list
078      @throws IndexOutOfBoundsException if the index is out of range
079      *         {@code (index < 0 || index > size())}
080      */
081     public int get(final int index) {
082         rangeCheck(index);
083 
084         return _data[index];
085     }
086 
087     /**
088      * Performs the given action for each element of the list.
089      *
090      @param action the action to be performed for each element
091      @throws NullPointerException if the specified action is {@code null}
092      */
093     public void forEach(final IntConsumer action) {
094         requireNonNull(action);
095 
096         final int size = _size;
097         for (int i = 0; i < size; ++i) {
098             action.accept(_data[i]);
099         }
100     }
101 
102     /**
103      * Returns a sequential {@link IntStream} with the specified list as its
104      * source.
105      *
106      @return a sequential {@link IntStream}
107      */
108     public IntStream stream() {
109         return Arrays.stream(_data, 0, _size);
110     }
111 
112     /**
113      * Appends the specified element to the end of this list.
114      *
115      @param element element to be appended to this list
116      */
117     public void add(final int element) {
118         ensureSize(_size + 1);
119         _data[_size++= element;
120     }
121 
122     /**
123      * Inserts the specified element at the specified position in this list.
124      * Shifts the element currently at that position (if any) and any subsequent
125      * elements to the right (adds one to their indices).
126      *
127      @param index index at which the specified element is to be inserted
128      @param element element to be inserted
129      @throws IndexOutOfBoundsException if the index is out of range
130      *         {@code (index < 0 || index > size())}
131      */
132     public void add(final int index, final int element) {
133         addRangeCheck(index);
134 
135         ensureSize(_size + 1);
136         arraycopy(
137             _data, index,
138             _data, index + 1,
139             _size - index
140         );
141         _data[index= element;
142         _size++;
143     }
144 
145     /**
146      * Appends all of the elements in the specified array to the end of this
147      * list.
148      *
149      @param elements array containing elements to be added to this list
150      @return <tt>true</tt> if this list changed as a result of the call
151      @throws NullPointerException if the specified array is null
152      */
153     public boolean addAll(final int[] elements) {
154         final int count = elements.length;
155         ensureSize(_size + count);
156         arraycopy(elements, 0, _data, _size, count);
157         _size += count;
158 
159         return count != 0;
160     }
161 
162     /**
163      * Inserts all of the elements in the specified array into this list,
164      * starting at the specified position.
165      *
166      @param index index at which to insert the first element from the
167      *              specified collection
168      @param elements collection containing elements to be added to this list
169      @return <tt>true</tt> if this list changed as a result of the call
170      @throws IndexOutOfBoundsException if the index is out of range
171      *         {@code (index < 0 || index > size())}
172      @throws NullPointerException if the specified array is null
173      */
174     public boolean addAll(final int index, final int[] elements) {
175         addRangeCheck(index);
176 
177         final int count = elements.length;
178         ensureSize(_size + count);
179 
180         final int moved = _size - index;
181         if (moved > 0) {
182             arraycopy(_data, index, _data, index + count, moved);
183         }
184 
185         arraycopy(elements, 0, _data, index, count);
186         _size += count;
187         return count != 0;
188     }
189 
190     /**
191      * Removes all of the elements from this list. The list will be empty after
192      * this call returns.
193      */
194     public void clear() {
195         _size = 0;
196     }
197 
198     /**
199      * Trims the capacity of this <tt>ArrayList</tt> instance to be the list's
200      * current size.  An application can use this operation to minimize the
201      * storage of an <tt>ArrayList</tt> instance.
202      */
203     public void trimToSize() {
204         if (_size < _data.length) {
205             _data = _size == 0
206                 ? EMPTY_ARRAY
207                 : copyOf(_data, _size);
208         }
209     }
210 
211     /**
212      * Returns the number of elements in this list.
213      *
214      @return the number of elements in this list
215      */
216     public int size() {
217         return _size;
218     }
219 
220     /**
221      * Return {@code true} if the list is empty.
222      *
223      @return {@code true} if the list is empty, {@code false} otherwise
224      */
225     public boolean isEmpty() {
226         return _size == 0;
227     }
228 
229     /**
230      * Return the current elements as int array.
231      *
232      @return the current elements as int array
233      */
234     public int[] toArray() {
235         return copyOf(_data, _size);
236     }
237 
238     private void ensureSize(int size) {
239         ensureExplicitSize(capacity(_data, size));
240     }
241 
242     private void ensureExplicitSize(int size) {
243         if (size - _data.length > 0) {
244             grow(size);
245         }
246     }
247 
248     private void rangeCheck(final int index) {
249         if (index >= _size)
250             throw new IndexOutOfBoundsException(format(
251                 "Index: %d, Size: %d", index, _size
252             ));
253     }
254 
255     private void addRangeCheck(int index) {
256         if (index > _size || index < 0)
257             throw new IndexOutOfBoundsException(format(
258                 "Index: %d, Size: %d", index, _size
259             ));
260     }
261 
262     private static int capacity(final int[] data, final int capacity) {
263         if (data == DEFAULT_EMPTY_ARRAY) {
264             return max(DEFAULT_CAPACITY, capacity);
265         }
266         return capacity;
267     }
268 
269     private void grow(final int size) {
270         final int oldSize = _data.length;
271 
272         int newSize = oldSize + (oldSize >> 1);
273         if (newSize - size < 0) {
274             newSize = size;
275         }
276         if (newSize - MAX_SIZE > 0) {
277             newSize = hugeCapacity(size);
278         }
279 
280         _data = copyOf(_data, newSize);
281     }
282 
283     private static int hugeCapacity(final int minCapacity) {
284         if (minCapacity < 0) {
285             throw new OutOfMemoryError();
286         }
287 
288         return minCapacity > MAX_SIZE
289             ? Integer.MAX_VALUE
290             : MAX_SIZE;
291     }
292 
293 }