/* (c) 2014 LinkedIn Corp. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use * this file except in compliance with the License. You may obtain a copy of the * License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. */ package com.linkedin.cubert.memory; import java.util.Arrays; import java.util.List; /** * A resizable list of integers that does not box/unbox the values to Integer objects. * <p> * This class supports a subset of methods from {@link java.util.List}: * <ul> * <li> {@link add} to add a value in the list</li> * * <li> {@link clear} to reset the list.</li> * * <li> {@link iterator} to obtain an {@link IntIterator} for values.</li> * </ul> * <p> * This class is not thread-safe. Also the iterator is not safe against concurrent * modifications (calling store() or clear() while iterating). * <p> * Implementation notes: the underlying storage is an ArrayList of int array ( * {@code ArrayList<int[]>}). Each int array in the ArryaList is of fixed size (equal to * BatchSize). * * @see IntSet * @author Maneesh Varshney * */ public final class IntArrayList extends SegmentedArrayList { private final List<int[]> list; public IntArrayList() { super(); list = (List) super.list; } public IntArrayList(int batchSize) { super(batchSize); list = (List) super.list; } public void setDefaultValue(Integer defaultValue) { if (defaultValue == null) return; if (! (defaultValue instanceof Integer)) throw new RuntimeException("Non Integer used as default value for " + IntArrayList.class.getCanonicalName()); super.setDefaultValue(defaultValue); } @Override public void add(Object value) { addInt(((Number) value).intValue()); } @Override public Object get(int index) { return getInt(index); } @Override public int compareIndices(int i1, int i2) { final int l1 = getInt(i1); final int l2 = getInt(i2); return (l1 < l2 ? -1 : (l1 == l2 ? 0 : 1)); } /** * Add an integer value to the list. * * @param value * the value to add to list */ public void addInt(int value) { ensureCapacity(size); int index = size % batchSize; int batch = size / batchSize; list.get(batch)[index] = value; size++; } @Override protected Object freshBatch(Object reuse) { int[] batch = (reuse != null) ? ((int[]) reuse) : new int[batchSize]; if (defaultValue != null) Arrays.fill(batch, ((Integer) defaultValue).intValue()); return batch; } public void updateInt(int location, int value) { int batch = location / batchSize; if (batch >= list.size()) throw new RuntimeException("Specified update location is outside range. Use add API"); int index = location % batchSize; list.get(batch)[index] = value; } public int getInt(int pointer) { int batch = pointer / batchSize; int index = pointer % batchSize; return list.get(batch)[index]; } /** * Obtain an iterator for the list. * * @return an iterator for the list */ public IntIterator iterator() { return new StoreIterator(); } /** * Inner class that implements the iterator for this list. * * @author Maneesh Varshney * */ private class StoreIterator implements IntIterator { private int pointer = 0; @Override public boolean hasNext() { return pointer < size; } @Override public int next() { int result = getInt(pointer); pointer++; return result; } } }