/*
* Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.oracle.max.vma.tools.qa;
import java.util.*;
import com.oracle.max.vma.tools.qa.TransientVMAdviceHandlerTypes.*;
/**
* Manages the list of {@link } instances for an {@link ObjectRecord}.
* This is where most of the space goes, so it pays to have a custom implementation
* that tries to use the minimum space. There are the following implementations:
* <ul>
* <li>{@link Empty the empty list} which is how we start
* <li>{@link Singleton one element}
* <li>{@link Doubleton two elements}
* <li>{@link SimpleArray array from 3 to 7 elements}
* <li>{@link ChunkedArray lists 8 elements and larger} stored as a list of chunks of size 8
* </ul>
*
*/
public class GrowableArrayImpl {
private GrowableArrayImpl() {
}
public static GrowableArray create() {
return new Empty();
}
static abstract class GAIteratorAdaptor implements Iterator<AdviceRecord> {
public void remove() {
throw new UnsupportedOperationException();
}
}
static class Empty extends GrowableArray {
@Override
public GrowableArray add(AdviceRecord te) {
return new Singleton(te);
}
@Override
public int size() {
return 0;
}
@Override
public AdviceRecord get(int index) {
throw new IndexOutOfBoundsException();
}
@Override
public Iterator<AdviceRecord> iterator() {
return new GAIterator();
}
private static class GAIterator extends GAIteratorAdaptor {
public boolean hasNext() {
return false;
}
public AdviceRecord next() {
throw new NoSuchElementException();
}
}
}
/**
* Single element.
*/
static class Singleton extends GrowableArray {
private final AdviceRecord te;
Singleton(AdviceRecord te) {
this.te = te;
}
@Override
public GrowableArray add(AdviceRecord te) {
return new Doubleton(this.te, te);
}
@Override
public int size() {
return 1;
}
@Override
public AdviceRecord get(int index) {
if (index > 0) {
throw new IndexOutOfBoundsException();
}
return te;
}
@Override
public Iterator<AdviceRecord> iterator() {
return new GAIterator();
}
private class GAIterator extends GAIteratorAdaptor {
private boolean processed;
public boolean hasNext() {
return !processed;
}
public AdviceRecord next() {
processed = true;
return te;
}
}
}
/**
* Two elements.
*
*/
static class Doubleton extends GrowableArray {
private final AdviceRecord first;
private final AdviceRecord second;
Doubleton(AdviceRecord first, AdviceRecord second) {
this.first = first;
this.second = second;
}
@Override
public AdviceRecord get(int index) {
if (index > 1) {
throw new IndexOutOfBoundsException();
}
return index == 0 ? first : second;
}
@Override
public int size() {
return 2;
}
@Override
public GrowableArray add(AdviceRecord te) {
GrowableArray result = new SimpleArray(first, second, te);
return result;
}
@Override
public Iterator<AdviceRecord> iterator() {
return new GAIterator();
}
private class GAIterator extends GAIteratorAdaptor {
private int iterIndex;
public boolean hasNext() {
return iterIndex < 2;
}
public AdviceRecord next() {
return iterIndex++ == 0 ? first : second;
}
}
}
static class SimpleArray extends GrowableArray {
AdviceRecord[] array;
int nextIndex;
SimpleArray(AdviceRecord first, AdviceRecord second, AdviceRecord third) {
array = new AdviceRecord[3];
array[0] = first;
array[1] = second;
array[2] = third;
nextIndex = 3;
}
@Override
public GrowableArray add(AdviceRecord element) {
if (nextIndex < array.length) {
array[nextIndex++] = element;
return this;
} else if (array.length < ChunkedArray.CHUNK_SIZE - 1) {
final AdviceRecord[] newArray = new AdviceRecord[array.length + 1];
System.arraycopy(array, 0, newArray, 0, array.length);
array = newArray;
array[nextIndex++] = element;
return this;
} else {
final GrowableArray result = new ChunkedArray(array);
result.add(element);
return result;
}
}
@Override
public AdviceRecord get(int index) {
return array[index];
}
@Override
public int size() {
return array.length;
}
@Override
public Iterator<AdviceRecord> iterator() {
return new GAIterator();
}
private class GAIterator extends GAIteratorAdaptor {
private int iterIndex;
public boolean hasNext() {
return iterIndex < nextIndex;
}
public AdviceRecord next() {
return array[iterIndex++];
}
}
}
/**
* An extensible array based on a list of chunks, each of which is an array.
* For large lists.
*/
static class ChunkedArray extends GrowableArray {
private ArrayList<AdviceRecord[]> chunks = new ArrayList<AdviceRecord[]>();
private AdviceRecord[] currentChunk;
private int indexInChunk;
private static final int CHUNK_SIZE = 8;
ChunkedArray(AdviceRecord[] starter) {
for (AdviceRecord te : starter) {
add(te);
}
}
@Override
public GrowableArray add(AdviceRecord element) {
if (currentChunk == null || indexInChunk >= CHUNK_SIZE) {
currentChunk = new AdviceRecord[CHUNK_SIZE];
chunks.add(currentChunk);
indexInChunk = 0;
}
currentChunk[indexInChunk++] = element;
return this;
}
@Override
public AdviceRecord get(int index) {
final int chunkIndex = index / CHUNK_SIZE;
final int thisIndexInChunk = index % CHUNK_SIZE;
return chunks.get(chunkIndex)[thisIndexInChunk];
}
@Override
public int size() {
if (currentChunk == null) {
return 0;
} else {
return ((chunks.size() - 1) * CHUNK_SIZE) + indexInChunk;
}
}
@Override
public Iterator<AdviceRecord> iterator() {
return new ThisIterator();
}
class ThisIterator implements Iterator<AdviceRecord> {
private AdviceRecord[] iterCurrentChunk;
private int iterChunkIndex;
private int iterIndexInChunk;
private int iterChunkLimit;
ThisIterator() {
iterCurrentChunk = chunks.size() > 0 ? chunks.get(0) : null;
iterChunkLimit = chunks.size() == 1 ? indexInChunk : CHUNK_SIZE;
}
public boolean hasNext() {
return iterCurrentChunk != null
&& iterIndexInChunk < iterChunkLimit;
}
public AdviceRecord next() {
final AdviceRecord result = iterCurrentChunk[iterIndexInChunk++];
if (iterIndexInChunk >= iterChunkLimit) {
iterIndexInChunk = 0;
iterChunkIndex++;
iterCurrentChunk = iterChunkIndex < chunks.size() ? chunks.get(iterChunkIndex) : null;
iterChunkLimit = iterChunkIndex == chunks.size() - 1 ? indexInChunk
: CHUNK_SIZE;
}
return result;
}
public void remove() {
}
}
}
}