blob: c3ff8a909ce05fd8d676eeff4f272b044e6cdba2 [file] [log] [blame]
/*
* Copyright (c) 2012, 2013, 2015 Eike Stepper (Berlin, Germany) and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Eike Stepper - initial API and implementation
*/
package org.eclipse.net4j.util.collection;
import java.lang.reflect.Array;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Queue;
import java.util.RandomAccess;
/**
* @author Eike Stepper
* @since 3.3
*/
public class GrowingRandomAccessList<E> extends AbstractList<E>implements Queue<E>, RandomAccess
{
private final Class<E> componentType;
private final int pageCapacity;
private List<E[]> pages = new ArrayList<E[]>();
private int firstFree;
private int lastFree;
public GrowingRandomAccessList(Class<E> componentType, int pageCapacity)
{
this.componentType = componentType;
this.pageCapacity = pageCapacity;
}
@Override
public E get(int index)
{
int size = size();
if (index >= size)
{
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
}
index += firstFree;
E[] page = getPage(index);
return page[index % pageCapacity];
}
@Override
public int size()
{
return pages.size() * pageCapacity - firstFree - lastFree;
}
public void addFirst(E e)
{
E[] page;
if (firstFree == 0)
{
if (pages.isEmpty())
{
initFirstPage();
}
else
{
firstFree = pageCapacity;
}
page = createPage();
pages.add(0, page);
}
else
{
page = pages.get(0);
}
page[--firstFree] = e;
}
public void addLast(E e)
{
E[] page;
if (lastFree == 0)
{
if (pages.isEmpty())
{
initFirstPage();
}
else
{
lastFree = pageCapacity;
}
page = createPage();
pages.add(page);
}
else
{
int size = pages.size();
page = pages.get(size - 1);
}
page[pageCapacity - lastFree--] = e;
}
@Override
public boolean add(E e)
{
addLast(e);
return true;
}
@Override
public E set(int index, E element)
{
throw new UnsupportedOperationException();
}
@Override
public void add(int index, E element)
{
int size = size();
if (index > size || index < 0)
{
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
}
if (index == 0)
{
addFirst(element);
}
else if (index == size)
{
addLast(element);
}
else
{
GrowingRandomAccessList<E> result = new GrowingRandomAccessList<E>(componentType, pageCapacity);
for (int i = 0; i < size; i++)
{
E e = get(i);
if (i == index)
{
result.add(element);
}
result.add(e);
}
pages = result.pages;
firstFree = result.firstFree;
lastFree = result.lastFree;
}
}
@Override
public E remove(int index)
{
throw new UnsupportedOperationException();
}
@Override
public void clear()
{
throw new UnsupportedOperationException();
}
@Override
public boolean addAll(int index, Collection<? extends E> c)
{
throw new UnsupportedOperationException();
}
@Override
public boolean remove(Object o)
{
throw new UnsupportedOperationException();
}
@Override
public boolean removeAll(Collection<?> c)
{
throw new UnsupportedOperationException();
}
@Override
public boolean retainAll(Collection<?> c)
{
throw new UnsupportedOperationException();
}
public boolean offerFirst(E e)
{
addFirst(e);
return true;
}
public boolean offerLast(E e)
{
addLast(e);
return true;
}
public E removeFirst()
{
throw new UnsupportedOperationException();
}
public E removeLast()
{
throw new UnsupportedOperationException();
}
public E pollFirst()
{
throw new UnsupportedOperationException();
}
public E pollLast()
{
throw new UnsupportedOperationException();
}
public E getFirst()
{
return get(0);
}
public E getLast()
{
return get(size() - 1);
}
public E peekFirst()
{
if (pages.isEmpty())
{
return null;
}
return getFirst();
}
public E peekLast()
{
if (pages.isEmpty())
{
return null;
}
return getLast();
}
public boolean removeFirstOccurrence(Object o)
{
throw new UnsupportedOperationException();
}
public boolean removeLastOccurrence(Object o)
{
throw new UnsupportedOperationException();
}
public boolean offer(E e)
{
return offerLast(e);
}
public E remove()
{
throw new UnsupportedOperationException();
}
public E poll()
{
throw new UnsupportedOperationException();
}
public E element()
{
return getFirst();
}
public E peek()
{
return peekFirst();
}
public void push(E e)
{
addFirst(e);
}
public E pop()
{
throw new UnsupportedOperationException();
}
public Iterator<E> descendingIterator()
{
ListIterator<E> delegate = listIterator(size() - 1);
return new BidirectionalIterator<E>(delegate, true);
}
protected E[] createPage()
{
@SuppressWarnings("unchecked")
E[] page = (E[])Array.newInstance(componentType, pageCapacity);
return page;
}
protected E[] getPage(int index)
{
return pages.get(getPageIndex(index));
}
protected int getPageIndex(int index)
{
return index / pageCapacity;
}
private void initFirstPage()
{
int centerIndex = (pageCapacity - 1) / 2;
firstFree = centerIndex + 1;
lastFree = pageCapacity - centerIndex - 1;
}
}