org.agrona.ExpandableArrayBuffer Maven / Gradle / Ivy
Show all versions of agrona Show documentation
/*
* Copyright 2014-2021 Real Logic Limited.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.agrona;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;
import static java.nio.charset.StandardCharsets.US_ASCII;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.agrona.BitUtil.*;
import static org.agrona.UnsafeAccess.UNSAFE;
import static org.agrona.BufferUtil.*;
import static org.agrona.AsciiEncoding.*;
/**
* Expandable {@link MutableDirectBuffer} that is backed by an array. When values are put into the buffer beyond its
* current length, then it will be expanded to accommodate the resulting position for the value.
*
* Put operations will expand the capacity as necessary up to {@link #MAX_ARRAY_LENGTH}. Get operations will throw
* a {@link IndexOutOfBoundsException} if past current capacity.
*
* Note: this class has a natural ordering that is inconsistent with equals.
* Types may be different but equal on buffer contents.
*/
public class ExpandableArrayBuffer implements MutableDirectBuffer
{
/**
* Maximum length to which the underlying buffer can grow. Some JVMs store state in the last few bytes.
*/
public static final int MAX_ARRAY_LENGTH = Integer.MAX_VALUE - 8;
/**
* Initial capacity of the buffer from which it will expand as necessary.
*/
public static final int INITIAL_CAPACITY = 128;
private byte[] byteArray;
/**
* Create an {@link ExpandableArrayBuffer} with an initial length of {@link #INITIAL_CAPACITY}.
*/
public ExpandableArrayBuffer()
{
this(INITIAL_CAPACITY);
}
/**
* Create an {@link ExpandableArrayBuffer} with a provided initial length.
*
* @param initialCapacity of the buffer.
*/
public ExpandableArrayBuffer(final int initialCapacity)
{
byteArray = new byte[initialCapacity];
}
/**
* {@inheritDoc}
*/
public void wrap(final byte[] buffer)
{
throw new UnsupportedOperationException();
}
/**
* {@inheritDoc}
*/
public void wrap(final byte[] buffer, final int offset, final int length)
{
throw new UnsupportedOperationException();
}
/**
* {@inheritDoc}
*/
public void wrap(final ByteBuffer buffer)
{
throw new UnsupportedOperationException();
}
/**
* {@inheritDoc}
*/
public void wrap(final ByteBuffer buffer, final int offset, final int length)
{
throw new UnsupportedOperationException();
}
/**
* {@inheritDoc}
*/
public void wrap(final DirectBuffer buffer)
{
throw new UnsupportedOperationException();
}
/**
* {@inheritDoc}
*/
public void wrap(final DirectBuffer buffer, final int offset, final int length)
{
throw new UnsupportedOperationException();
}
/**
* {@inheritDoc}
*/
public void wrap(final long address, final int length)
{
throw new UnsupportedOperationException();
}
/**
* {@inheritDoc}
*/
public long addressOffset()
{
return ARRAY_BASE_OFFSET;
}
/**
* {@inheritDoc}
*/
public byte[] byteArray()
{
return byteArray;
}
/**
* {@inheritDoc}
*/
public ByteBuffer byteBuffer()
{
return null;
}
/**
* {@inheritDoc}
*/
public void setMemory(final int index, final int length, final byte value)
{
ensureCapacity(index, length);
Arrays.fill(byteArray, index, index + length, value);
}
/**
* {@inheritDoc}
*/
public int capacity()
{
return byteArray.length;
}
/**
* {@inheritDoc}
*/
public boolean isExpandable()
{
return true;
}
/**
* {@inheritDoc}
*/
public void checkLimit(final int limit)
{
ensureCapacity(limit, SIZE_OF_BYTE);
}
///////////////////////////////////////////////////////////////////////////
/**
* {@inheritDoc}
*/
public long getLong(final int index, final ByteOrder byteOrder)
{
boundsCheck0(index, SIZE_OF_LONG);
long bits = UNSAFE.getLong(byteArray, ARRAY_BASE_OFFSET + index);
if (NATIVE_BYTE_ORDER != byteOrder)
{
bits = Long.reverseBytes(bits);
}
return bits;
}
/**
* {@inheritDoc}
*/
public void putLong(final int index, final long value, final ByteOrder byteOrder)
{
ensureCapacity(index, SIZE_OF_LONG);
long bits = value;
if (NATIVE_BYTE_ORDER != byteOrder)
{
bits = Long.reverseBytes(bits);
}
UNSAFE.putLong(byteArray, ARRAY_BASE_OFFSET + index, bits);
}
/**
* {@inheritDoc}
*/
public long getLong(final int index)
{
boundsCheck0(index, SIZE_OF_LONG);
return UNSAFE.getLong(byteArray, ARRAY_BASE_OFFSET + index);
}
/**
* {@inheritDoc}
*/
public void putLong(final int index, final long value)
{
ensureCapacity(index, SIZE_OF_LONG);
UNSAFE.putLong(byteArray, ARRAY_BASE_OFFSET + index, value);
}
///////////////////////////////////////////////////////////////////////////
/**
* {@inheritDoc}
*/
public int getInt(final int index, final ByteOrder byteOrder)
{
boundsCheck0(index, SIZE_OF_INT);
int bits = UNSAFE.getInt(byteArray, ARRAY_BASE_OFFSET + index);
if (NATIVE_BYTE_ORDER != byteOrder)
{
bits = Integer.reverseBytes(bits);
}
return bits;
}
/**
* {@inheritDoc}
*/
public void putInt(final int index, final int value, final ByteOrder byteOrder)
{
ensureCapacity(index, SIZE_OF_INT);
int bits = value;
if (NATIVE_BYTE_ORDER != byteOrder)
{
bits = Integer.reverseBytes(bits);
}
UNSAFE.putInt(byteArray, ARRAY_BASE_OFFSET + index, bits);
}
/**
* {@inheritDoc}
*/
public int getInt(final int index)
{
boundsCheck0(index, SIZE_OF_INT);
return UNSAFE.getInt(byteArray, ARRAY_BASE_OFFSET + index);
}
/**
* {@inheritDoc}
*/
public void putInt(final int index, final int value)
{
ensureCapacity(index, SIZE_OF_INT);
UNSAFE.putInt(byteArray, ARRAY_BASE_OFFSET + index, value);
}
///////////////////////////////////////////////////////////////////////////
/**
* {@inheritDoc}
*/
public double getDouble(final int index, final ByteOrder byteOrder)
{
boundsCheck0(index, SIZE_OF_DOUBLE);
if (NATIVE_BYTE_ORDER != byteOrder)
{
final long bits = UNSAFE.getLong(byteArray, ARRAY_BASE_OFFSET + index);
return Double.longBitsToDouble(Long.reverseBytes(bits));
}
else
{
return UNSAFE.getDouble(byteArray, ARRAY_BASE_OFFSET + index);
}
}
/**
* {@inheritDoc}
*/
public void putDouble(final int index, final double value, final ByteOrder byteOrder)
{
ensureCapacity(index, SIZE_OF_DOUBLE);
if (NATIVE_BYTE_ORDER != byteOrder)
{
final long bits = Long.reverseBytes(Double.doubleToRawLongBits(value));
UNSAFE.putLong(byteArray, ARRAY_BASE_OFFSET + index, bits);
}
else
{
UNSAFE.putDouble(byteArray, ARRAY_BASE_OFFSET + index, value);
}
}
/**
* {@inheritDoc}
*/
public double getDouble(final int index)
{
boundsCheck0(index, SIZE_OF_DOUBLE);
return UNSAFE.getDouble(byteArray, ARRAY_BASE_OFFSET + index);
}
/**
* {@inheritDoc}
*/
public void putDouble(final int index, final double value)
{
ensureCapacity(index, SIZE_OF_DOUBLE);
UNSAFE.putDouble(byteArray, ARRAY_BASE_OFFSET + index, value);
}
///////////////////////////////////////////////////////////////////////////
/**
* {@inheritDoc}
*/
public float getFloat(final int index, final ByteOrder byteOrder)
{
boundsCheck0(index, SIZE_OF_FLOAT);
if (NATIVE_BYTE_ORDER != byteOrder)
{
final int bits = UNSAFE.getInt(byteArray, ARRAY_BASE_OFFSET + index);
return Float.intBitsToFloat(Integer.reverseBytes(bits));
}
else
{
return UNSAFE.getFloat(byteArray, ARRAY_BASE_OFFSET + index);
}
}
/**
* {@inheritDoc}
*/
public void putFloat(final int index, final float value, final ByteOrder byteOrder)
{
ensureCapacity(index, SIZE_OF_FLOAT);
if (NATIVE_BYTE_ORDER != byteOrder)
{
final int bits = Integer.reverseBytes(Float.floatToRawIntBits(value));
UNSAFE.putInt(byteArray, ARRAY_BASE_OFFSET + index, bits);
}
else
{
UNSAFE.putFloat(byteArray, ARRAY_BASE_OFFSET + index, value);
}
}
/**
* {@inheritDoc}
*/
public float getFloat(final int index)
{
boundsCheck0(index, SIZE_OF_FLOAT);
return UNSAFE.getFloat(byteArray, ARRAY_BASE_OFFSET + index);
}
/**
* {@inheritDoc}
*/
public void putFloat(final int index, final float value)
{
ensureCapacity(index, SIZE_OF_FLOAT);
UNSAFE.putFloat(byteArray, ARRAY_BASE_OFFSET + index, value);
}
///////////////////////////////////////////////////////////////////////////
/**
* {@inheritDoc}
*/
public short getShort(final int index, final ByteOrder byteOrder)
{
boundsCheck0(index, SIZE_OF_SHORT);
short bits = UNSAFE.getShort(byteArray, ARRAY_BASE_OFFSET + index);
if (NATIVE_BYTE_ORDER != byteOrder)
{
bits = Short.reverseBytes(bits);
}
return bits;
}
/**
* {@inheritDoc}
*/
public void putShort(final int index, final short value, final ByteOrder byteOrder)
{
ensureCapacity(index, SIZE_OF_SHORT);
short bits = value;
if (NATIVE_BYTE_ORDER != byteOrder)
{
bits = Short.reverseBytes(bits);
}
UNSAFE.putShort(byteArray, ARRAY_BASE_OFFSET + index, bits);
}
/**
* {@inheritDoc}
*/
public short getShort(final int index)
{
boundsCheck0(index, SIZE_OF_SHORT);
return UNSAFE.getShort(byteArray, ARRAY_BASE_OFFSET + index);
}
/**
* {@inheritDoc}
*/
public void putShort(final int index, final short value)
{
ensureCapacity(index, SIZE_OF_SHORT);
UNSAFE.putShort(byteArray, ARRAY_BASE_OFFSET + index, value);
}
///////////////////////////////////////////////////////////////////////////
/**
* {@inheritDoc}
*/
public byte getByte(final int index)
{
return byteArray[index];
}
/**
* {@inheritDoc}
*/
public void putByte(final int index, final byte value)
{
ensureCapacity(index, SIZE_OF_BYTE);
byteArray[index] = value;
}
private void putByte0(final int index, final byte value)
{
ensureCapacity(index, SIZE_OF_BYTE);
byteArray[index] = value;
}
/**
* {@inheritDoc}
*/
public void getBytes(final int index, final byte[] dst)
{
getBytes(index, dst, 0, dst.length);
}
/**
* {@inheritDoc}
*/
public void getBytes(final int index, final byte[] dst, final int offset, final int length)
{
System.arraycopy(byteArray, index, dst, offset, length);
}
/**
* {@inheritDoc}
*/
public void getBytes(final int index, final MutableDirectBuffer dstBuffer, final int dstIndex, final int length)
{
dstBuffer.putBytes(dstIndex, this, index, length);
}
/**
* {@inheritDoc}
*/
public void getBytes(final int index, final ByteBuffer dstBuffer, final int length)
{
final int dstOffset = dstBuffer.position();
getBytes(index, dstBuffer, dstOffset, length);
dstBuffer.position(dstOffset + length);
}
/**
* {@inheritDoc}
*/
public void getBytes(final int index, final ByteBuffer dstBuffer, final int dstOffset, final int length)
{
boundsCheck0(index, length);
BufferUtil.boundsCheck(dstBuffer, dstOffset, length);
final byte[] dstByteArray;
final long dstBaseOffset;
if (dstBuffer.isDirect())
{
dstByteArray = null;
dstBaseOffset = address(dstBuffer);
}
else
{
dstByteArray = array(dstBuffer);
dstBaseOffset = ARRAY_BASE_OFFSET + arrayOffset(dstBuffer);
}
UNSAFE.copyMemory(byteArray, ARRAY_BASE_OFFSET + index, dstByteArray, dstBaseOffset + dstOffset, length);
}
/**
* {@inheritDoc}
*/
public void putBytes(final int index, final byte[] src)
{
putBytes(index, src, 0, src.length);
}
/**
* {@inheritDoc}
*/
public void putBytes(final int index, final byte[] src, final int offset, final int length)
{
ensureCapacity(index, length);
System.arraycopy(src, offset, byteArray, index, length);
}
/**
* {@inheritDoc}
*/
public void putBytes(final int index, final ByteBuffer srcBuffer, final int length)
{
final int srcIndex = srcBuffer.position();
putBytes(index, srcBuffer, srcIndex, length);
srcBuffer.position(srcIndex + length);
}
/**
* {@inheritDoc}
*/
public void putBytes(final int index, final ByteBuffer srcBuffer, final int srcIndex, final int length)
{
ensureCapacity(index, length);
BufferUtil.boundsCheck(srcBuffer, srcIndex, length);
final byte[] srcByteArray;
final long srcBaseOffset;
if (srcBuffer.isDirect())
{
srcByteArray = null;
srcBaseOffset = address(srcBuffer);
}
else
{
srcByteArray = array(srcBuffer);
srcBaseOffset = ARRAY_BASE_OFFSET + arrayOffset(srcBuffer);
}
UNSAFE.copyMemory(srcByteArray, srcBaseOffset + srcIndex, byteArray, ARRAY_BASE_OFFSET + index, length);
}
/**
* {@inheritDoc}
*/
public void putBytes(final int index, final DirectBuffer srcBuffer, final int srcIndex, final int length)
{
ensureCapacity(index, length);
srcBuffer.boundsCheck(srcIndex, length);
UNSAFE.copyMemory(
srcBuffer.byteArray(),
srcBuffer.addressOffset() + srcIndex,
byteArray,
ARRAY_BASE_OFFSET + index,
length);
}
///////////////////////////////////////////////////////////////////////////
/**
* {@inheritDoc}
*/
public char getChar(final int index, final ByteOrder byteOrder)
{
boundsCheck0(index, SIZE_OF_SHORT);
char bits = UNSAFE.getChar(byteArray, ARRAY_BASE_OFFSET + index);
if (NATIVE_BYTE_ORDER != byteOrder)
{
bits = (char)Short.reverseBytes((short)bits);
}
return bits;
}
/**
* {@inheritDoc}
*/
public void putChar(final int index, final char value, final ByteOrder byteOrder)
{
ensureCapacity(index, SIZE_OF_CHAR);
char bits = value;
if (NATIVE_BYTE_ORDER != byteOrder)
{
bits = (char)Short.reverseBytes((short)bits);
}
UNSAFE.putChar(byteArray, ARRAY_BASE_OFFSET + index, bits);
}
/**
* {@inheritDoc}
*/
public char getChar(final int index)
{
boundsCheck0(index, SIZE_OF_CHAR);
return UNSAFE.getChar(byteArray, ARRAY_BASE_OFFSET + index);
}
/**
* {@inheritDoc}
*/
public void putChar(final int index, final char value)
{
ensureCapacity(index, SIZE_OF_CHAR);
UNSAFE.putChar(byteArray, ARRAY_BASE_OFFSET + index, value);
}
///////////////////////////////////////////////////////////////////////////
/**
* {@inheritDoc}
*/
public String getStringAscii(final int index)
{
boundsCheck0(index, STR_HEADER_LEN);
final int length = UNSAFE.getInt(byteArray, ARRAY_BASE_OFFSET + index);
return getStringAscii(index, length);
}
/**
* {@inheritDoc}
*/
public int getStringAscii(final int index, final Appendable appendable)
{
boundsCheck0(index, STR_HEADER_LEN);
final int length = UNSAFE.getInt(byteArray, ARRAY_BASE_OFFSET + index);
return getStringAscii(index, length, appendable);
}
/**
* {@inheritDoc}
*/
public String getStringAscii(final int index, final ByteOrder byteOrder)
{
boundsCheck0(index, STR_HEADER_LEN);
int bits = UNSAFE.getInt(byteArray, ARRAY_BASE_OFFSET + index);
if (NATIVE_BYTE_ORDER != byteOrder)
{
bits = Integer.reverseBytes(bits);
}
final int length = bits;
return getStringAscii(index, length);
}
/**
* {@inheritDoc}
*/
public int getStringAscii(final int index, final Appendable appendable, final ByteOrder byteOrder)
{
boundsCheck0(index, STR_HEADER_LEN);
int bits = UNSAFE.getInt(byteArray, ARRAY_BASE_OFFSET + index);
if (NATIVE_BYTE_ORDER != byteOrder)
{
bits = Integer.reverseBytes(bits);
}
final int length = bits;
return getStringAscii(index, length, appendable);
}
/**
* {@inheritDoc}
*/
public String getStringAscii(final int index, final int length)
{
final byte[] stringInBytes = new byte[length];
System.arraycopy(byteArray, index + STR_HEADER_LEN, stringInBytes, 0, length);
return new String(stringInBytes, US_ASCII);
}
/**
* {@inheritDoc}
*/
public int getStringAscii(final int index, final int length, final Appendable appendable)
{
try
{
for (int i = index + STR_HEADER_LEN, limit = index + STR_HEADER_LEN + length; i < limit; i++)
{
final char c = (char)(byteArray[i]);
appendable.append(c > 127 ? '?' : c);
}
}
catch (final IOException ex)
{
LangUtil.rethrowUnchecked(ex);
}
return length;
}
/**
* {@inheritDoc}
*/
public int putStringAscii(final int index, final String value)
{
final int length = value != null ? value.length() : 0;
ensureCapacity(index, length + STR_HEADER_LEN);
UNSAFE.putInt(byteArray, ARRAY_BASE_OFFSET + index, length);
for (int i = 0; i < length; i++)
{
char c = value.charAt(i);
if (c > 127)
{
c = '?';
}
UNSAFE.putByte(byteArray, ARRAY_BASE_OFFSET + STR_HEADER_LEN + index + i, (byte)c);
}
return STR_HEADER_LEN + length;
}
/**
* {@inheritDoc}
*/
public int putStringAscii(final int index, final String value, final ByteOrder byteOrder)
{
final int length = value != null ? value.length() : 0;
ensureCapacity(index, length + STR_HEADER_LEN);
int bits = length;
if (NATIVE_BYTE_ORDER != byteOrder)
{
bits = Integer.reverseBytes(bits);
}
UNSAFE.putInt(byteArray, ARRAY_BASE_OFFSET + index, bits);
for (int i = 0; i < length; i++)
{
char c = value.charAt(i);
if (c > 127)
{
c = '?';
}
UNSAFE.putByte(byteArray, ARRAY_BASE_OFFSET + STR_HEADER_LEN + index + i, (byte)c);
}
return STR_HEADER_LEN + length;
}
/**
* {@inheritDoc}
*/
public String getStringWithoutLengthAscii(final int index, final int length)
{
final byte[] stringInBytes = new byte[length];
System.arraycopy(byteArray, index, stringInBytes, 0, length);
return new String(stringInBytes, US_ASCII);
}
/**
* {@inheritDoc}
*/
public int getStringWithoutLengthAscii(final int index, final int length, final Appendable appendable)
{
try
{
for (int i = index, limit = index + length; i < limit; i++)
{
final char c = (char)(byteArray[i]);
appendable.append(c > 127 ? '?' : c);
}
}
catch (final IOException ex)
{
LangUtil.rethrowUnchecked(ex);
}
return length;
}
/**
* {@inheritDoc}
*/
public int putStringWithoutLengthAscii(final int index, final String value)
{
final int length = value != null ? value.length() : 0;
ensureCapacity(index, length);
for (int i = 0; i < length; i++)
{
char c = value.charAt(i);
if (c > 127)
{
c = '?';
}
UNSAFE.putByte(byteArray, ARRAY_BASE_OFFSET + index + i, (byte)c);
}
return length;
}
/**
* {@inheritDoc}
*/
public int putStringWithoutLengthAscii(final int index, final String value, final int valueOffset, final int length)
{
final int len = value != null ? Math.min(value.length() - valueOffset, length) : 0;
ensureCapacity(index, len);
for (int i = 0; i < len; i++)
{
char c = value.charAt(valueOffset + i);
if (c > 127)
{
c = '?';
}
UNSAFE.putByte(byteArray, ARRAY_BASE_OFFSET + index + i, (byte)c);
}
return len;
}
/**
* {@inheritDoc}
*/
public String getStringUtf8(final int index)
{
boundsCheck0(index, STR_HEADER_LEN);
final int length = UNSAFE.getInt(byteArray, ARRAY_BASE_OFFSET + index);
return getStringUtf8(index, length);
}
/**
* {@inheritDoc}
*/
public String getStringUtf8(final int index, final ByteOrder byteOrder)
{
boundsCheck0(index, STR_HEADER_LEN);
int bits = UNSAFE.getInt(byteArray, ARRAY_BASE_OFFSET + index);
if (NATIVE_BYTE_ORDER != byteOrder)
{
bits = Integer.reverseBytes(bits);
}
final int length = bits;
return getStringUtf8(index, length);
}
/**
* {@inheritDoc}
*/
public String getStringUtf8(final int index, final int length)
{
final byte[] stringInBytes = new byte[length];
System.arraycopy(byteArray, index + STR_HEADER_LEN, stringInBytes, 0, length);
return new String(stringInBytes, UTF_8);
}
/**
* {@inheritDoc}
*/
public int putStringUtf8(final int index, final String value)
{
return putStringUtf8(index, value, Integer.MAX_VALUE);
}
/**
* {@inheritDoc}
*/
public int putStringUtf8(final int index, final String value, final ByteOrder byteOrder)
{
return putStringUtf8(index, value, byteOrder, Integer.MAX_VALUE);
}
/**
* {@inheritDoc}
*/
public int putStringUtf8(final int index, final String value, final int maxEncodedLength)
{
final byte[] bytes = value != null ? value.getBytes(UTF_8) : NULL_BYTES;
if (bytes.length > maxEncodedLength)
{
throw new IllegalArgumentException("Encoded string larger than maximum size: " + maxEncodedLength);
}
ensureCapacity(index, STR_HEADER_LEN + bytes.length);
UNSAFE.putInt(byteArray, ARRAY_BASE_OFFSET + index, bytes.length);
System.arraycopy(bytes, 0, byteArray, index + STR_HEADER_LEN, bytes.length);
return STR_HEADER_LEN + bytes.length;
}
/**
* {@inheritDoc}
*/
public int putStringUtf8(final int index, final String value, final ByteOrder byteOrder, final int maxEncodedLength)
{
final byte[] bytes = value != null ? value.getBytes(UTF_8) : NULL_BYTES;
if (bytes.length > maxEncodedLength)
{
throw new IllegalArgumentException("Encoded string larger than maximum size: " + maxEncodedLength);
}
ensureCapacity(index, STR_HEADER_LEN + bytes.length);
int bits = bytes.length;
if (NATIVE_BYTE_ORDER != byteOrder)
{
bits = Integer.reverseBytes(bits);
}
UNSAFE.putInt(byteArray, ARRAY_BASE_OFFSET + index, bits);
System.arraycopy(bytes, 0, byteArray, index + STR_HEADER_LEN, bytes.length);
return STR_HEADER_LEN + bytes.length;
}
/**
* {@inheritDoc}
*/
public String getStringWithoutLengthUtf8(final int index, final int length)
{
final byte[] stringInBytes = new byte[length];
System.arraycopy(byteArray, index, stringInBytes, 0, length);
return new String(stringInBytes, UTF_8);
}
/**
* {@inheritDoc}
*/
public int putStringWithoutLengthUtf8(final int index, final String value)
{
final byte[] bytes = value != null ? value.getBytes(UTF_8) : NULL_BYTES;
ensureCapacity(index, bytes.length);
System.arraycopy(bytes, 0, byteArray, index, bytes.length);
return bytes.length;
}
///////////////////////////////////////////////////////////////////////////
/**
* {@inheritDoc}
*/
public int parseNaturalIntAscii(final int index, final int length)
{
boundsCheck0(index, length);
if (length <= 0)
{
throw new AsciiNumberFormatException("empty string: index=" + index + " length=" + length);
}
final int end = index + length;
int tally = 0;
for (int i = index; i < end; i++)
{
tally = (tally * 10) + AsciiEncoding.getDigit(i, byteArray[i]);
}
return tally;
}
/**
* {@inheritDoc}
*/
public long parseNaturalLongAscii(final int index, final int length)
{
boundsCheck0(index, length);
if (length <= 0)
{
throw new AsciiNumberFormatException("empty string: index=" + index + " length=" + length);
}
final int end = index + length;
long tally = 0;
for (int i = index; i < end; i++)
{
tally = (tally * 10) + AsciiEncoding.getDigit(i, byteArray[i]);
}
return tally;
}
/**
* {@inheritDoc}
*/
public int parseIntAscii(final int index, final int length)
{
boundsCheck0(index, length);
if (length <= 0)
{
throw new AsciiNumberFormatException("empty string: index=" + index + " length=" + length);
}
else if (1 == length)
{
return AsciiEncoding.getDigit(index, byteArray[index]);
}
final int endExclusive = index + length;
final int first = byteArray[index];
int i = index;
if (first == MINUS_SIGN)
{
i++;
}
int tally = 0;
for (; i < endExclusive; i++)
{
tally = (tally * 10) + AsciiEncoding.getDigit(i, byteArray[i]);
}
if (first == MINUS_SIGN)
{
tally = -tally;
}
return tally;
}
/**
* {@inheritDoc}
*/
public long parseLongAscii(final int index, final int length)
{
boundsCheck0(index, length);
if (length <= 0)
{
throw new AsciiNumberFormatException("empty string: index=" + index + " length=" + length);
}
else if (1 == length)
{
return AsciiEncoding.getDigit(index, byteArray[index]);
}
final int endExclusive = index + length;
final int first = byteArray[index];
int i = index;
if (first == MINUS_SIGN)
{
i++;
}
long tally = 0;
for (; i < endExclusive; i++)
{
tally = (tally * 10) + AsciiEncoding.getDigit(i, byteArray[i]);
}
if (first == MINUS_SIGN)
{
tally = -tally;
}
return tally;
}
/**
* {@inheritDoc}
*/
public int putIntAscii(final int index, final int value)
{
if (value == 0)
{
putByte0(index, ZERO);
return 1;
}
if (value == Integer.MIN_VALUE)
{
putBytes(index, MIN_INTEGER_VALUE);
return MIN_INTEGER_VALUE.length;
}
int start = index;
int quotient = value;
int length = 1;
if (value < 0)
{
putByte0(index, MINUS_SIGN);
start++;
length++;
quotient = -quotient;
}
int i = endOffset(quotient);
length += i;
ensureCapacity(index, length);
while (i >= 0)
{
final int remainder = quotient % 10;
quotient = quotient / 10;
byteArray[i + start] = (byte)(ZERO + remainder);
i--;
}
return length;
}
/**
* {@inheritDoc}
*/
public int putNaturalIntAscii(final int index, final int value)
{
if (value == 0)
{
putByte0(index, ZERO);
return 1;
}
int i = endOffset(value);
final int length = i + 1;
ensureCapacity(index, length);
int quotient = value;
while (i >= 0)
{
final int remainder = quotient % 10;
quotient = quotient / 10;
byteArray[i + index] = (byte)(ZERO + remainder);
i--;
}
return length;
}
/**
* {@inheritDoc}
*/
public void putNaturalPaddedIntAscii(final int offset, final int length, final int value)
{
final int end = offset + length;
int remainder = value;
for (int index = end - 1; index >= offset; index--)
{
final int digit = remainder % 10;
remainder = remainder / 10;
putByte0(index, (byte)(ZERO + digit));
}
if (remainder != 0)
{
throw new NumberFormatException("Cannot write " + value + " in " + length + " bytes");
}
}
/**
* {@inheritDoc}
*/
public int putNaturalIntAsciiFromEnd(final int value, final int endExclusive)
{
int remainder = value;
int index = endExclusive;
while (remainder > 0)
{
index--;
final int digit = remainder % 10;
remainder = remainder / 10;
putByte0(index, (byte)(ZERO + digit));
}
return index;
}
/**
* {@inheritDoc}
*/
public int putNaturalLongAscii(final int index, final long value)
{
if (value == 0)
{
putByte0(index, ZERO);
return 1;
}
int i = endOffset(value);
final int length = i + 1;
ensureCapacity(index, length);
long quotient = value;
while (i >= 0)
{
final long remainder = quotient % 10;
quotient = quotient / 10;
byteArray[i + index] = (byte)(ZERO + remainder);
i--;
}
return length;
}
/**
* {@inheritDoc}
*/
public int putLongAscii(final int index, final long value)
{
if (value == 0)
{
putByte0(index, ZERO);
return 1;
}
if (value == Long.MIN_VALUE)
{
putBytes(index, MIN_LONG_VALUE);
return MIN_LONG_VALUE.length;
}
int start = index;
long quotient = value;
int length = 1;
if (value < 0)
{
putByte0(index, MINUS_SIGN);
start++;
length++;
quotient = -quotient;
}
int i = endOffset(quotient);
length += i;
ensureCapacity(index, length);
while (i >= 0)
{
final long remainder = quotient % 10L;
quotient = quotient / 10L;
byteArray[i + start] = (byte)(ZERO + remainder);
i--;
}
return length;
}
///////////////////////////////////////////////////////////////////////////
private void ensureCapacity(final int index, final int length)
{
if (index < 0 || length < 0)
{
throw new IndexOutOfBoundsException("negative value: index=" + index + " length=" + length);
}
final long resultingPosition = index + (long)length;
final int currentArrayLength = byteArray.length;
if (resultingPosition > currentArrayLength)
{
if (resultingPosition > MAX_ARRAY_LENGTH)
{
throw new IndexOutOfBoundsException(
"index=" + index + " length=" + length + " maxCapacity=" + MAX_ARRAY_LENGTH);
}
byteArray = Arrays.copyOf(byteArray, calculateExpansion(currentArrayLength, resultingPosition));
}
}
private int calculateExpansion(final int currentLength, final long requiredLength)
{
long value = Math.max(currentLength, INITIAL_CAPACITY);
while (value < requiredLength)
{
value = value + (value >> 1);
if (value > MAX_ARRAY_LENGTH)
{
value = MAX_ARRAY_LENGTH;
}
}
return (int)value;
}
private void boundsCheck0(final int index, final int length)
{
final int currentArrayLength = byteArray.length;
final long resultingPosition = index + (long)length;
if (index < 0 || length < 0 || resultingPosition > currentArrayLength)
{
throw new IndexOutOfBoundsException(
"index=" + index + " length=" + length + " capacity=" + currentArrayLength);
}
}
/**
* {@inheritDoc}
*/
public void boundsCheck(final int index, final int length)
{
boundsCheck0(index, length);
}
/**
* {@inheritDoc}
*/
public int wrapAdjustment()
{
return 0;
}
///////////////////////////////////////////////////////////////////////////
/**
* {@inheritDoc}
*/
public boolean equals(final Object obj)
{
if (this == obj)
{
return true;
}
if (obj == null || getClass() != obj.getClass())
{
return false;
}
final ExpandableArrayBuffer that = (ExpandableArrayBuffer)obj;
return Arrays.equals(this.byteArray, that.byteArray);
}
/**
* {@inheritDoc}
*/
public int hashCode()
{
return Arrays.hashCode(byteArray);
}
/**
* {@inheritDoc}
*/
public int compareTo(final DirectBuffer that)
{
final int thisCapacity = this.capacity();
final int thatCapacity = that.capacity();
final byte[] thisByteArray = this.byteArray;
final byte[] thatByteArray = that.byteArray();
final long thisOffset = this.addressOffset();
final long thatOffset = that.addressOffset();
for (int i = 0, length = Math.min(thisCapacity, thatCapacity); i < length; i++)
{
final int cmp = Byte.compare(
UNSAFE.getByte(thisByteArray, thisOffset + i),
UNSAFE.getByte(thatByteArray, thatOffset + i));
if (0 != cmp)
{
return cmp;
}
}
if (thisCapacity != thatCapacity)
{
return thisCapacity - thatCapacity;
}
return 0;
}
/**
* {@inheritDoc}
*/
public String toString()
{
return "ExpandableArrayBuffer{" +
"byteArray=" + byteArray + // lgtm [java/print-array]
" byteArray.length" + (null == byteArray ? 0 : byteArray.length) +
'}';
}
}