Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prepares to support reading binary Ion 1.1. #639

Merged
merged 6 commits into from
Nov 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions src/main/java/com/amazon/ion/Timestamp.java
Original file line number Diff line number Diff line change
Expand Up @@ -676,6 +676,19 @@ else if (shouldCheckFraction)
offset, APPLY_OFFSET_NO, CHECK_FRACTION_YES);
}

/**
* @return a new Timestamp from the given components in local time, without validating the fractional seconds.
*/
@Deprecated
public static Timestamp _private_createFromLocalTimeFieldsUnchecked(Precision p, int year, int month, int day,
int hour, int minute, int second,
BigDecimal frac, Integer offset)
{
return new Timestamp(p, year, month, day,
hour, minute, second, frac,
offset, APPLY_OFFSET_YES, CHECK_FRACTION_NO);
}

/**
* Creates a new Timestamp from a {@link Calendar}, preserving the
* {@link Calendar}'s precision and local offset from UTC.
Expand Down
91 changes: 80 additions & 11 deletions src/main/java/com/amazon/ion/impl/IonCursorBinary.java
Original file line number Diff line number Diff line change
Expand Up @@ -919,12 +919,53 @@ private boolean slowReadFieldName_1_0() {

/* ---- Ion 1.1 ---- */

private long uncheckedReadVarUInt_1_1() {
throw new UnsupportedOperationException();
/**
* Reads a FlexUInt. NOTE: the FlexUInt must fit in a `long`. This must only be called when it is known that the
* buffer already contains all the bytes in the FlexUInt.
* @return the value.
*/
private long uncheckedReadFlexUInt_1_1() {
int currentByte = buffer[(int) peekIndex++] & 0xFF;
if ((currentByte & 1) == 1) { // TODO perf: analyze whether the special case check is a net positive
// Single-byte.
return currentByte >>> 1;
}
if (currentByte == 0) { // The first byte is 0, so there are at least 9 bytes.
throw new IonException("Found a VarUInt that was too large to fit in a `long`");
}
// TODO perf: try putting the rest in its own method
byte length = (byte) (Integer.numberOfTrailingZeros(currentByte) + 1);
long result = currentByte >>> length;
for (byte i = 1; i < length; i++) {
result |= ((long) (buffer[(int) (peekIndex++)] & SINGLE_BYTE_MASK) << (8 * i - length));
}
return result;
}

private long slowReadVarUInt_1_1() {
throw new UnsupportedOperationException();
/**
* Reads a FlexUInt, ensuring enough data is available in the buffer. NOTE: the FlexUInt must fit in a `long`.
* @return the value.
*/
private long slowReadFlexUInt_1_1() {
// TODO perf: try 1-byte special case checks. Least-significant bits of 1 indicate 1-byte
int currentByte = slowReadByte();
if (currentByte < 0) {
return -1;
}
if (currentByte == 0) {
throw new IonException("Found a VarUInt that was too large to fit in a `long`");
}
byte length = (byte) (Integer.numberOfTrailingZeros(currentByte) + 1);
long result = currentByte >>> length;
int numberOfBytesRead = 0;
while (numberOfBytesRead++ < length - 1) {
currentByte = slowReadByte();
if (currentByte < 0) {
return -1;
}
result |= ((long) currentByte << (8 * numberOfBytesRead - length));
}
return result;
}

private boolean uncheckedReadAnnotationWrapperHeader_1_1(IonTypeID valueTid) {
Expand All @@ -935,8 +976,29 @@ private boolean slowReadAnnotationWrapperHeader_1_1(IonTypeID valueTid) {
throw new UnsupportedOperationException();
}

/**
* Calculates the end index for the given type ID and sets `event` based on the type of value encountered, if any.
* At the time of invocation, `peekIndex` must point to the first byte after the value's type ID byte. After return,
* `peekIndex` will point to the first byte in the value's representation, or, in the case of a NOP pad, the first
* byte that follows the pad.
* @param valueTid the type ID of the value.
* @param isAnnotated true if the value is annotated.
* @return the end index of the value or NOP pad.
*/
private long calculateEndIndex_1_1(IonTypeID valueTid, boolean isAnnotated) {
throw new UnsupportedOperationException();
if (valueTid.isDelimited) {
event = Event.START_CONTAINER;
return DELIMITED_MARKER;
}
long endIndex = (valueTid.variableLength ? uncheckedReadFlexUInt_1_1() : valueTid.length) + peekIndex;
if (valueTid.type != null && valueTid.type.ordinal() >= LIST_TYPE_ORDINAL) {
event = Event.START_CONTAINER;
} else if (valueTid.isNopPad) {
uncheckedSeekPastNopPad(endIndex, isAnnotated);
} else {
event = Event.START_SCALAR;
}
return endIndex;
}

private void uncheckedReadFieldName_1_1() {
Expand Down Expand Up @@ -1098,6 +1160,8 @@ private void readIvm() {
}
if (minorVersion == 0) {
typeIds = IonTypeID.TYPE_IDS_1_0;
} else if (minorVersion == 1) {
typeIds = IonTypeID.TYPE_IDS_1_1;
} else {
throw new IonException(String.format("Unsupported Ion version: %d.%d", majorVersion, minorVersion));
}
Expand Down Expand Up @@ -1201,6 +1265,9 @@ private boolean uncheckedReadHeader(final int typeIdByte, final boolean isAnnota
if (endIndex > limit) {
isValueIncomplete = true;
}
if (minorVersion == 1 && valueTid.isNull && valueTid.length > 0) {
valueTid = IonTypeID.NULL_TYPE_IDS_1_1[buffer[(int)(peekIndex++) & SINGLE_BYTE_MASK]];
}
}
markerToSet.typeId = valueTid;
if (event == Event.START_CONTAINER) {
Expand Down Expand Up @@ -1245,6 +1312,13 @@ private boolean slowReadHeader(final int typeIdByte, final boolean isAnnotated,
}
return true;
}
if (minorVersion == 1 && valueTid.isNull && valueTid.length > 0) {
int nullTypeIndex = slowReadByte();
if (nullTypeIndex < 0) {
return true;
}
valueTid = IonTypeID.NULL_TYPE_IDS_1_1[nullTypeIndex];
}
markerToSet.typeId = valueTid;
if (checkpointLocation == CheckpointLocation.AFTER_SCALAR_HEADER) {
return true;
Expand Down Expand Up @@ -1274,12 +1348,7 @@ private boolean slowReadValueHeader(IonTypeID valueTid, boolean isAnnotated, Mar
if (valueTid.isDelimited) {
endIndex = DELIMITED_MARKER;
} else if (valueTid.variableLength) {
// At this point the value must be at least 2 more bytes: 1 for the smallest-possible value length
// and 1 for the smallest-possible value representation.
if (!fillAt(peekIndex, 2)) {
return true;
}
valueLength = minorVersion == 0 ? slowReadVarUInt_1_0() : slowReadVarUInt_1_1();
valueLength = minorVersion == 0 ? slowReadVarUInt_1_0() : slowReadFlexUInt_1_1();
if (valueLength < 0) {
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -902,7 +902,7 @@ private enum State {
boolean startsWithIonSymbolTable() {
long savedPeekIndex = peekIndex;
peekIndex = annotationSequenceMarker.startIndex;
int sid = minorVersion == 0 ? readVarUInt_1_0() : readVarUInt_1_1();
int sid = minorVersion == 0 ? readVarUInt_1_0() : (int) readFlexUInt_1_1();
peekIndex = savedPeekIndex;
return ION_SYMBOL_TABLE_SID == sid;
}
Expand Down
Loading