Skip to content

Commit

Permalink
Add natural, int and long parse and put methods for the buffer hierarchy
Browse files Browse the repository at this point in the history
  • Loading branch information
RichardWarburton committed Dec 11, 2017
1 parent 19ac040 commit b422867
Show file tree
Hide file tree
Showing 7 changed files with 870 additions and 5 deletions.
73 changes: 73 additions & 0 deletions agrona/src/main/java/org/agrona/AsciiEncodingHelper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* Copyright 2014-2017 Real Logic Ltd.
*
* 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
*
* http://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 static java.nio.charset.StandardCharsets.US_ASCII;

/**
* Single source of truth for ascii encoding data
*/
public class AsciiEncodingHelper
{
public static final byte NEGATIVE = '-';
public static final byte ZERO = '0';
private static final int[] INT_ROUNDS =
{
9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999, Integer.MAX_VALUE
};
private static final long[] LONG_ROUNDS =
{
9L, 99L, 999L, 9999L, 99999L, 999999L, 9999999L, 99999999L, 999999999L,
9_999999999L, 99_999999999L, 999_999999999L, 9999_999999999L,
99999_999999999L, 999999_999999999L, 9999999_999999999L, 99999999_999999999L,
999999999_999999999L, Long.MAX_VALUE
};
public static final byte[] MIN_INTEGER_VALUE = String.valueOf(Integer.MIN_VALUE).getBytes(US_ASCII);
public static final byte[] MIN_LONG_VALUE = String.valueOf(Long.MIN_VALUE).getBytes(US_ASCII);
public static final byte MINUS_SIGN = (byte)'-';

public static int endOffset(final int value)
{
for (int i = 0; true; i++)
{
if (value <= INT_ROUNDS[i])
{
return i;
}
}
}

public static int endOffset(final long value)
{
for (int i = 0; true; i++)
{
if (value <= LONG_ROUNDS[i])
{
return i;
}
}
}

public static int getDigit(final int index, final byte value)
{
if (value < 0x30 || value > 0x39)
{
throw new NumberFormatException("'" + ((char)value) + "' isn't a valid digit @ " + index);
}

return value - 0x30;
}
}
29 changes: 28 additions & 1 deletion agrona/src/main/java/org/agrona/DirectBuffer.java
Original file line number Diff line number Diff line change
Expand Up @@ -162,10 +162,37 @@ public interface DirectBuffer extends Comparable<DirectBuffer>
* Get the value at a given index.
*
* @param index in bytes from which to get.
* @return the value for at a given index
* @return the value for a given index
*/
int getInt(int index);

/**
* Get the ascii encoded natural value at a given index.
*
* @param index in bytes from which to get.
* @param length the length in bytes to parse
* @return the value at a given index
*/
int parseNaturalAscii(int index, int length);

/**
* Get the ascii encoded integer value at a given index.
*
* @param index in bytes from which to get.
* @param length the length in bytes to parse
* @return the value at a given index
*/
int parseIntAscii(int index, int length);

/**
* Get the ascii encoded long integer value at a given index.
*
* @param index in bytes from which to get.
* @param length the length in bytes to parse
* @return the value at a given index
*/
long parseLongAscii(int index, int length);

/**
* Get the value at a given index.
*
Expand Down
183 changes: 183 additions & 0 deletions agrona/src/main/java/org/agrona/ExpandableArrayBuffer.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import static org.agrona.BitUtil.*;
import static org.agrona.UnsafeAccess.UNSAFE;
import static org.agrona.BufferUtil.*;
import static org.agrona.AsciiEncodingHelper.*;

/**
* Expandable {@link MutableDirectBuffer} that is backed by an array. When values are put into the buffer beyond its
Expand Down Expand Up @@ -802,6 +803,188 @@ public int wrapAdjustment()

///////////////////////////////////////////////////////////////////////////

public int parseNaturalAscii(final int start, final int length)
{
boundsCheck0(start, length);

final int end = start + length;
int tally = 0;
for (int index = start; index < end; index++)
{
tally = (tally * 10) + getDigit(index);
}

return tally;
}

public int parseIntAscii(final int start, final int length)
{
boundsCheck0(start, length);

final int endExclusive = start + length;
final int first = getByte(start);
int index = start;
if (first == NEGATIVE)
{
index++;
}

int tally = 0;
for (; index < endExclusive; index++)
{
tally = (tally * 10) + getDigit(index);
}

if (first == NEGATIVE)
{
tally *= -1;
}

return tally;
}

public long parseLongAscii(final int start, final int length)
{
boundsCheck0(start, length);

final int endExclusive = start + length;
final int first = getByte(start);
int index = start;
if (first == NEGATIVE)
{
index++;
}

long tally = 0;
for (; index < endExclusive; index++)
{
tally = (tally * 10) + getDigit(index);
}

if (first == NEGATIVE)
{
tally *= -1;
}

return tally;
}

private int getDigit(final int index)
{
final byte value = getByte(index);
return AsciiEncodingHelper.getDigit(index, value);
}

public int putIntAscii(final int index, final int value)
{
if (value == 0)
{
putByte(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)
{
putByte(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;
}

public int putNaturalAscii(final int index, final int value)
{
if (value == 0)
{
putByte(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;
}

public int putLongAscii(final int index, final long value)
{
if (value == 0)
{
putByte(index, ZERO);
return 1;
}

if (value == Integer.MIN_VALUE)
{
putBytes(index, MIN_LONG_VALUE);
return MIN_LONG_VALUE.length;
}

int start = index;
long quotient = value;
int length = 1;
if (value < 0)
{
putByte(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;
}

///////////////////////////////////////////////////////////////////////////

public boolean equals(final Object obj)
{
if (this == obj)
Expand Down
Loading

0 comments on commit b422867

Please sign in to comment.