/*
* (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.ArrayList;
import java.util.Comparator;
import java.util.List;
/**
* 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>
*
* </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 object/primitive arrays.
* Each array in the ArrayList is of fixed size (equal to BatchSize).
*
* Created by spyne on 1/9/15.
*/
public abstract class SegmentedArrayList
{
protected final List<Object> list = new ArrayList<Object>();
protected final int batchSize;
protected int size = 0;
protected Object defaultValue = null;
public SegmentedArrayList()
{
batchSize = 1 << 10;
}
/**
*
* @param batchSize the size of each batch that is used for paging.
*/
public SegmentedArrayList(int batchSize)
{
this.batchSize = batchSize;
}
public void setDefaultValue(Object defaultValue)
{
if (list.size() > 0)
{
throw new RuntimeException("Error: set default value for " + this.getClass().getCanonicalName()
+ " before any elements are allocated");
}
this.defaultValue = defaultValue;
}
/**
* Add an Object to the list.
*
* @param value: the value to add to list
*/
public abstract void add(Object value);
/**
* Returns the object at a specific index
* @param index index
* @return object at index
*/
public abstract Object get(int index);
/**
* compare the objects at indices i1 and i2 and return compare(object(i1), object(i2))
* @param i1 index 1
* @param i2 index 2
* @return compare(object(i1), object(i2))
*/
public abstract int compareIndices(int i1, int i2);
/**
* Setter method for the comparator parameter
*
* @param comparator the comparator object
*/
public void setComparator(Comparator comparator)
{
}
/**
* Clear the items in the list.
*/
public void clear()
{
list.clear();
size = 0;
}
/**
* Reset each batch. Expected size of array is to accommodate <code>length</code> number of elements.
*
* @param length
*/
public void reset(int length)
{
List<Object> savedBatches = new ArrayList<Object>();
for (Object batch : list)
{
savedBatches.add(batch);
if (savedBatches.size() * batchSize >= length)
break;
}
this.clear();
for (Object batch : savedBatches)
{
list.add(freshBatch(batch));
}
ensureCapacity(length);
}
public void reset()
{
reset(batchSize);
}
/**
*
* @return the size of the list
*/
public int size()
{
return size;
}
/**
* Increases the size of array to accommodate <code>length</code> number of elements.
*
* @param length
*/
public void ensureCapacity(int length)
{
int batch = length / batchSize;
while (batch >= list.size())
list.add(freshBatch(null));
}
/**
* Returns a new batch of primitive array. Override in derived classes.
*
* @return
*/
protected abstract Object freshBatch(Object reuse);
public int capacity()
{
return list.size() * batchSize;
}
}