/*
* Copyright (C) 2013 Omry Yadan <omry@yadan.net>
* All rights reserved.
*
* See https://github.com/omry/banana/blob/master/BSD-LICENSE for licensing information
*/
package net.yadan.banana.memory;
public class Buffer implements IBuffer {
// TODO: Use BlockAllocator as an underlying storage
private int m_buffer[];
private int m_usedSize;
private double m_growthFactor;
public Buffer(int a[], double growthFactor) {
this(a.length, growthFactor);
setInts(0, a, 0, a.length);
}
public Buffer(short a[], double growthFactor) {
this(1 + (a.length - 1) / 2, growthFactor);
int numInts = 1 + (a.length - 1) / 2;
for (int i = 0; i < numInts; i++) {
int elementIndex = i * 2;
setUpperShort(i, a[elementIndex]);
if (a.length < elementIndex + 1) {
setLowerShort(i, a[elementIndex + 1]);
}
}
}
public Buffer(int initialMaxSize) {
this(initialMaxSize, 2);
}
public Buffer(int initialMaxSize, double growthFactor) {
m_growthFactor = growthFactor;
m_buffer = new int[initialMaxSize];
m_usedSize = 0;
}
@Override
public double getGrowthFactor() {
return m_growthFactor;
}
@Override
public void setGrowthFactor(double growthFactor) {
m_growthFactor = growthFactor;
}
@Override
public int size() {
return m_usedSize;
}
@Override
public void reset() {
m_usedSize = 0;
}
@Override
public void ensureCapacity(int numInts) {
int capacity = capacity();
if (capacity < numInts) {
if (m_growthFactor == 0) {
throw new OutOfMemoryException("Buffer is configured to not grow (growthFactor = 0)");
}
int newSize = Math.max(numInts, (int) (capacity * m_growthFactor));
int newBuf[] = new int[newSize];
System.arraycopy(m_buffer, 0, newBuf, 0, m_buffer.length);
m_buffer = newBuf;
}
}
@Override
public int capacity() {
return m_buffer.length;
}
@Override
public short getUpperShort(int offset) {
return (short) (m_buffer[offset] >>> 16);
}
@Override
public short getLowerShort(int offset) {
return (short) (m_buffer[offset]);
}
@Override
public void setUpperShort(int offset, int v) {
int newSize = Math.max(m_usedSize, offset + 1);
int lower = newSize > m_usedSize ? 0 : m_buffer[offset] & 0x0000ffff;
m_buffer[offset] = (v << 16) | lower;
m_usedSize = newSize;
}
@Override
public void setLowerShort(int offset, int v) {
int newSize = Math.max(m_usedSize, offset + 1);
int upper = newSize > m_usedSize ? 0 : m_buffer[offset] & 0xffff0000;
m_buffer[offset] = upper | (v & 0x0000ffff);
m_usedSize = newSize;
}
@Override
public int getInt(int offset) {
return m_buffer[offset];
}
@Override
public void setInt(int offset, int v) {
m_buffer[offset] = v;
m_usedSize = Math.max(m_usedSize, offset + 1);
}
@Override
public long getLong(int offset) {
int ilower = m_buffer[offset + 1];
int iupper = m_buffer[offset + 0];
long lower = 0x00000000FFFFFFFFL & ilower;
long upper = ((long) iupper) << 32;
long ret = upper | lower;
return ret;
}
@Override
public void setLong(int offset, long v) {
m_buffer[offset + 0] = (int) (v >> 32);
m_buffer[offset + 1] = (int) (v);
m_usedSize = Math.max(m_usedSize, offset + 2);
}
@Override
public void setInts(int dst_offset, int[] src_data, int src_pos, int length) {
System.arraycopy(src_data, src_pos, m_buffer, dst_offset, length);
m_usedSize = Math.max(m_usedSize, dst_offset + length);
}
@Override
public void getInts(int src_offset, int[] dst_data, int dst_pos, int length) {
System.arraycopy(m_buffer, src_offset, dst_data, dst_pos, length);
}
@Override
public void appendInt(int v) {
setInt(m_usedSize, v);
}
@Override
public void appendLong(long v) {
setLong(m_usedSize, v);
}
@Override
public void appendInts(int[] src_data) {
appendInts(src_data, 0, src_data.length);
}
@Override
public void appendInts(int[] src_data, int src_pos, int length) {
setInts(m_usedSize, src_data, src_pos, length);
}
@Override
public int hashCode() {
int h = 1;
for (int i = 0; i < size(); i++) {
h = 31 * h + m_buffer[i];
}
return h;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof IBuffer) {
IBuffer buff = (IBuffer) obj;
if (buff.size() == size()) {
for (int i = 0; i < size(); i++) {
if (m_buffer[i] != buff.array()[i])
return false;
}
return true;
} else {
return false;
}
} else {
return false;
}
}
@Override
public boolean equals(IMemAllocator mem, int pointer, int start_offset, int length) {
if (length != size()) {
return false;
}
for (int i = start_offset; i < start_offset + length; i++) {
int v1 = mem.getInt(pointer, i);
int v2 = getInt(i - start_offset);
if (v1 != v2) {
return false;
}
}
return true;
}
@Override
public int[] array() {
return m_buffer;
}
@Override
public void setChars(int dst_offset, char[] src_data) {
setChars(dst_offset, src_data, 0, src_data.length);
}
@Override
public void setChars(int dst_offset, char[] src_data, int src_pos, int length) {
if (length == 0) {
return;
}
int numInts = 1 + (length - 1) / 2;
for (int i = 0; i < numInts; i++) {
int elementIndex = i * 2;
setUpperShort(dst_offset + i, src_data[src_pos + elementIndex]);
if (elementIndex + 1 < length) {
setLowerShort(dst_offset + i, src_data[src_pos + elementIndex + 1]);
}
}
m_usedSize = Math.max(m_usedSize, dst_offset + numInts);
}
@Override
public void getChars(int src_offset, char[] dst_data, int dst_pos, int length) {
if (length == 0) {
return;
}
int numInts = 1 + (length - 1) / 2;
for (int i = 0; i < numInts; i++) {
int elementIndex = i * 2;
dst_data[dst_pos + elementIndex] = (char) getUpperShort(src_offset + i);
if (elementIndex + 1 < length) {
dst_data[dst_pos + elementIndex + 1] = (char) getLowerShort(src_offset + i);
}
}
}
@Override
public void appendChars(char[] src_data) {
appendChars(src_data, 0, src_data.length);
}
@Override
public void appendChars(char[] src_data, int src_pos, int length) {
setChars(m_usedSize, src_data, src_pos, length);
}
@Override
public void setUsed(int used) {
assert used <= capacity();
m_usedSize = used;
}
@Override
public String toString() {
return "Buffer " + m_usedSize + " / " + capacity() + " used";
}
}