001/* 002 * Java Genetic Algorithm Library (jenetics-7.2.0). 003 * Copyright (c) 2007-2023 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 */ 020package io.jenetics.ext.internal.util; 021 022import static java.lang.Math.max; 023import static java.lang.String.format; 024import static java.lang.System.arraycopy; 025import static java.util.Arrays.copyOf; 026import static java.util.Objects.requireNonNull; 027 028import java.util.Arrays; 029import java.util.function.IntConsumer; 030import 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 */ 039public 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 {@code true} 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 the elements in the specified array into this list, starting 164 * 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 {@code true} 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 {@code ArrayList} instance to be the list's 200 * current size. An application can use this operation to minimize the 201 * storage of an {@code ArrayList} 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 an int array. 231 * 232 * @return the current elements as an 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}