package com.oracle.truffle.llvm.parser.scanner;
import java.util.Arrays;
import com.oracle.truffle.llvm.runtime.except.LLVMParserException;
import com.oracle.truffle.llvm.runtime.types.Type;
public final class RecordBuffer {
private static final int INITIAL_BUFFER_SIZE = 8;
private long[] opBuffer = new long[INITIAL_BUFFER_SIZE];
private int size = 0;
private int index = 1;
void addOpNoCheck(long op) {
assert size < opBuffer.length;
opBuffer[size++] = op;
}
void addOp(long op) {
ensureFits(1);
addOpNoCheck(op);
}
void ensureFits(long numOfAdditionalOps) {
if (size >= opBuffer.length - numOfAdditionalOps) {
int newLength = opBuffer.length;
while (size >= newLength - numOfAdditionalOps) {
newLength *= 2;
}
opBuffer = Arrays.copyOf(opBuffer, newLength);
}
}
long[] getOps() {
return Arrays.copyOfRange(opBuffer, 1, size);
}
void invalidate() {
size = 0;
index = 1;
}
public long getAt(int pos) {
return opBuffer[pos + 1];
}
public int getId() {
if (size <= 0) {
throw new LLVMParserException("Record Id not set!");
}
long id = opBuffer[0];
if (id != (int) id) {
throw new LLVMParserException("invalid record id " + id);
}
return (int) id;
}
public int size() {
return size - 1;
}
public long read() {
assert index < size;
return opBuffer[index++];
}
public void skip() {
index++;
}
public int readInt() {
long read = read();
return toUnsignedIntExact(read);
}
private static int toUnsignedIntExact(long read) {
if (Type.fitsIntoUnsignedInt(read)) {
return Type.toUnsignedInt(read);
}
throw new ArithmeticException("unsigned integer overflow");
}
public boolean readBoolean() {
return read() != 0;
}
public int remaining() {
return size - index;
}
public void checkEnd(String message) {
if (remaining() > 0) {
throw new LLVMParserException(message);
}
}
public static String describe(long id, long[] args) {
final StringBuilder builder = new StringBuilder();
builder.append("<id=").append(id).append(" - ");
for (int i = 0; i < args.length; i++) {
builder.append("op").append(i).append('=').append(args[i]);
if (i != args.length - 1) {
builder.append(", ");
}
}
builder.append('>');
return builder.toString();
}
public long readSignedValue() {
long v = read();
if ((v & 1L) == 1L) {
v = v >>> 1;
return v == 0 ? Long.MIN_VALUE : -v;
} else {
return v >>> 1;
}
}
public String readString() {
int length = remaining();
StringBuilder string = new StringBuilder(length);
for (int i = 0; i < length; i++) {
string.append((char) opBuffer[index + i]);
}
index += length;
return string.toString();
}
public byte[] readStringAsBytes(boolean cstring) {
int length = remaining();
byte[] result = new byte[length + (cstring ? 1 : 0)];
for (int i = 0; i < length; i++) {
result[i] = (byte) opBuffer[index + i];
}
index += length;
return result;
}
public String readUnicodeString() {
return new String(readStringAsBytes(false));
}
public long[] dumpArray() {
return getOps();
}
}