/*
* Copyright 2001-2008 Geert Bevin <gbevin[remove] at uwyn dot com>
* Licensed under the Apache License, Version 2.0 (the "License")
* $Id: ContinuationStack.java 3918 2008-04-14 17:35:35Z gbevin $
*/
package com.uwyn.rife.continuations;
import com.uwyn.rife.continuations.instrument.ContinuationDebug;
import com.uwyn.rife.tools.ObjectUtils;
import java.lang.reflect.Array;
import java.util.Arrays;
/**
* [PRIVATE AND UNSUPPORTED] Contains the local state of a continuation.
* <p>This needs to be publicly accessible for the instrumented code to be
* able to interact with it, but it's not supposed to be used directly.
*
* @since 1.6
*/
public class ContinuationStack
{
static final int NONE = 0;
static final int INTEGER = 1;
static final int LONG = 2;
static final int FLOAT = 3;
static final int DOUBLE = 4;
static final int REFERENCE = 5;
private int[] mPositionMapping = null;
private int[] mTypeMapping = null;
private int mStackHeight = 0;
private int[] mIntStack = null;
private long[] mLongStack = null;
private float[] mFloatStack = null;
private double[] mDoubleStack = null;
private Object[] mReferenceStack = null;
private int mIntTop = 0;
private int mLongTop = 0;
private int mDoubleTop = 0;
private int mFloatTop = 0;
private int mReferenceTop = 0;
ContinuationStack()
{
}
ContinuationStack initialize()
{
mIntStack = new int[10];
mLongStack = new long[5];
mFloatStack = new float[5];
mDoubleStack = new double[5];
mReferenceStack = new Object[5];
mPositionMapping = new int[] {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
mTypeMapping = new int[] {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
return this;
}
public synchronized int getType(int index)
{
if (index <= mTypeMapping.length-1)
{
return mTypeMapping[index];
}
return NONE;
}
public synchronized int popInt()
{
return getInt(--mStackHeight);
}
public synchronized long popLong()
{
return getLong(--mStackHeight);
}
public synchronized float popFloat()
{
return getFloat(--mStackHeight);
}
public synchronized double popDouble()
{
return getDouble(--mStackHeight);
}
public synchronized Object popReference()
{
return getReference(--mStackHeight);
}
public synchronized int getInt(int index)
{
int position = mPositionMapping[index];
if (-1 == position ||
position >= mIntStack.length)
{
return 0;
}
return mIntStack[position];
}
public synchronized long getLong(int index)
{
int position = mPositionMapping[index];
if (-1 == position ||
position >= mLongStack.length)
{
return 0L;
}
return mLongStack[position];
}
public synchronized float getFloat(int index)
{
int position = mPositionMapping[index];
if (-1 == position ||
position >= mFloatStack.length)
{
return 0f;
}
return mFloatStack[position];
}
public synchronized double getDouble(int index)
{
int position = mPositionMapping[index];
if (-1 == position ||
position >= mDoubleStack.length)
{
return 0d;
}
return mDoubleStack[position];
}
public synchronized Object getReference(int index)
{
int position = mPositionMapping[index];
if (-1 == position ||
position >= mReferenceStack.length)
{
return null;
}
return mReferenceStack[position];
}
private synchronized void storeIndex(int index, int position, int type)
{
if (index > mPositionMapping.length-1)
{
int size = (((index+1) /10)+1)*10;
int[] new_positionmapping = new int[size];
int[] new_typemapping = new int[size];
Arrays.fill(new_positionmapping, mPositionMapping.length, new_positionmapping.length, -1);
Arrays.fill(new_typemapping, mTypeMapping.length, new_typemapping.length, -1);
System.arraycopy(mPositionMapping, 0, new_positionmapping, 0, mPositionMapping.length);
System.arraycopy(mTypeMapping, 0, new_typemapping, 0, mTypeMapping.length);
mPositionMapping = new_positionmapping;
mTypeMapping = new_typemapping;
}
mPositionMapping[index] = position;
mTypeMapping[index] = type;
}
public synchronized void incrementInt(int index, int increment)
{
int position = -1;
position = mPositionMapping[index];
mIntStack[position] += increment;
}
public synchronized void pushInt(int value)
{
storeInt(mStackHeight++, value);
}
public synchronized void pushLong(long value)
{
storeLong(mStackHeight++, value);
}
public synchronized void pushFloat(float value)
{
storeFloat(mStackHeight++, value);
}
public synchronized void pushDouble(double value)
{
storeDouble(mStackHeight++, value);
}
public synchronized void pushReference(Object value)
{
storeReference(mStackHeight++, value);
}
public synchronized void storeInt(int index, int value)
{
int position = -1;
if (getType(index) != INTEGER)
{
position = mIntTop++;
storeIndex(index, position, INTEGER);
if (position > mIntStack.length-1)
{
int size = (((position+1) /10)+1)*10;
int[] new_stack = new int[size];
System.arraycopy(mIntStack, 0, new_stack, 0, mIntStack.length);
mIntStack = new_stack;
}
}
else
{
position = mPositionMapping[index];
}
mIntStack[position] = value;
}
public synchronized void storeLong(int index, long value)
{
int position = -1;
if (getType(index) != LONG)
{
position = mLongTop++;
storeIndex(index, position, LONG);
if (position > mLongStack.length-1)
{
int size = (((position+1) /10)+1)*10;
long[] new_stack = new long[size];
System.arraycopy(mLongStack, 0, new_stack, 0, mLongStack.length);
mLongStack = new_stack;
}
}
else
{
position = mPositionMapping[index];
}
mLongStack[position] = value;
}
public synchronized void storeFloat(int index, float value)
{
int position = -1;
if (getType(index) != FLOAT)
{
position = mFloatTop++;
storeIndex(index, position, FLOAT);
if (position > mFloatStack.length-1)
{
int size = (((position+1) /10)+1)*10;
float[] new_stack = new float[size];
System.arraycopy(mFloatStack, 0, new_stack, 0, mFloatStack.length);
mFloatStack = new_stack;
}
}
else
{
position = mPositionMapping[index];
}
mFloatStack[position] = value;
}
public synchronized void storeDouble(int index, double value)
{
int position = -1;
if (getType(index) != DOUBLE)
{
position = mDoubleTop++;
storeIndex(index, position, DOUBLE);
if (position > mDoubleStack.length-1)
{
int size = (((position+1) /10)+1)*10;
double[] new_stack = new double[size];
System.arraycopy(mDoubleStack, 0, new_stack, 0, mDoubleStack.length);
mDoubleStack = new_stack;
}
}
else
{
position = mPositionMapping[index];
}
mDoubleStack[position] = value;
}
public synchronized void storeReference(int index, Object value)
{
int position = -1;
if (getType(index) != REFERENCE)
{
position = mReferenceTop++;
storeIndex(index, position, REFERENCE);
if (position > mReferenceStack.length-1)
{
int size = (((position+1) /10)+1)*10;
Object[] new_stack = new Object[size];
System.arraycopy(mReferenceStack, 0, new_stack, 0, mReferenceStack.length);
mReferenceStack = new_stack;
}
}
else
{
position = mPositionMapping[index];
}
mReferenceStack[position] = value;
}
///CLOVER:OFF
public synchronized void outputState()
{
ContinuationDebug.LOGGER.finest("");
ContinuationDebug.LOGGER.finest("STACK : "+this);
ContinuationDebug.LOGGER.finest("mPositionMapping["+mPositionMapping.length+"] = "+join(mPositionMapping, ","));
ContinuationDebug.LOGGER.finest("mTypeMapping["+mTypeMapping.length+"] = "+join(mTypeMapping, ","));
ContinuationDebug.LOGGER.finest("mIntStack["+mIntStack.length+"] = "+join(mIntStack, ","));
ContinuationDebug.LOGGER.finest("mLongStack["+mLongStack.length+"] = "+join(mLongStack, ","));
ContinuationDebug.LOGGER.finest("mFloatStack["+mFloatStack.length+"] = "+join(mFloatStack, ","));
ContinuationDebug.LOGGER.finest("mDoubleStack["+mDoubleStack.length+"] = "+join(mDoubleStack, ","));
ContinuationDebug.LOGGER.finest("mReferenceStack["+mReferenceStack.length+"] = "+join(mReferenceStack, ","));
}
// adding a join method here to remove a viral dependency on the StringUtils class
private static String join(Object array, String separator)
{
if (null == array)
{
return "";
}
if (!array.getClass().isArray())
{
return String.valueOf(array);
}
StringBuilder result = new StringBuilder();
for (int i = 0; i < Array.getLength(array); i++)
{
if (result.length() > 0)
{
result.append(separator);
}
result.append(Array.get(array, i));
}
return result.toString();
}
///CLOVER:ON
public synchronized ContinuationStack clone(Object elementInstance)
throws CloneNotSupportedException
{
ContinuationStack new_stack = new ContinuationStack();
new_stack.mPositionMapping = mPositionMapping.clone();
new_stack.mTypeMapping = mTypeMapping.clone();
new_stack.mStackHeight = mStackHeight;
new_stack.mIntStack = mIntStack.clone();
new_stack.mLongStack = mLongStack.clone();
new_stack.mFloatStack = mFloatStack.clone();
new_stack.mDoubleStack = mDoubleStack.clone();
new_stack.mReferenceStack = new Object[mReferenceStack.length];
for (int i = 0; i < mReferenceStack.length; i++)
{
if (mReferenceStack[i] != null &&
mReferenceStack[i].getClass() == elementInstance.getClass())
{
new_stack.mReferenceStack[i] = elementInstance;
}
else
{
new_stack.mReferenceStack[i] = ObjectUtils.deepClone(mReferenceStack[i]);
}
}
new_stack.mIntTop = mIntTop;
new_stack.mLongTop = mLongTop;
new_stack.mDoubleTop = mDoubleTop;
new_stack.mFloatTop = mFloatTop;
new_stack.mReferenceTop = mReferenceTop;
return new_stack;
}
}