From e942e2076c2552276f99b14291938a40e463888d Mon Sep 17 00:00:00 2001 From: David Noble Date: Thu, 12 Sep 2019 20:55:36 -0700 Subject: [PATCH] Code cleanup, especially in Utf8String class which is much improved. --- .../com/azure/data/cosmos/core/Reference.java | 8 +- .../azure/data/cosmos/core/Utf8String.java | 411 +++++++--- .../azure/data/cosmos/core/UtfAnyString.java | 430 +++++------ .../serialization/hybridrow/io/RowWriter.java | 704 +++++++----------- .../hybridrow/layouts/LayoutBinary.java | 43 +- .../hybridrow/layouts/LayoutTypedTuple.java | 2 +- .../hybridrow/layouts/LayoutUniqueScope.java | 2 +- .../hybridrow/layouts/LayoutUtf8.java | 3 +- .../hybridrow/schemas/SchemaHash.java | 290 ++++---- java/src/main/java/tangible/StringHelper.java | 54 +- .../hybridrow/perf/JsonModelRowGenerator.java | 8 +- .../hybridrow/unit/AssertThrowsException.java | 1 - .../unit/CustomerExampleUnitTests.java | 15 +- .../hybridrow/unit/RowWriterUnitTests.java | 2 +- 14 files changed, 996 insertions(+), 977 deletions(-) diff --git a/java/src/main/java/com/azure/data/cosmos/core/Reference.java b/java/src/main/java/com/azure/data/cosmos/core/Reference.java index 10c1dfc..6e67e8c 100644 --- a/java/src/main/java/com/azure/data/cosmos/core/Reference.java +++ b/java/src/main/java/com/azure/data/cosmos/core/Reference.java @@ -23,7 +23,7 @@ public final class Reference { } public T get() { - return value; + return this.value; } public void set(T value) { @@ -41,7 +41,7 @@ public final class Reference { * @return {@code true} if there is a value present, otherwise {@code false} */ public boolean isPresent() { - return value != null; + return this.value != null; } /** @@ -66,12 +66,12 @@ public final class Reference { return false; } - return Objects.equals(value, ((Reference)other).value); + return Objects.equals(this.value, ((Reference)other).value); } @Override public String toString() { - return value == null ? "null" : value.toString(); + return this.value == null ? "null" : this.value.toString(); } } \ No newline at end of file diff --git a/java/src/main/java/com/azure/data/cosmos/core/Utf8String.java b/java/src/main/java/com/azure/data/cosmos/core/Utf8String.java index ee44503..03d613b 100644 --- a/java/src/main/java/com/azure/data/cosmos/core/Utf8String.java +++ b/java/src/main/java/com/azure/data/cosmos/core/Utf8String.java @@ -13,10 +13,13 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import com.fasterxml.jackson.databind.node.JsonNodeType; import com.fasterxml.jackson.databind.ser.std.StdSerializer; +import com.google.common.base.Objects; +import com.google.common.base.Suppliers; import com.google.common.base.Utf8; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufHolder; import io.netty.buffer.Unpooled; +import io.netty.util.ByteProcessor; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -27,6 +30,7 @@ import java.util.Optional; import java.util.Spliterator; import java.util.function.Consumer; import java.util.function.IntConsumer; +import java.util.function.Supplier; import java.util.stream.IntStream; import java.util.stream.StreamSupport; @@ -40,32 +44,49 @@ import static java.nio.charset.StandardCharsets.UTF_8; @SuppressWarnings("UnstableApiUsage") public final class Utf8String implements ByteBufHolder, CharSequence, Comparable { - public static final Utf8String EMPTY = new Utf8String(Unpooled.EMPTY_BUFFER, 0); - public static final Utf8String NULL = new Utf8String(); + public static final Utf8String EMPTY = new Utf8String(Unpooled.EMPTY_BUFFER); + public static final Utf8String NULL = new Utf8String(null); private final ByteBuf buffer; - private final int length; + private final Supplier codePointCount; + private final Supplier utf16CodeUnitCount; - private Utf8String() { - this.buffer = null; - this.length = -1; - } + private Utf8String(@Nullable final ByteBuf buffer) { - private Utf8String(@Nonnull final ByteBuf buffer) { - this(buffer, decodedLength(buffer)); - } + if (buffer == null) { + this.buffer = null; + this.codePointCount = Suppliers.memoize(() -> -1); + this.utf16CodeUnitCount = Suppliers.memoize(() -> -1); + return; + } - private Utf8String(@Nonnull final ByteBuf buffer, final int decodedLength) { - checkNotNull(buffer, "expected non-null buffer"); - this.buffer = buffer.asReadOnly(); - this.length = decodedLength; + if (buffer.writerIndex() == 0) { + this.buffer = Unpooled.EMPTY_BUFFER; + this.codePointCount = Suppliers.memoize(() -> 0); + this.utf16CodeUnitCount = Suppliers.memoize(() -> 0); + return; + } + + this.buffer = buffer; + + this.codePointCount = Suppliers.memoize(() -> { + final UTF8CodePointCounter counter = new UTF8CodePointCounter(); + this.buffer.forEachByte(0, this.buffer.writerIndex(), counter); + return counter.value(); + }); + + this.utf16CodeUnitCount = Suppliers.memoize(() -> { + final UTF16CodeUnitCounter counter = new UTF16CodeUnitCounter(); + this.buffer.forEachByte(0, this.buffer.writerIndex(), counter); + return counter.value(); + }); } /** * {@code true} if the length of this instance is zero */ public final boolean isEmpty() { - return this.length == 0; + return this.buffer != null && this.buffer.writerIndex() == 0; } /** @@ -92,10 +113,10 @@ public final class Utf8String implements ByteBufHolder, CharSequence, Comparable * Non-allocating enumeration of each code point in the UTF-8 stream */ public final IntStream codePoints() { - if (this.length == 0) { + if (this.buffer == null || this.buffer.writerIndex() == 0) { return IntStream.empty(); } - return StreamSupport.intStream(new CodePointIterable(this.buffer, this.length), false); + return StreamSupport.intStream(new CodePointIterable(this.buffer, this.codePointCount.get()), false); } @@ -130,7 +151,7 @@ public final class Utf8String implements ByteBufHolder, CharSequence, Comparable if (limit > 0) { - final CodePointIterable iterable = new CodePointIterable(this.buffer, this.length); + final CodePointIterable iterable = new CodePointIterable(this.buffer, this.utf16CodeUnitCount.get()); int index = 0; for (int codePoint : iterable) { @@ -182,16 +203,16 @@ public final class Utf8String implements ByteBufHolder, CharSequence, Comparable /** * Encoded length of this {@link Utf8String} *

- * This is the same value as would be returned by {@link String#getBytes()#length} with no time or space overhead. + * This is the same value as would be returned by {@link String#getBytes()#utf16CodeUnitCount} with no time or space overhead. * * @return encoded length of {@link Utf8String} */ public final int encodedLength() { - return this.buffer.writerIndex(); + return this.buffer == null ? 0 : this.buffer.writerIndex(); } public final boolean equals(ByteBuf other) { - return this.buffer.equals(other); + return Objects.equal(this.buffer, other); } public final boolean equals(String other) { @@ -202,33 +223,25 @@ public final class Utf8String implements ByteBufHolder, CharSequence, Comparable } public final boolean equals(Utf8String other) { - if (other == null) { - return false; - } - if (other == this) { + if (this == other) { return true; } - return this.buffer.equals(other.buffer); + if (null == other) { + return false; + } + return Objects.equal(this.buffer, other.buffer); } @Override public boolean equals(Object other) { - if (other == null) { - return false; - } - if (other == this) { + if (this == other) { return true; } - if (other instanceof ByteBuf) { - return this.equals((ByteBuf)other); + if (null == other || this.getClass() != other.getClass()) { + return false; } - if (other instanceof String) { - return this.equals((String)other); - } - if (other instanceof Utf8String) { - return this.equals((Utf8String)other); - } - return false; + Utf8String that = (Utf8String) other; + return this.utf16CodeUnitCount == that.utf16CodeUnitCount && Objects.equal(this.buffer, that.buffer); } /** @@ -247,11 +260,12 @@ public final class Utf8String implements ByteBufHolder, CharSequence, Comparable } /** - * Creates a new {@link Utf8String} from a {@link ByteBuf} without UTF-8 character validation + * Creates a new {@link Utf8String} from a {@link ByteBuf} without UTF-8 character validation. *

- * The {@link Utf8String} created retains the {@link ByteBuf}. (No data is transferred.) + * The {@link Utf8String} created retains the {@link ByteBuf} and ensures it is read-only by calling + * {@link ByteBuf#asReadOnly}. No data is transferred. * - * @param buffer The {@link ByteBuf} to assign to the {@link Utf8String} created. + * @param buffer a {@link ByteBuf} to assign to the {@link Utf8String} created. * @return a new {@link Utf8String} */ @Nonnull @@ -266,12 +280,13 @@ public final class Utf8String implements ByteBufHolder, CharSequence, Comparable } /** - * Returns the length of this character sequence + * Returns the length of this character sequence. *

- * The length is the number of Unicode characters in the sequence. + * The length is the number of UTF-16 code units in the sequence. This is the same value as would be returned by + * {@link Utf8String#toUtf16()#length()} with no time or space overhead. */ public final int length() { - return this.length; + return this.utf16CodeUnitCount.get(); } /** @@ -285,10 +300,11 @@ public final class Utf8String implements ByteBufHolder, CharSequence, Comparable } /** - * Decreases the reference count by {@code 1} and deallocates this object if the reference count reaches at - * {@code 0}. + * Decreases the reference count by {@code 1}. * - * @return {@code true} if and only if the reference count became {@code 0} and this object has been deallocated + * The underlying storage for this instance is deallocated, if the reference count reaches {@code 0}. + * + * @return {@code true} if and only if the reference count became {@code 0} and this object has been deallocated. */ @Override public boolean release() { @@ -296,11 +312,12 @@ public final class Utf8String implements ByteBufHolder, CharSequence, Comparable } /** - * Decreases the reference count by the specified {@code decrement} and deallocates this object if the reference - * count reaches at {@code 0}. + * Decreases the reference count by the specified {@code decrement} * - * @param decrement - * @return {@code true} if and only if the reference count became {@code 0} and this object has been deallocated + * The underlying storage for this instance is deallocated, if the reference count reaches {@code 0}. + * + * @param decrement the value to subtract from the reference count. + * @return {@code true} if and only if the reference count became {@code 0}. */ @Override public boolean release(int decrement) { @@ -308,7 +325,7 @@ public final class Utf8String implements ByteBufHolder, CharSequence, Comparable } /** - * Returns a new {@link Utf8String} which contains the specified {@code content} + * Returns a new {@link Utf8String} which contains the specified {@code content}. * * @param content text of the {@link Utf8String} to be created. */ @@ -330,7 +347,7 @@ public final class Utf8String implements ByteBufHolder, CharSequence, Comparable } /** - * Duplicates this {@link Utf8String} + * Duplicates this {@link Utf8String}. *

* This method returns a retained duplicate unlike {@link #duplicate()}. * @@ -343,9 +360,8 @@ public final class Utf8String implements ByteBufHolder, CharSequence, Comparable @Override public CharSequence subSequence(int start, int end) { - checkArgument(start < 0 || end < 0 || start > end || end > this.length, "start: %s, end: %s", start, end); - // TODO: DANOBLE: compute buffer index for start and end character positions and use them in the slice - return new Utf8String(this.buffer.slice(), end - start); + checkArgument(start < 0 || end < 0 || start > end || end > this.length(), "start: %s, end: %s", start, end); + return new Utf8String(this.buffer.slice(start, end)); } @Override @@ -394,43 +410,34 @@ public final class Utf8String implements ByteBufHolder, CharSequence, Comparable checkState(count == length, "count: %s, length: %s", count, length); - return new Utf8String(buffer, string.length()); + return new Utf8String(buffer); } - private static int decodedLength(final ByteBuf buffer) { - - final CodePointIterable iterable = new CodePointIterable(buffer, -1); - int decodedLength = 0; - - for (int ignored : iterable) { - decodedLength++; - } - - return decodedLength; - } - - private static final class CodePointIterable implements Iterable, Iterator, Spliterator.OfInt { + private static final class CodePointIterable extends UTF8CodePointGetter implements + Iterable, Iterator, Spliterator.OfInt { private static final int CHARACTERISTICS = Spliterator.IMMUTABLE | Spliterator.NONNULL | Spliterator.ORDERED; private final ByteBuf buffer; - private final int length; - private int index; + private final int codePointCount; - CodePointIterable(final ByteBuf buffer, final int length) { + private int start, length; + + CodePointIterable(final ByteBuf buffer, final int codePointCount) { + this.codePointCount = codePointCount; this.buffer = buffer; - this.length = length; - this.index = 0; + this.start = 0; + this.length = buffer.writerIndex(); } @Override public int characteristics() { - return this.length == -1 ? CHARACTERISTICS : CHARACTERISTICS | Spliterator.SIZED | Spliterator.SUBSIZED; + return this.codePointCount == -1 ? CHARACTERISTICS : CHARACTERISTICS | Spliterator.SIZED | Spliterator.SUBSIZED; } @Override public long estimateSize() { - return this.length < 0 ? Long.MAX_VALUE : this.length; + return this.codePointCount < 0 ? Long.MAX_VALUE : this.codePointCount; } @Override @@ -440,7 +447,7 @@ public final class Utf8String implements ByteBufHolder, CharSequence, Comparable @Override public boolean hasNext() { - return this.index < this.buffer.capacity(); + return this.length > 0; } @Override @@ -456,50 +463,10 @@ public final class Utf8String implements ByteBufHolder, CharSequence, Comparable throw new NoSuchElementException(); } - final int leadingByte = this.buffer.getByte(this.index++) & 0xFF; + this.start = this.buffer.forEachByte(this.start, this.length, this); + this.length -= this.start; - // A 1-byte UTF-8 code point is a special case that covers the 7-bit ASCII character set - - if (leadingByte < 0x80) { - return leadingByte; - } - - // The initial byte of 2-, 3- and 4-byte UTF-8 code points start with 2, 3, or 4 one bits followed by a 0 - // bit - - final int codePoint; - - if ((leadingByte & 0b1110_0000) == 0b1100_0000) { - - // 110xxxxx 10xxxxxx => 0x00000080 - 0x000007FF - - codePoint = ((leadingByte & 0b0001_1111) << 6) | - (this.buffer.getByte(this.index++) & 0b0011_1111); - - } else if ((leadingByte & 0b1111_0000) == 0b1110_0000) { - - // 1110xxxx 10xxxxxx 10xxxxxx => 0x00000800 - 0x0000FFFF - - codePoint = ((leadingByte & 0b0000_1111) << 12) | - ((this.buffer.getByte(this.index++) & 0b0011_1111) << 6) | - ((this.buffer.getByte(this.index++) & 0b0011_1111)); - - } else if ((leadingByte & 0b1111_1000) == 0b1111_0000) { - - // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx => 0x00010000 - 0x001FFFFF - - codePoint = ((leadingByte & 0b0000_0111) << 18) | - ((this.buffer.getByte(this.index++) & 0b0011_1111) << 12) | - ((this.buffer.getByte(this.index++) & 0b0011_1111) << 6) | - ((this.buffer.getByte(this.index++) & 0b0011_1111)); - - } else { - // leading byte is improperly encoded and we'll detect that before returning - codePoint = leadingByte; - } - - checkState(Character.isDefined(codePoint), "invalid character: %s", codePoint); - return codePoint; + return this.codePoint(); } @Override @@ -563,4 +530,204 @@ public final class Utf8String implements ByteBufHolder, CharSequence, Comparable generator.writeString(value.toString()); } } + + /** + * A {@link ByteProcessor} used by to count the number of UTF-16 code units in a UTF-8 encoded string. + * + * This class makes use of the fact that code points that UTF-16 encodes with two 16-bit code units, UTF-8 encodes + * with 4 8-bit code units, and vice versa. Lead bytes are identified and counted. All other bytes are skipped. + * Code points are not validated. The {@link #process} method counts undefined leading bytes as an undefined UTF-16 + * code unit to be replaced. + * + * @see RFC 3629: UTF-8, a transformation format of ISO 10646 + */ + private static final class UTF16CodeUnitCounter implements ByteProcessor { + + private int count = 0; + private int skip = 0; + + @Override + public boolean process(byte value) throws Exception { + + if (this.skip > 0) { + this.skip--; + } else { + final int leadingByte = value & 0xFF; + if (leadingByte < 0x7F) { + // UTF-8-1 = 0x00-7F + this.skip = 0; + this.count++; + } else if (0xC2 <= leadingByte && leadingByte <= 0xDF) { + // UTF8-8-2 = 0xC2-DF UTF8-tail + this.skip = 1; + this.count++; + } else if (0xE0 <= leadingByte && leadingByte <= 0xEF) { + // UTF-8-3 = 0xE0 0xA0-BF UTF8-tail / 0xE1-EC 2(UTF8-tail) / 0xED 0x80-9F UTF8-tail / 0xEE-EF 2(UTF8-tail) + this.skip = 2; + this.count++; + } else if (0xF0 <= leadingByte && leadingByte <= 0xF4) { + // UTF8-4 = 0xF0 0x90-BF 2( UTF8-tail ) / 0xF1-F3 3( UTF8-tail ) / 0xF4 0x80-8F 2( UTF8-tail ) + this.skip = 3; + this.count += 2; + } else { + this.skip = 0; + this.count++; + } + } + return true; + } + + public int value() { + return this.count; + } + } + + /** + * A {@link ByteProcessor} used by to count the number of Unicode code points in a UTF-8 encoded string. + * + * Lead bytes are identified and counted. All other bytes are skipped. Code points are not validated. The + * {@link #process} method counts undefined lead bytes as a single code point to be replaced. + * + * @see RFC 3629: UTF-8, a transformation format of ISO 10646 + */ + private static final class UTF8CodePointCounter implements ByteProcessor { + + private int count = 0; + private int skip = 0; + + @Override + public boolean process(byte value) { + + if (this.skip > 0) { + this.skip--; + } else { + final int leadingByte = value & 0xFF; + if (leadingByte < 0x7F) { + // UTF-8-1 = 0x00-7F + this.skip = 0; + } else if (0xC2 <= leadingByte && leadingByte <= 0xDF) { + // UTF8-8-2 = 0xC2-DF UTF8-tail + this.skip = 1; + } else if (0xE0 <= leadingByte && leadingByte <= 0xEF) { + // UTF-8-3 = 0xE0 0xA0-BF UTF8-tail / 0xE1-EC 2(UTF8-tail) / 0xED 0x80-9F UTF8-tail / 0xEE-EF 2(UTF8-tail) + this.skip = 2; + } else if (0xF0 <= leadingByte && leadingByte <= 0xF4) { + // UTF8-4 = 0xF0 0x90-BF 2( UTF8-tail ) / 0xF1-F3 3( UTF8-tail ) / 0xF4 0x80-8F 2( UTF8-tail ) + this.skip = 3; + } else { + // Undefined leading byte + this.skip = 0; + } + this.count++; + } + return true; + } + + public int value() { + return this.count; + } + } + + /** + * A {@link ByteProcessor} used to read a UTF-8 encoded string one Unicode code point at a time. + *

+ * This {@link #process(byte)} method reads a single code point at a time. The first byte read following + * construction of an instance of this class must be a leading byte. This is used to determine the number of + * single-byte UTF-8 code units in the code point. + *

+ * Code points are validated. The {@link #process(byte)} method returns the Unicode + * Replacement character + * when an undefined code point is encountered. + * + * @see RFC 3629: UTF-8, a transformation format of ISO 10646 + */ + private static class UTF8CodePointGetter implements ByteProcessor { + + private static final int REPLACEMENT_CHARACTER = 0xFFFD; + + private int codePoint = 0; + private int shift = -1; + + /** + * Gets the next code unit in a UTF-8 code point sequence. + * + * @param value the next code unit in a UTF-8 + * + * @return {@code true} if additional code units must be read to complete the code point; otherwise, if the + * code point is complete, a value of {@code false} is returned. + */ + @Override + public boolean process(byte value) { + + switch (this.shift) { + + default: { + + // Next unit of code point sequence + + this.codePoint |= (value & 0xFF << this.shift); + this.shift -= Byte.SIZE; + return true; + } + case 0: { + + // End of code point sequence + + this.codePoint |= value & 0xFF; + this.shift = -1; + + if (!Character.isDefined(this.codePoint)) { + this.codePoint = REPLACEMENT_CHARACTER; + }; + + return false; + } + case -1: { + + // Start of code point sequence + + final int leadingByte = value & 0xFF; + + if (leadingByte < 0x7F) { + // UTF-8-1 = 0x00-7F + this.codePoint = leadingByte; + return false; + } + + if (0xC2 <= leadingByte && leadingByte <= 0xDF) { + // UTF8-8-2 = 0xC2-DF UTF8-tail + this.codePoint = leadingByte << Byte.SIZE; + this.shift = 0; + return true; + } + + if (0xE0 <= leadingByte && leadingByte <= 0xEF) { + // UTF-8-3 = 0xE0 0xA0-BF UTF8-tail / 0xE1-EC 2(UTF8-tail) / 0xED 0x80-9F UTF8-tail / 0xEE-EF 2(UTF8-tail) + this.codePoint = leadingByte << 2 * Byte.SIZE; + this.shift = Byte.SIZE; + return true; + } + + if (0xF0 <= leadingByte && leadingByte <= 0xF4) { + // UTF8-4 = 0xF0 0x90-BF 2( UTF8-tail ) / 0xF1-F3 3( UTF8-tail ) / 0xF4 0x80-8F 2( UTF8-tail ) + this.codePoint = leadingByte << 3 * Byte.SIZE; + this.shift = 3 * Byte.SIZE; + return true; + } + + this.codePoint = REPLACEMENT_CHARACTER; + return false; + } + } + } + + /** + * Returns the value of the most-recently read code point. + * + * @return value of the most-recently read code point. + */ + int codePoint() { + return this.codePoint; + } + } } diff --git a/java/src/main/java/com/azure/data/cosmos/core/UtfAnyString.java b/java/src/main/java/com/azure/data/cosmos/core/UtfAnyString.java index cb1cf74..370e780 100644 --- a/java/src/main/java/com/azure/data/cosmos/core/UtfAnyString.java +++ b/java/src/main/java/com/azure/data/cosmos/core/UtfAnyString.java @@ -17,274 +17,278 @@ import static com.google.common.base.Preconditions.checkNotNull; */ public final class UtfAnyString implements CharSequence, Comparable { - private static final UtfAnyString EMPTY = new UtfAnyString(""); - private static final int NULL_HASHCODE = reduceHashCode(5_381, 5_381); + public static final UtfAnyString EMPTY = new UtfAnyString(""); + public static final UtfAnyString NULL = new UtfAnyString(); - private CharSequence buffer; + private static final int NULL_HASHCODE = reduceHashCode(5_381, 5_381); - public UtfAnyString(final String string) { - this.buffer = string; - } + private CharSequence buffer; - public UtfAnyString(final Utf8String utf8String) { - this.buffer = utf8String; - } + public UtfAnyString(final String value) { + this.buffer = value; + } - private UtfAnyString(final CharSequence sequence) { - this.buffer = sequence; - } + public UtfAnyString(final Utf8String value) { + this.buffer = value; + } - /** - * {@code true} if the {@link UtfAnyString} is empty - */ - public boolean isEmpty() { - return this.buffer != null && this.buffer.length() == 0; - } + private UtfAnyString() { + } - /** - * {@code true} if the {@link UtfAnyString} is {@code null} - */ - public boolean isNull() { - return null == this.buffer; - } + private UtfAnyString(final CharSequence sequence) { + this.buffer = sequence; + } - public boolean isUtf16() { - return this.buffer instanceof String; - } + /** + * {@code true} if the {@link UtfAnyString} is empty + */ + public boolean isEmpty() { + return this.buffer != null && this.buffer.length() == 0; + } - public boolean isUtf8() { - return this.buffer instanceof Utf8String; - } + /** + * {@code true} if the {@link UtfAnyString} is {@code null} + */ + public boolean isNull() { + return null == this.buffer; + } - /** - * Returns the {@code char} value at the specified {@code index} - *

- * An index ranges from zero to {@link UtfAnyString#length()} minus one. The first {@code char} value of the - * sequence is at index zero, the next at index one, and so on, as for array indexing. If the {@code char} - * value specified by the {@code index} is a surrogate, the surrogate (not the surrogate pair) is returned. - * - * @param index the index of the {@code char} value to be returned - * @return the specified {@code char} value - * @throws IndexOutOfBoundsException if the {@code index} argument is negative or not less than - * {@link UtfAnyString#length()} - * @throws UnsupportedOperationException if this {@link UtfAnyString} is {@code null}. - */ - @Override - public char charAt(final int index) { - if (this.buffer == null) { - throw new UnsupportedOperationException("String is null"); - } - return this.buffer.charAt(index); - } + public boolean isUtf16() { + return this.buffer instanceof String; + } - public int compareTo(@Nonnull final String other) { + public boolean isUtf8() { + return this.buffer instanceof Utf8String; + } - checkNotNull(other); + /** + * Returns the {@code char} value at the specified {@code index} + *

+ * An index ranges from zero to {@link UtfAnyString#length()} minus one. The first {@code char} value of the + * sequence is at index zero, the next at index one, and so on, as for array indexing. If the {@code char} + * value specified by the {@code index} is a surrogate, the surrogate (not the surrogate pair) is returned. + * + * @param index the index of the {@code char} value to be returned. + * @return the specified {@code char} value + * @throws IndexOutOfBoundsException if the {@code index} argument is negative or not less than + * {@link UtfAnyString#length()} + * @throws UnsupportedOperationException if this {@link UtfAnyString} is {@code null}. + */ + @Override + public char charAt(final int index) { + if (this.buffer == null) { + throw new UnsupportedOperationException("String is null"); + } + return this.buffer.charAt(index); + } - if (other == this.buffer) { - return 0; - } + public int compareTo(@Nonnull final String other) { - if (this.buffer == null) { - return -1; - } + checkNotNull(other, "expected non-null other"); - return this.buffer instanceof String - ? ((String) this.buffer).compareTo(other) - : ((Utf8String) this.buffer).compareTo(other); - } + if (other == this.buffer) { + return 0; + } - public int compareTo(@Nonnull final Utf8String other) { + if (this.buffer == null) { + return -1; + } - checkNotNull(other); + return this.buffer instanceof String + ? ((String) this.buffer).compareTo(other) + : ((Utf8String) this.buffer).compareTo(other); + } - if (other == this.buffer) { - return 0; - } + public int compareTo(@Nonnull final Utf8String other) { - if (this.buffer == null) { - return -1; - } + checkNotNull(other, "expected non-null other"); - return this.buffer instanceof String - ? -other.compareTo((String) this.buffer) - : ((Utf8String) this.buffer).compareTo(other); - } + if (other == this.buffer) { + return 0; + } - @Override - public int compareTo(@Nonnull final UtfAnyString other) { + if (this.buffer == null) { + return -1; + } - checkNotNull(other); + return this.buffer instanceof String + ? -other.compareTo((String) this.buffer) + : ((Utf8String) this.buffer).compareTo(other); + } - if (other.buffer == this.buffer) { - return 0; - } + @Override + public int compareTo(@Nonnull final UtfAnyString other) { - if (other.buffer == null) { - return 1; - } + checkNotNull(other, "expected non-null other"); - if (this.buffer == null) { - return -1; - } + if (other.buffer == this.buffer) { + return 0; + } - if (this.buffer instanceof String) { - return other.buffer instanceof String - ? ((String) this.buffer).compareTo((String) other.buffer) - : -((Utf8String) other.buffer).compareTo((String) this.buffer); - } + if (other.buffer == null) { + return 1; + } - return ((Utf8String) this.buffer).compareTo((Utf8String) other.buffer); - } + if (this.buffer == null) { + return -1; + } - public static UtfAnyString empty() { - return EMPTY; - } + if (this.buffer instanceof String) { + return other.buffer instanceof String + ? ((String) this.buffer).compareTo((String) other.buffer) + : -((Utf8String) other.buffer).compareTo((String) this.buffer); + } - @Override - public boolean equals(final Object other) { + return ((Utf8String) this.buffer).compareTo((Utf8String) other.buffer); + } - if (other == null) { - return false; - } + public static UtfAnyString empty() { + return EMPTY; + } - if (other instanceof String) { - return this.equals((String) other); - } + @Override + public boolean equals(final Object other) { - if (other instanceof Utf8String) { - return this.equals((Utf8String) other); - } + if (other == null) { + return false; + } - if (other instanceof UtfAnyString) { - return this.equals((UtfAnyString) other); - } + if (other instanceof String) { + return this.equals((String) other); + } - return false; - } + if (other instanceof Utf8String) { + return this.equals((Utf8String) other); + } - public boolean equals(final String other) { + if (other instanceof UtfAnyString) { + return this.equals((UtfAnyString) other); + } - if (null == this.buffer) { - return null == other; - } + return false; + } - if (this.buffer instanceof String) { - return other.contentEquals(this.buffer); // skips the type check that String.equals performs - } + public boolean equals(final String other) { - return ((Utf8String) this.buffer).equals(other); - } + if (null == this.buffer) { + return null == other; + } - public boolean equals(final Utf8String other) { + if (this.buffer instanceof String) { + return other.contentEquals(this.buffer); // skips the type check that String.equals performs + } - if (null == other) { - return null == this.buffer; - } + return ((Utf8String) this.buffer).equals(other); + } - return other.equals(this.buffer); - } + public boolean equals(final Utf8String other) { - public boolean equals(final UtfAnyString other) { + if (null == other) { + return null == this.buffer; + } - if (null == other) { - return false; - } + return other.equals(this.buffer); + } - if (null == this.buffer) { - return null == other.buffer; - } + public boolean equals(final UtfAnyString other) { - return this.buffer instanceof String ? other.buffer.equals(this.buffer) : this.buffer.equals(other.buffer); - } + if (null == other) { + return false; + } - @Override - public int hashCode() { + if (null == this.buffer) { + return null == other.buffer; + } - final long[] hash = { 5_381, 5_381 }; + return this.buffer instanceof String ? other.buffer.equals(this.buffer) : this.buffer.equals(other.buffer); + } - if (this.buffer == null) { - return NULL_HASHCODE; - } + @Override + public int hashCode() { - if (this.buffer instanceof String) { + final long[] hash = { 5_381, 5_381 }; - final int ignored = ((String) this.buffer).codePoints().reduce(0, (index, codePoint) -> { - if (index % 2 == 0) { - hash[0] = ((hash[0] << 5) + hash[0]) ^ codePoint; - } else { - hash[1] = ((hash[1] << 5) + hash[1]) ^ codePoint; - } - return index; - }); + if (this.buffer == null) { + return NULL_HASHCODE; + } - return reduceHashCode(hash[0], hash[1]); - } + if (this.buffer instanceof String) { - return this.buffer.hashCode(); - } + final int ignored = ((String) this.buffer).codePoints().reduce(0, (index, codePoint) -> { + if (index % 2 == 0) { + hash[0] = ((hash[0] << 5) + hash[0]) ^ codePoint; + } else { + hash[1] = ((hash[1] << 5) + hash[1]) ^ codePoint; + } + return index; + }); - /** - * Returns the length of this character sequence. The length is the number - * of 16-bit {@code char}s in the sequence. - * - * @return the number of {@code char}s in this sequence - * - * @throws UnsupportedOperationException if this {@link UtfAnyString} is {@code null} - */ - @Override - public int length() { - if (this.buffer == null) { - throw new UnsupportedOperationException("String is null"); - } - return this.buffer.length(); - } + return reduceHashCode(hash[0], hash[1]); + } - /** - * Returns a {@code CharSequence} that is a subsequence of this sequence - *

- * The subsequence starts with the {@code char} value at the specified index and ends with the{@code char} value at - * index {@code end - 1}. The length (in {@code char}s) of the returned sequence is {@code end - start}, so if - * {@code start == end}, an empty sequence is returned. - * - * @param start the start index, inclusive - * @param end the end index, exclusive - * @return the specified subsequence - * @throws IndexOutOfBoundsException if {@code start} or {@code end} are negative, {@code end} is greater than - * {@link UtfAnyString#length()}, or {@code start} is greater than {@code - * end}. - * @throws UnsupportedOperationException if string is {@code null} - */ - @Override - @Nonnull - public CharSequence subSequence(final int start, final int end) { - if (this.buffer == null) { - throw new UnsupportedOperationException("String is null"); - } - return this.buffer.subSequence(start, end); - } + return this.buffer.hashCode(); + } - @Override - @Nonnull - public String toString() { - return String.valueOf(this.buffer); - } + /** + * Returns the length of this character sequence. The length is the number + * of 16-bit {@code char}s in the sequence. + * + * @return the number of {@code char}s in this sequence + * @throws UnsupportedOperationException if this {@link UtfAnyString} is {@code null} + */ + @Override + public int length() { + if (this.buffer == null) { + throw new UnsupportedOperationException("String is null"); + } + return this.buffer.length(); + } - public String toUtf16() { - if (null == this.buffer) { - return null; - } - return this.buffer instanceof String ? (String) this.buffer : this.buffer.toString(); - } + /** + * Returns a {@code CharSequence} that is a subsequence of this sequence + *

+ * The subsequence starts with the {@code char} value at the specified index and ends with the{@code char} value at + * index {@code end - 1}. The length (in {@code char}s) of the returned sequence is {@code end - start}, so if + * {@code start == end}, an empty sequence is returned. + * + * @param start the start index, inclusive + * @param end the end index, exclusive + * @return the specified subsequence + * @throws IndexOutOfBoundsException if {@code start} or {@code end} are negative, {@code end} is greater than + * {@link UtfAnyString#length()}, or {@code start} is greater than {@code + * end}. + * @throws UnsupportedOperationException if string is {@code null} + */ + @Override + @Nonnull + public CharSequence subSequence(final int start, final int end) { + if (this.buffer == null) { + throw new UnsupportedOperationException("String is null"); + } + return this.buffer.subSequence(start, end); + } - public Utf8String toUtf8() { - if (null == this.buffer) { - return null; - } - return this.buffer instanceof String ? transcodeUtf16((String) this.buffer) : (Utf8String) this.buffer; - } + @Override + @Nonnull + public String toString() { + return String.valueOf(this.buffer); + } - private static int reduceHashCode(final long h1, final long h2) { - return Long.valueOf(h1 + (h2 * 1_566_083_941L)).intValue(); - } + public String toUtf16() { + if (null == this.buffer) { + return null; + } + return this.buffer instanceof String ? (String) this.buffer : this.buffer.toString(); + } + + public Utf8String toUtf8() { + if (null == this.buffer) { + return null; + } + return this.buffer instanceof String ? transcodeUtf16((String) this.buffer) : (Utf8String) this.buffer; + } + + private static int reduceHashCode(final long h1, final long h2) { + return Long.valueOf(h1 + (h2 * 1_566_083_941L)).intValue(); + } } \ No newline at end of file diff --git a/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/io/RowWriter.java b/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/io/RowWriter.java index 3a511d9..c6caeca 100644 --- a/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/io/RowWriter.java +++ b/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/io/RowWriter.java @@ -3,7 +3,6 @@ package com.azure.data.cosmos.serialization.hybridrow.io; -import com.azure.data.cosmos.core.Out; import com.azure.data.cosmos.core.Reference; import com.azure.data.cosmos.core.Utf8String; import com.azure.data.cosmos.core.UtfAnyString; @@ -15,13 +14,22 @@ import com.azure.data.cosmos.serialization.hybridrow.RowCursor; import com.azure.data.cosmos.serialization.hybridrow.RowCursors; import com.azure.data.cosmos.serialization.hybridrow.UnixDateTime; import com.azure.data.cosmos.serialization.hybridrow.layouts.Layout; +import com.azure.data.cosmos.serialization.hybridrow.layouts.LayoutArray; import com.azure.data.cosmos.serialization.hybridrow.layouts.LayoutColumn; import com.azure.data.cosmos.serialization.hybridrow.layouts.LayoutListWritable; import com.azure.data.cosmos.serialization.hybridrow.layouts.LayoutNullable; +import com.azure.data.cosmos.serialization.hybridrow.layouts.LayoutObject; import com.azure.data.cosmos.serialization.hybridrow.layouts.LayoutResolver; +import com.azure.data.cosmos.serialization.hybridrow.layouts.LayoutTagged; +import com.azure.data.cosmos.serialization.hybridrow.layouts.LayoutTagged2; +import com.azure.data.cosmos.serialization.hybridrow.layouts.LayoutTuple; import com.azure.data.cosmos.serialization.hybridrow.layouts.LayoutType; import com.azure.data.cosmos.serialization.hybridrow.layouts.LayoutTypePrimitive; +import com.azure.data.cosmos.serialization.hybridrow.layouts.LayoutTypeScope; +import com.azure.data.cosmos.serialization.hybridrow.layouts.LayoutTypedArray; import com.azure.data.cosmos.serialization.hybridrow.layouts.LayoutTypedMap; +import com.azure.data.cosmos.serialization.hybridrow.layouts.LayoutTypedSet; +import com.azure.data.cosmos.serialization.hybridrow.layouts.LayoutTypedTuple; import com.azure.data.cosmos.serialization.hybridrow.layouts.LayoutTypes; import com.azure.data.cosmos.serialization.hybridrow.layouts.LayoutUDT; import com.azure.data.cosmos.serialization.hybridrow.layouts.LayoutUniqueScope; @@ -33,11 +41,18 @@ import com.azure.data.cosmos.serialization.hybridrow.schemas.StorageKind; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.math.BigDecimal; import java.time.OffsetDateTime; +import java.util.List; +import java.util.Optional; import java.util.UUID; import java.util.function.Consumer; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Strings.lenientFormat; + public final class RowWriter { private RowCursor cursor; @@ -85,8 +100,8 @@ public final class RowWriter { * @param value The value to write. * @return {@link Result#SUCCESS} if the write is successful, an error {@link Result} otherwise. */ - public Result WriteBinary(UtfAnyString path, byte[] value) { - return this.WriteBinary(path, Unpooled.wrappedBuffer(value)); + public Result writeBinary(UtfAnyString path, byte[] value) { + return this.writeBinary(path, Unpooled.wrappedBuffer(value)); } /** @@ -96,9 +111,10 @@ public final class RowWriter { * @param value The value to write. * @return {@link Result#SUCCESS} if the write is successful, an error {@link Result} otherwise. */ - public Result WriteBinary(UtfAnyString path, ByteBuf value) { - return this.writePrimitive(path, value, LayoutTypes.BINARY, (ByteBuf v) -> - this.row.writeSparseBinary(this.cursor, v, UpdateOptions.UPSERT)); + public Result writeBinary(UtfAnyString path, ByteBuf value) { + return this.writePrimitive(path, value, LayoutTypes.BINARY, + field -> this.row.writeSparseBinary(this.cursor, field, UpdateOptions.UPSERT) + ); } /** @@ -108,36 +124,33 @@ public final class RowWriter { * @param value The value to write. * @return {@link Result#SUCCESS} if the write is successful, an error {@link Result} otherwise. */ - public Result WriteBoolean(UtfAnyString path, boolean value) { - return this.writePrimitive(path, value, LayoutTypes.BOOLEAN, (Boolean v) -> - this.row.writeSparseBoolean(this.cursor, value, UpdateOptions.UPSERT)); + public Result writeBoolean(UtfAnyString path, boolean value) { + return this.writePrimitive(path, value, LayoutTypes.BOOLEAN, + field -> this.row.writeSparseBoolean(this.cursor, field, UpdateOptions.UPSERT) + ); } /** - * Write an entire row in a streaming left-to-right way. + * Write an entire buffer in a streaming left-to-right way. * * @param The type of the context value to pass to {@code func}. - * @param row The row to write. + * @param buffer The buffer to write. * @param context A context value to pass to {@code func}. - * @param func A function to write the entire row. + * @param func A function to write the entire buffer. * @return {@link Result#SUCCESS} if the write is successful, an error {@link Result} otherwise. */ - public static Result WriteBuffer( - Reference row, TContext context, WriterFunc func) { - RowCursor scope = RowCursor.create(row); - Reference tempReference_scope = - new Reference(scope); - RowWriter writer = new RowWriter(row, tempReference_scope); - scope = tempReference_scope.get(); - TypeArgument typeArg = new TypeArgument(LayoutTypes.UDT, - new TypeArgumentList(scope.layout().schemaId())); - Reference tempReference_writer = - new Reference(writer); - // TODO: C# TO JAVA CONVERTER: The following line could not be converted: - Result result = func(ref writer, typeArg, context); - writer = tempReference_writer.get(); - row.setAndGet(writer.row); - return result; + public static Result writeBuffer( + @Nonnull final RowBuffer buffer, final @Nonnull TContext context, @Nonnull final WriterFunc func) { + + checkNotNull(buffer, "expected non-null buffer"); + checkNotNull(context, "expected non-null context"); + checkNotNull(func, "expected non-null func"); + + RowCursor scope = RowCursor.create(buffer); + RowWriter writer = new RowWriter(buffer, scope); + TypeArgument typeArg = new TypeArgument(LayoutTypes.UDT, new TypeArgumentList(scope.layout().schemaId())); + + return func.invoke(writer, typeArg, context); } /** @@ -148,8 +161,9 @@ public final class RowWriter { * @return {@link Result#SUCCESS} if the write is successful, an error {@link Result} otherwise. */ public Result writeDateTime(UtfAnyString path, OffsetDateTime value) { - return this.writePrimitive(path, value, LayoutTypes.DATE_TIME, (OffsetDateTime v) -> - this.row.writeSparseDateTime(this.cursor, v, UpdateOptions.UPSERT)); + return this.writePrimitive(path, value, LayoutTypes.DATE_TIME, + field -> this.row.writeSparseDateTime(this.cursor, field, UpdateOptions.UPSERT) + ); } /** @@ -160,8 +174,9 @@ public final class RowWriter { * @return {@link Result#SUCCESS} if the write is successful, an error {@link Result} otherwise. */ public Result writeDecimal(UtfAnyString path, BigDecimal value) { - return this.writePrimitive(path, value, LayoutTypes.DECIMAL, (BigDecimal v) -> - this.row.writeSparseDecimal(this.cursor, v, UpdateOptions.UPSERT)); + return this.writePrimitive(path, value, LayoutTypes.DECIMAL, + field -> this.row.writeSparseDecimal(this.cursor, field, UpdateOptions.UPSERT) + ); } /** @@ -172,8 +187,9 @@ public final class RowWriter { * @return {@link Result#SUCCESS} if the write is successful, an error {@link Result} otherwise. */ public Result writeFloat128(UtfAnyString path, Float128 value) { - return this.writePrimitive(path, value, LayoutTypes.FLOAT_128, (Float128 v) -> - this.row.writeSparseFloat128(this.cursor, v, UpdateOptions.UPSERT)); + return this.writePrimitive(path, value, LayoutTypes.FLOAT_128, + field -> this.row.writeSparseFloat128(this.cursor, field, UpdateOptions.UPSERT) + ); } /** @@ -184,8 +200,9 @@ public final class RowWriter { * @return {@link Result#SUCCESS} if the write is successful, an error {@link Result} otherwise. */ public Result writeFloat32(UtfAnyString path, float value) { - return this.writePrimitive(path, value, LayoutTypes.FLOAT_32, (Float v) -> - this.row.writeSparseFloat32(this.cursor, v, UpdateOptions.UPSERT)); + return this.writePrimitive(path, value, LayoutTypes.FLOAT_32, + field -> this.row.writeSparseFloat32(this.cursor, field, UpdateOptions.UPSERT) + ); } /** @@ -196,8 +213,9 @@ public final class RowWriter { * @return {@link Result#SUCCESS} if the write is successful, an error {@link Result} otherwise. */ public Result writeFloat64(UtfAnyString path, double value) { - return this.writePrimitive(path, value, LayoutTypes.FLOAT_64, (Double v) -> - this.row.writeSparseFloat64(this.cursor, v, UpdateOptions.UPSERT)); + return this.writePrimitive(path, value, LayoutTypes.FLOAT_64, + field -> this.row.writeSparseFloat64(this.cursor, field, UpdateOptions.UPSERT) + ); } /** @@ -208,8 +226,9 @@ public final class RowWriter { * @return {@link Result#SUCCESS} if the write is successful, an error {@link Result} otherwise. */ public Result writeGuid(UtfAnyString path, UUID value) { - return this.writePrimitive(path, value, LayoutTypes.GUID, (UUID v) -> - this.row.writeSparseGuid(this.cursor, v, UpdateOptions.UPSERT)); + return this.writePrimitive(path, value, LayoutTypes.GUID, + field -> this.row.writeSparseGuid(this.cursor, field, UpdateOptions.UPSERT) + ); } /** @@ -220,8 +239,21 @@ public final class RowWriter { * @return {@link Result#SUCCESS} if the write is successful, an error {@link Result} otherwise. */ public Result writeInt16(UtfAnyString path, short value) { - return this.writePrimitive(path, value, LayoutTypes.INT_16, (Short v) -> - this.row.writeSparseInt16(this.cursor, v, UpdateOptions.UPSERT)); + return this.writePrimitive(path, value, LayoutTypes.INT_16, + field -> this.row.writeSparseInt16(this.cursor, field, UpdateOptions.UPSERT) + ); + } + + /** + * Write a field as a fixed length, 32-bit, signed integer. + * + * @param path The scope-relative path of the field to write. + * @param value The value to write. + * @return {@link Result#SUCCESS} if the write is successful, an error {@link Result} otherwise. + */ + public Result writeInt32(UtfAnyString path, int value) { + return this.writePrimitive(path, value, LayoutTypes.INT_32, + field -> this.row.writeSparseInt32(this.cursor, field, UpdateOptions.UPSERT)); } /** @@ -232,8 +264,9 @@ public final class RowWriter { * @return {@link Result#SUCCESS} if the write is successful, an error {@link Result} otherwise. */ public Result writeInt64(UtfAnyString path, long value) { - return this.writePrimitive(path, value, LayoutTypes.INT_64, (Long v) -> - this.row.writeSparseInt64(this.cursor, v, UpdateOptions.UPSERT)); + return this.writePrimitive(path, value, LayoutTypes.INT_64, + field -> this.row.writeSparseInt64(this.cursor, field, UpdateOptions.UPSERT) + ); } /** @@ -244,19 +277,9 @@ public final class RowWriter { * @return {@link Result#SUCCESS} if the write is successful, an error {@link Result} otherwise. */ public Result writeInt8(UtfAnyString path, byte value) { - return this.writePrimitive(path, value, LayoutTypes.INT_8, (Byte v) -> - this.row.writeSparseInt8(this.cursor, v, UpdateOptions.UPSERT)); - } - - /** - * Write a field as a {@code null}. - * - * @param path The scope-relative path of the field to write. - * @return {@link Result#SUCCESS} if the write is successful, an error {@link Result} otherwise. - */ - public Result writeNull(UtfAnyString path) { - return this.writePrimitive(path, NullValue.DEFAULT, LayoutTypes.NULL, (NullValue v) -> - this.row.writeSparseNull(this.cursor, v, UpdateOptions.UPSERT)); + return this.writePrimitive(path, value, LayoutTypes.INT_8, + field -> this.row.writeSparseInt8(this.cursor, field, UpdateOptions.UPSERT) + ); } // TODO: DANOBLE: Resurrect this method @@ -272,185 +295,100 @@ public final class RowWriter { // // return this.writePrimitive(path, value, LayoutTypes.MongoDbObjectId, (ref RowWriter w, MongoDbObjectId v) -> w.row.writeSparseMongoDbObjectId(ref w.cursor, v, UpdateOptions.UPSERT)); // } - public Result WriteScope( - UtfAnyString path, TypeArgument typeArg, TContext context, WriterFunc func) { + /** + * Write a field as a {@code null}. + * + * @param path The scope-relative path of the field to write. + * @return {@link Result#SUCCESS} if the write is successful, an error {@link Result} otherwise. + */ + public Result writeNull(UtfAnyString path) { + return this.writePrimitive(path, NullValue.DEFAULT, LayoutTypes.NULL, + field -> this.row.writeSparseNull(this.cursor, field, UpdateOptions.UPSERT) + ); + } - LayoutType type = typeArg.type(); + public Result writeScope( + @Nonnull final UtfAnyString path, + @Nonnull final TypeArgument typeArg, + @Nullable final TContext context, + @Nullable final WriterFunc func) { + + checkNotNull(path, "expected non-null path"); + checkNotNull(typeArg, "expected non-null typeArg"); Result result = this.prepareSparseWrite(path, typeArg); + if (result != Result.SUCCESS) { return result; } - RowCursor nestedScope = new RowCursor(); - switch (type) { - // TODO: C# TO JAVA CONVERTER: Java has no equivalent to C# pattern variables in 'case' statements: - //ORIGINAL LINE: case LayoutObject scopeType: - case LayoutObject - scopeType: - Reference tempReference_cursor = - new Reference(this.cursor); - Out tempOut_nestedScope = - new Out(); - this.row.writeSparseObject(tempRef_cursor, scopeType, UpdateOptions.UPSERT); - nestedScope = tempOut_nestedScope.get(); - this.cursor = tempRef_cursor.argValue; - break; - // TODO: C# TO JAVA CONVERTER: Java has no equivalent to C# pattern variables in 'case' statements: - //ORIGINAL LINE: case LayoutArray scopeType: - case LayoutArray - scopeType: - Reference tempReference_cursor2 = - new Reference(this.cursor); - Out tempOut_nestedScope2 = - new Out(); - this.row.writeSparseArray(tempRef_cursor2, scopeType, UpdateOptions.UPSERT); - nestedScope = tempOut_nestedScope2.get(); - this.cursor = tempRef_cursor2.argValue; - break; - // TODO: C# TO JAVA CONVERTER: Java has no equivalent to C# pattern variables in 'case' statements: - //ORIGINAL LINE: case LayoutTypedArray scopeType: - case LayoutTypedArray - scopeType: - Reference tempReference_cursor3 = - new Reference(this.cursor); - Out tempOut_nestedScope3 = - new Out(); - this.row.writeTypedArray(tempRef_cursor3, scopeType, typeArg.typeArgs(), - UpdateOptions.UPSERT, tempOut_nestedScope3); - nestedScope = tempOut_nestedScope3.get(); - this.cursor = tempRef_cursor3.argValue; + final UpdateOptions options = UpdateOptions.UPSERT; + final LayoutType type = typeArg.type(); + final RowCursor nestedScope; - break; - // TODO: C# TO JAVA CONVERTER: Java has no equivalent to C# pattern variables in 'case' statements: - //ORIGINAL LINE: case LayoutTuple scopeType: - case LayoutTuple - scopeType: - Reference tempReference_cursor4 = - new Reference(this.cursor); - Out tempOut_nestedScope4 = - new Out(); - this.row.writeSparseTuple(tempRef_cursor4, scopeType, typeArg.typeArgs(), - UpdateOptions.UPSERT, tempOut_nestedScope4); - nestedScope = tempOut_nestedScope4.get(); - this.cursor = tempRef_cursor4.argValue; + if (type instanceof LayoutObject) { - break; - // TODO: C# TO JAVA CONVERTER: Java has no equivalent to C# pattern variables in 'case' statements: - //ORIGINAL LINE: case LayoutTypedTuple scopeType: - case LayoutTypedTuple - scopeType: - Reference tempReference_cursor5 = - new Reference(this.cursor); - Out tempOut_nestedScope5 = - new Out(); - this.row.writeTypedTuple(tempRef_cursor5, scopeType, typeArg.typeArgs(), - UpdateOptions.UPSERT); - nestedScope = tempOut_nestedScope5.get(); - this.cursor = tempRef_cursor5.argValue; + nestedScope = this.row.writeSparseObject(this.cursor, (LayoutObject) type, options); - break; - // TODO: C# TO JAVA CONVERTER: Java has no equivalent to C# pattern variables in 'case' statements: - //ORIGINAL LINE: case LayoutTagged scopeType: - case LayoutTagged - scopeType: - Reference tempReference_cursor6 = - new Reference(this.cursor); - Out tempOut_nestedScope6 = - new Out(); - this.row.writeTypedTuple(tempRef_cursor6, scopeType, typeArg.typeArgs(), - UpdateOptions.UPSERT); - nestedScope = tempOut_nestedScope6.get(); - this.cursor = tempRef_cursor6.argValue; + } else if (type instanceof LayoutArray) { - break; - // TODO: C# TO JAVA CONVERTER: Java has no equivalent to C# pattern variables in 'case' statements: - //ORIGINAL LINE: case LayoutTagged2 scopeType: - case LayoutTagged2 - scopeType: - Reference tempReference_cursor7 = - new Reference(this.cursor); - Out tempOut_nestedScope7 = - new Out(); - this.row.writeTypedTuple(tempRef_cursor7, scopeType, typeArg.typeArgs(), - UpdateOptions.UPSERT); - nestedScope = tempOut_nestedScope7.get(); - this.cursor = tempRef_cursor7.argValue; + nestedScope = this.row.writeSparseArray(this.cursor, (LayoutArray) type, options); - break; - // TODO: C# TO JAVA CONVERTER: Java has no equivalent to C# pattern variables in 'case' statements: - //ORIGINAL LINE: case LayoutNullable scopeType: - case LayoutNullable - scopeType: - Reference tempReference_cursor8 = - new Reference(this.cursor); - Out tempOut_nestedScope8 = - new Out(); - this.row.writeNullable(tempRef_cursor8, scopeType, typeArg.typeArgs(), - UpdateOptions.UPSERT, func != null); - nestedScope = tempOut_nestedScope8.get(); - this.cursor = tempRef_cursor8.argValue; + } else if (type instanceof LayoutTypedArray) { - break; - // TODO: C# TO JAVA CONVERTER: Java has no equivalent to C# pattern variables in 'case' statements: - //ORIGINAL LINE: case LayoutUDT scopeType: - case LayoutUDT - scopeType: - Layout udt = this.row.resolver().resolve(typeArg.typeArgs().schemaId()); - Reference tempReference_cursor9 = - new Reference(this.cursor); - Out tempOut_nestedScope9 = - new Out(); - this.row.writeSparseUDT(tempReference_cursor9, scopeType, udt, UpdateOptions.UPSERT, tempOut_nestedScope9); - nestedScope = tempOut_nestedScope9.get(); - this.cursor = tempReference_cursor9.get(); - break; + nestedScope = this.row.writeTypedArray(this.cursor, (LayoutTypedArray) type, typeArg.typeArgs(), options); - // TODO: C# TO JAVA CONVERTER: Java has no equivalent to C# pattern variables in 'case' statements: - //ORIGINAL LINE: case LayoutTypedSet scopeType: - case LayoutTypedSet - scopeType: - Reference tempReference_cursor10 = - new Reference(this.cursor); - Out tempOut_nestedScope10 = - new Out(); - this.row.writeTypedSet(tempRef_cursor10, scopeType, typeArg.typeArgs(), - UpdateOptions.UPSERT); - nestedScope = tempOut_nestedScope10.get(); - this.cursor = tempRef_cursor10.argValue; + } else if (type instanceof LayoutTuple) { - break; - // TODO: C# TO JAVA CONVERTER: Java has no equivalent to C# pattern variables in 'case' statements: - //ORIGINAL LINE: case LayoutTypedMap scopeType: - case LayoutTypedMap - scopeType: - Reference tempReference_cursor11 = - new Reference(this.cursor); - Out tempOut_nestedScope11 = - new Out(); - this.row.writeTypedMap(tempRef_cursor11, scopeType, typeArg.typeArgs(), - UpdateOptions.UPSERT); - nestedScope = tempOut_nestedScope11.get(); - this.cursor = tempRef_cursor11.argValue; + nestedScope = this.row.writeSparseTuple(this.cursor, (LayoutTuple) type, typeArg.typeArgs(), options); - break; + } else if (type instanceof LayoutTypedTuple) { - default: - return Result.FAILURE; + nestedScope = this.row.writeTypedTuple(this.cursor, (LayoutTypedTuple) type, typeArg.typeArgs(), options); + + } else if (type instanceof LayoutTagged) { + + nestedScope = this.row.writeTypedTuple(this.cursor, (LayoutTagged) type, typeArg.typeArgs(), options); + + } else if (type instanceof LayoutTagged2) { + + nestedScope = this.row.writeTypedTuple(this.cursor, (LayoutTagged2) type, typeArg.typeArgs(), options); + + } else if (type instanceof LayoutNullable) { + + nestedScope = this.row.writeNullable(this.cursor, (LayoutNullable) type, typeArg.typeArgs(), options, + func != null); + + } else if (type instanceof LayoutUDT) { + + LayoutUDT scopeType = (LayoutUDT) type; + Layout udt = this.row.resolver().resolve(typeArg.typeArgs().schemaId()); + nestedScope = this.row.writeSparseUDT(this.cursor, scopeType, udt, options); + + } else if (type instanceof LayoutTypedSet) { + + LayoutTypedSet scopeType = (LayoutTypedSet) type; + nestedScope = this.row.writeTypedSet(this.cursor, scopeType, typeArg.typeArgs(), options); + + } else if (type instanceof LayoutTypedMap) { + + LayoutTypedMap scopeType = (LayoutTypedMap) type; + nestedScope = this.row.writeTypedMap(this.cursor, scopeType, typeArg.typeArgs(), options); + + } else { + + throw new IllegalStateException(lenientFormat("expected type argument of %s, not %s", + LayoutTypeScope.class, + type.getClass())); + } + + RowWriter nestedWriter = new RowWriter(this.row, nestedScope); + result = func == null ? null : func.invoke(nestedWriter, typeArg, context); + + if (result == null) { + result = Result.SUCCESS; } - Reference tempReference_row = - new Reference(this.row); - Reference tempReference_nestedScope = - new Reference(nestedScope); - RowWriter nestedWriter = new RowWriter(tempReference_row, tempReference_nestedScope); - nestedScope = tempReference_nestedScope.get(); - this.row = tempReference_row.get(); - Reference tempReference_nestedWriter = - new Reference(nestedWriter); - // TODO: C# TO JAVA CONVERTER: The following line could not be converted: - result = func == null ? null : func.Invoke(ref nestedWriter, typeArg, context) ??Result.SUCCESS; - nestedWriter = tempReference_nestedWriter.get(); this.row = nestedWriter.row; nestedScope.count(nestedWriter.cursor.count()); @@ -460,39 +398,17 @@ public final class RowWriter { } if (type instanceof LayoutUniqueScope) { - Reference tempReference_nestedScope2 = - new Reference(nestedScope); - result = this.row.typedCollectionUniqueIndexRebuild(tempReference_nestedScope2); - nestedScope = tempReference_nestedScope2.get(); + result = this.row.typedCollectionUniqueIndexRebuild(nestedScope); if (result != Result.SUCCESS) { // TODO: If the index rebuild fails then the row is corrupted. Should we automatically clean up here? return result; } } - Reference tempReference_row2 = - new Reference(this.row); - Reference tempReference_cursor12 = - new Reference(nestedWriter.cursor); - RowCursors.moveNext(this.cursor, tempReference_row2 - , tempReference_cursor12); - nestedWriter.cursor = tempReference_cursor12.get(); - this.row = tempReference_row2.get(); + RowCursors.moveNext(this.cursor, this.row, nestedWriter.cursor); return Result.SUCCESS; } - /** - * Write a field as a fixed length, 32-bit, signed integer. - * - * @param path The scope-relative path of the field to write. - * @param value The value to write. - * @return {@link Result#SUCCESS} if the write is successful, an error {@link Result} otherwise. - */ - public Result writeInt32(UtfAnyString path, int value) { - return this.writePrimitive(path, value, LayoutTypes.INT_32, (RowWriter writer, int v) -> - writer.row.writeSparseInt32(writer.cursor, v, UpdateOptions.UPSERT)); - } - /** * Write a field as a variable length, UTF8 encoded, string value. * @@ -501,12 +417,16 @@ public final class RowWriter { * @return {@link Result#SUCCESS} if the write is successful, an error {@link Result} otherwise. */ public Result writeString(UtfAnyString path, String value) { + // TODO: DANOBLE: RowBuffer should support writing String values directly (without conversion to Utf8String) + Utf8String string = Utf8String.transcodeUtf16(value); assert string != null; + try { - return this.writePrimitive(path, value, LayoutTypes.UTF_8, (RowWriter writer, String v) -> - writer.row.writeSparseString(writer.cursor, string, UpdateOptions.UPSERT)); + return this.writePrimitive(path, value, LayoutTypes.UTF_8, + field -> this.row.writeSparseString(this.cursor, string, UpdateOptions.UPSERT) + ); } finally { string.release(); } @@ -520,8 +440,11 @@ public final class RowWriter { * @return {@link Result#SUCCESS} if the write is successful, an error {@link Result} otherwise. */ public Result writeString(UtfAnyString path, Utf8String value) { - return this.writePrimitive(path, value, LayoutTypes.UTF_8, (RowWriter writer, Utf8String v) -> - writer.row.writeSparseString(writer.cursor, v, UpdateOptions.UPSERT)); + // TODO: DANOBLE: BUG FIX: this.writePrimitive should write Utf8String as well as String + // note incorrect use of string "value" as the value argument + return this.writePrimitive(path, "value", LayoutTypes.UTF_8, + field -> this.row.writeSparseString(this.cursor, value, UpdateOptions.UPSERT) + ); } /** @@ -532,8 +455,9 @@ public final class RowWriter { * @return {@link Result#SUCCESS} if the write is successful, an error {@link Result} otherwise. */ public Result writeUInt16(UtfAnyString path, short value) { - return this.writePrimitive(path, value, LayoutTypes.UINT_16, (RowWriter writer, short v) -> - writer.row.writeSparseUInt16(writer.cursor, v, UpdateOptions.UPSERT)); + return this.writePrimitive(path, (int) value, LayoutTypes.UINT_16, + field -> this.row.writeSparseUInt16(this.cursor, field.shortValue(), UpdateOptions.UPSERT) + ); } /** @@ -543,9 +467,10 @@ public final class RowWriter { * @param value The value to write. * @return {@link Result#SUCCESS} if the write is successful, an error {@link Result} otherwise. */ - public Result writeUInt32(UtfAnyString path, int value) { - return this.writePrimitive(path, value, LayoutTypes.UINT_32, (RowWriter writer, int v) -> - writer.row.writeSparseUInt32(writer.cursor, v, UpdateOptions.UPSERT)); + public Result writeUInt32(UtfAnyString path, long value) { + return this.writePrimitive(path, value, LayoutTypes.UINT_32, field -> + this.row.writeSparseUInt32(this.cursor, field.intValue(), UpdateOptions.UPSERT) + ); } /** @@ -556,8 +481,9 @@ public final class RowWriter { * @return {@link Result#SUCCESS} if the write is successful, an error {@link Result} otherwise. */ public Result writeUInt64(UtfAnyString path, long value) { - return this.writePrimitive(path, value, LayoutTypes.UINT_64, (RowWriter writer, long v) -> - writer.row.writeSparseUInt64(writer.cursor, v, UpdateOptions.UPSERT)); + return this.writePrimitive(path, value, LayoutTypes.UINT_64, field -> + this.row.writeSparseUInt64(this.cursor, field, UpdateOptions.UPSERT) + ); } /** @@ -568,8 +494,9 @@ public final class RowWriter { * @return {@link Result#SUCCESS} if the write is successful, an error {@link Result} otherwise. */ public Result writeUInt8(UtfAnyString path, byte value) { - return this.writePrimitive(path, value, LayoutTypes.UINT_8, (RowWriter writer, byte v) -> - writer.row.writeSparseUInt8(writer.cursor, v, UpdateOptions.UPSERT)); + return this.writePrimitive(path, (short) value, LayoutTypes.UINT_8, + field -> this.row.writeSparseUInt8(this.cursor, field.byteValue(), UpdateOptions.UPSERT) + ); } /** @@ -580,8 +507,9 @@ public final class RowWriter { * @return {@link Result#SUCCESS} if the write is successful, an error {@link Result} otherwise. */ public Result writeUnixDateTime(UtfAnyString path, UnixDateTime value) { - return this.writePrimitive(path, value, LayoutTypes.UNIX_DATE_TIME, (RowWriter writer, UnixDateTime v) -> - writer.row.writeSparseUnixDateTime(writer.cursor, v, UpdateOptions.UPSERT)); + return this.writePrimitive(path, value, LayoutTypes.UNIX_DATE_TIME, + field -> this.row.writeSparseUnixDateTime(this.cursor, field, UpdateOptions.UPSERT) + ); } /** @@ -592,8 +520,9 @@ public final class RowWriter { * @return {@link Result#SUCCESS} if the write is successful, an error {@link Result} otherwise. */ public Result writeVarInt(UtfAnyString path, long value) { - return this.writePrimitive(path, value, LayoutTypes.VAR_INT, (RowWriter writer, long v) -> - writer.row.writeSparseVarInt(writer.cursor, v, UpdateOptions.UPSERT)); + return this.writePrimitive(path, value, LayoutTypes.VAR_INT, + field -> this.row.writeSparseVarInt(this.cursor, field, UpdateOptions.UPSERT) + ); } /** @@ -604,8 +533,9 @@ public final class RowWriter { * @return {@link Result#SUCCESS} if the write is successful, an error {@link Result} otherwise. */ public Result writeVarUInt(UtfAnyString path, long value) { - return this.writePrimitive(path, value, LayoutTypes.VAR_UINT, (RowWriter writer, long v) -> - writer.row.writeSparseVarUInt(writer.cursor, v, UpdateOptions.UPSERT)); + return this.writePrimitive(path, value, LayoutTypes.VAR_UINT, + field -> this.row.writeSparseVarUInt(this.cursor, field, UpdateOptions.UPSERT) + ); } /** @@ -616,18 +546,14 @@ public final class RowWriter { * @return Success if the write is permitted, the error code otherwise. */ private Result prepareSparseWrite(UtfAnyString path, TypeArgument typeArg) { + if (this.cursor.scopeType().isFixedArity() && !(this.cursor.scopeType() instanceof LayoutNullable)) { if ((this.cursor.index() < this.cursor.scopeTypeArgs().count()) && !typeArg.equals(this.cursor.scopeTypeArgs().get(this.cursor.index()))) { return Result.TYPE_CONSTRAINT; } } else if (this.cursor.scopeType() instanceof LayoutTypedMap) { - Reference tempReference_cursor = - new Reference(this.cursor); - if (!typeArg.equals(this.cursor.scopeType().typeAs().fieldType(tempReference_cursor))) { - this.cursor = tempReference_cursor.get(); + if (!typeArg.equals(this.cursor.scopeType().typeAs().fieldType(this.cursor))) { return Result.TYPE_CONSTRAINT; - } else { - this.cursor = tempReference_cursor.get(); } } else if (this.cursor.scopeType().isTypedScope() && !typeArg.equals(this.cursor.scopeTypeArgs().get(0))) { return Result.TYPE_CONSTRAINT; @@ -637,6 +563,7 @@ public final class RowWriter { return Result.SUCCESS; } + // TODO: DANOBLE: Does Java implementation need this method? /** * Helper for writing a primitive value. * @@ -647,8 +574,8 @@ public final class RowWriter { * @param sparse The {@link RowBuffer} access method for {@code type}. * @return {@link Result#SUCCESS} if the write is successful, an error {@link Result} otherwise. */ - private & LayoutUtf8Writable> - Result writePrimitive(UtfAnyString path, Utf8String value, TLayoutType type, AccessUtf8SpanMethod sparse) { + private + Result writePrimitive(UtfAnyString path, Utf8String value, TLayoutType type, Consumer sparse) { Result result = Result.NOT_FOUND; @@ -657,61 +584,51 @@ public final class RowWriter { } if (result == Result.NOT_FOUND) { - // Write sparse value. + result = this.prepareSparseWrite(path, type.typeArg()); + if (result != Result.SUCCESS) { return result; } - Reference tempReference_this = - new Reference(this); - // TODO: C# TO JAVA CONVERTER: The following line could not be converted: - sparse(ref this, value) - this = tempReference_this.get(); - Reference tempReference_row = - new Reference(this.row); - RowCursors.moveNext(this.cursor, - tempReference_row); - this.row = tempReference_row.get(); + sparse.accept(value); + RowCursors.moveNext(this.cursor, this.row); } return result; } + // TODO: DANOBLE: Does Java implementation need this method? /** * Helper for writing a primitive value. * * @param The type of layout type. - * @param The sub-element type of the field. + * @param The sub-element type of the field. * @param path The scope-relative path of the field to write. * @param value The value to write. * @param type The layout type. * @param sparse The {@link RowBuffer} access method for {@code type}. * @return {@link Result#SUCCESS} if the write is successful, an error {@link Result} otherwise. */ - private & LayoutListWritable, TElement> Result writePrimitive(UtfAnyString path, ReadOnlySpan value, TLayoutType type, AccessReadOnlySpanMethod sparse) { + private , TValue> + Result writePrimitiveList(UtfAnyString path, List value, TLayoutType type, Consumer> sparse) { + Result result = Result.NOT_FOUND; + if (this.cursor.scopeType() instanceof LayoutUDT) { result = this.writeSchematizedValue(path, value); } if (result == Result.NOT_FOUND) { - // Write sparse value. + result = this.prepareSparseWrite(path, type.typeArg()); + if (result != Result.SUCCESS) { return result; } - Reference tempReference_this = - new Reference(this); - // TODO: C# TO JAVA CONVERTER: The following line could not be converted: - sparse(ref this, value) - this = tempReference_this.get(); - Reference tempReference_row = - new Reference(this.row); - RowCursors.moveNext(this.cursor, - tempReference_row); - this.row = tempReference_row.get(); + sparse.accept(value); + RowCursors.moveNext(this.cursor, this.row); } return result; @@ -744,7 +661,7 @@ public final class RowWriter { return result; } - sparse.accept(this, value); + sparse.accept(value); RowCursors.moveNext(this.cursor, this.row); } @@ -760,36 +677,33 @@ public final class RowWriter { * @return {@link Result#SUCCESS} if the write is successful, an error {@link Result} otherwise. */ private Result writeSchematizedValue(UtfAnyString path, TValue value) { - LayoutColumn col; - // TODO: C# TO JAVA CONVERTER: The following method call contained an unresolved 'out' keyword - these - // cannot be converted using the 'Out' helper class unless the method is within the code being modified: - if (!this.cursor.layout().tryFind(path, out col)) { + + final Optional column = this.cursor.layout().tryFind(path); + + if (!column.isPresent()) { return Result.NOT_FOUND; } - boolean tempVar = col.type() instanceof LayoutType; - LayoutType t = tempVar ? (LayoutType)col.type() : null; - if (!(tempVar)) { + // TODO: DANOBLE: Add a mechanism for performing the equivalent of this type check + // if (!(column.Type is LayoutTypePrimitive t)) { + // return Result.NotFound; + // } + // Type erasure prevents this test: + // column.type instanceof LayoutTypePrimitive + // Reason: Runtime does not instantiate or otherwise represent or identify instances of a generic type. + + if (!(column.get().type() instanceof LayoutTypePrimitive)) { return Result.NOT_FOUND; } - switch (col.storage()) { - case StorageKind.FIXED: - Reference tempReference_row = - new Reference(this.row); - Result tempVar2 = t.writeFixed(ref this.row, ref this.cursor, col, value) - this.row = tempReference_row.get(); - return tempVar2; + @SuppressWarnings("unchecked") + LayoutTypePrimitive type = (LayoutTypePrimitive)column.get().type(); - case StorageKind.VARIABLE: - Reference tempReference_row2 = - new Reference(this.row); - Result tempVar3 = t.writeVariable(ref this.row, ref this.cursor, col, value) - this.row = tempReference_row2.get(); - return tempVar3; - - default: - return Result.NOT_FOUND; + switch (column.get().storage()) { + case FIXED: + return type.writeFixed(this.row, this.cursor, column.get(), value); + case VARIABLE: + return type.writeVariable(this.row, this.cursor, column.get(), value); } return Result.NOT_FOUND; @@ -803,150 +717,74 @@ public final class RowWriter { * @return {@link Result#SUCCESS} if the write is successful, an error {@link Result} otherwise. */ private Result writeSchematizedValue(UtfAnyString path, Utf8String value) { - LayoutColumn col; - // TODO: C# TO JAVA CONVERTER: The following method call contained an unresolved 'out' keyword - these - // cannot be converted using the 'Out' helper class unless the method is within the code being modified: - if (!this.cursor.layout().tryFind(path, out col)) { + + final Optional column = this.cursor.layout().tryFind(path); + + if (!column.isPresent()) { return Result.NOT_FOUND; } - LayoutType t = col.type(); - if (!(t instanceof ILayoutUtf8SpanWritable)) { + final LayoutType type = column.get().type(); + + if (!(type instanceof LayoutUtf8Writable)) { return Result.NOT_FOUND; } - switch (col.storage()) { - case StorageKind.FIXED: - Reference tempReference_row = - new Reference(this.row); - Reference tempReference_cursor = - new Reference(this.cursor); - Result tempVar = t.typeAs().writeFixed(tempReference_row, tempReference_cursor, col, - value); - this.cursor = tempReference_cursor.get(); - this.row = tempReference_row.get(); - return tempVar; - case StorageKind.VARIABLE: - Reference tempReference_row2 = - new Reference(this.row); - Reference tempReference_cursor2 = - new Reference(this.cursor); - Result tempVar2 = t.typeAs().writeVariable(tempReference_row2, - tempReference_cursor2, - col, value); - this.cursor = tempReference_cursor2.get(); - this.row = tempReference_row2.get(); - return tempVar2; - default: - return Result.NOT_FOUND; + switch (column.get().storage()) { + case FIXED: + return type.typeAs().writeFixed(this.row, this.cursor, column.get(), value); + case VARIABLE: + return type.typeAs().writeVariable(this.row, this.cursor, column.get(), value); } + + return Result.NOT_FOUND; } /** * Write a generic schematized field value via the scope's layout. - * @param The sub-element type of the field. * - * @param path The scope-relative path of the field to write. - * @param value The value to write. + * @param The sub-element type of the field. + * @param path The scope-relative path of the field to write. + * @param value The value to write. * @return {@link Result#SUCCESS} if the write is successful, an error {@link Result} otherwise. */ - private Result writeSchematizedValue(UtfAnyString path, ReadOnlySpan value) { - LayoutColumn col; - // TODO: C# TO JAVA CONVERTER: The following method call contained an unresolved 'out' keyword - these cannot be converted using the 'Out' helper class unless the method is within the code being modified: - if (!this.cursor.layout().tryFind(path, out col)) { + private Result writeSchematizedValue(UtfAnyString path, List value) { + + final Optional column = this.cursor.layout().tryFind(path); + + if (!column.isPresent()) { return Result.NOT_FOUND; } - LayoutType t = col.type(); - if (!(t instanceof ILayoutSpanWritable)) { + final LayoutType type = column.get().type(); + + if (!(type instanceof LayoutListWritable)) { return Result.NOT_FOUND; } - switch (col.storage()) { - case StorageKind.FIXED: - Reference tempReference_row = new Reference(this.row); - Reference tempReference_cursor = new Reference(this.cursor); - Result tempVar = t.>typeAs().writeFixed(tempReference_row, tempReference_cursor, col, value); - this.cursor = tempReference_cursor.get(); - this.row = tempReference_row.get(); - return tempVar; - case StorageKind.VARIABLE: - Reference tempReference_row2 = new Reference(this.row); - Reference tempReference_cursor2 = new Reference(this.cursor); - Result tempVar2 = t.>typeAs().writeVariable(tempReference_row2, tempReference_cursor2, col, value); - this.cursor = tempReference_cursor2.get(); - this.row = tempReference_row2.get(); - return tempVar2; - default: - return Result.NOT_FOUND; + switch (column.get().storage()) { + case FIXED: + return type.>typeAs().writeFixedList(this.row, this.cursor, column.get(), value); + case VARIABLE: + return type.>typeAs().writeVariableList(this.row, this.cursor, column.get(), value); } + + return Result.NOT_FOUND; } /** - * Write a generic schematized field value via the scope's layout. - * @param The sub-element type of the field. - * - * @param path The scope-relative path of the field to write. - * @param value The value to write. - * @return {@link Result#SUCCESS} if the write is successful, an error {@link Result} otherwise. - */ - private Result writeSchematizedValue(UtfAnyString path, ReadOnlySequence value) { - LayoutColumn col; - // TODO: C# TO JAVA CONVERTER: The following method call contained an unresolved 'out' keyword - these cannot be converted using the 'Out' helper class unless the method is within the code being modified: - if (!this.cursor.layout().tryFind(path, out col)) { - return Result.NOT_FOUND; - } - - LayoutType t = col.type(); - if (!(t instanceof ILayoutSequenceWritable)) { - return Result.NOT_FOUND; - } - - switch (col.storage()) { - case StorageKind.FIXED: - Reference tempReference_row = new Reference(this.row); - Reference tempReference_cursor = new Reference(this.cursor); - Result tempVar = t.>typeAs().writeFixed(tempReference_row, tempReference_cursor, col, value); - this.cursor = tempReference_cursor.get(); - this.row = tempReference_row.get(); - return tempVar; - case StorageKind.VARIABLE: - Reference tempReference_row2 = new Reference(this.row); - Reference tempReference_cursor2 = new Reference(this.cursor); - Result tempVar2 = t.>typeAs().writeVariable(tempReference_row2, tempReference_cursor2, col, value); - this.cursor = tempReference_cursor2.get(); - this.row = tempReference_row2.get(); - return tempVar2; - default: - return Result.NOT_FOUND; - } - } - - @FunctionalInterface - private interface AccessMethod extends Consumer { - } - - @FunctionalInterface - private interface AccessReadOnlySpanMethod { - void invoke(RowWriter writer, ReadOnlySpan value); - } - - @FunctionalInterface - private interface AccessUtf8SpanMethod { - void invoke(RowWriter writer, Utf8String value); - } - - /** - * A function to write content into a {@link RowBuffer}. - * @param The type of the context value passed by the caller. - * - * @param writer A forward-only cursor for writing content. - * @param typeArg The type of the current scope. - * @param context A context value provided by the caller. - * @return The result. + * Functional interface for writing content to a {@link RowBuffer}. */ @FunctionalInterface public interface WriterFunc { + /** + * Write content using the specified writer, type argument, and context. + * + * @param writer writes content. + * @param typeArg specifies a type argument. + * @param context provides context for the write operation. + * @return a result code + */ Result invoke(RowWriter writer, TypeArgument typeArg, TContext context); } } \ No newline at end of file diff --git a/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/layouts/LayoutBinary.java b/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/layouts/LayoutBinary.java index 298672d..fe3862f 100644 --- a/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/layouts/LayoutBinary.java +++ b/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/layouts/LayoutBinary.java @@ -16,7 +16,7 @@ import javax.annotation.Nonnull; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; -public final class LayoutBinary extends LayoutTypePrimitive { +public final class LayoutBinary extends LayoutTypePrimitive { // implements // LayoutListWritable, // LayoutListReadable, @@ -41,7 +41,7 @@ public final class LayoutBinary extends LayoutTypePrimitive { @Nonnull final RowBuffer buffer, @Nonnull final RowCursor scope, @Nonnull final LayoutColumn column, - @Nonnull final Out value) { + @Nonnull final Out value) { checkNotNull(buffer, "expected non-null buffer"); checkNotNull(scope, "expected non-null scope"); @@ -56,14 +56,14 @@ public final class LayoutBinary extends LayoutTypePrimitive { return Result.NOT_FOUND; } - value.set(ByteBufUtil.getBytes(buffer.readFixedBinary(scope.start() + column.offset(), column.size()))); + value.set(buffer.readFixedBinary(scope.start() + column.offset(), column.size())); return Result.SUCCESS; } @Override @Nonnull public Result readSparse( - @Nonnull final RowBuffer buffer, @Nonnull final RowCursor edit, @Nonnull final Out value) { + @Nonnull final RowBuffer buffer, @Nonnull final RowCursor edit, @Nonnull final Out value) { checkNotNull(buffer, "expected non-null buffer"); checkNotNull(edit, "expected non-null edit"); @@ -76,7 +76,7 @@ public final class LayoutBinary extends LayoutTypePrimitive { return result; } - value.set(ByteBufUtil.getBytes(buffer.readSparseBinary(edit))); + value.set(buffer.readSparseBinary(edit)); return Result.SUCCESS; } @@ -86,7 +86,7 @@ public final class LayoutBinary extends LayoutTypePrimitive { @Nonnull RowBuffer buffer, @Nonnull RowCursor scope, @Nonnull LayoutColumn column, - @Nonnull Out value) { + @Nonnull Out value) { checkNotNull(buffer, "expected non-null buffer"); checkNotNull(scope, "expected non-null scope"); @@ -101,7 +101,7 @@ public final class LayoutBinary extends LayoutTypePrimitive { } final int valueOffset = buffer.computeVariableValueOffset(scope.layout(), scope.start(), column.offset()); - value.set(ByteBufUtil.getBytes(buffer.readVariableBinary(valueOffset))); + value.set(buffer.readVariableBinary(valueOffset)); return Result.SUCCESS; } @@ -112,7 +112,7 @@ public final class LayoutBinary extends LayoutTypePrimitive { @Nonnull RowBuffer buffer, @Nonnull RowCursor scope, @Nonnull LayoutColumn column, - @Nonnull byte[] value) { + @Nonnull ByteBuf value) { checkNotNull(buffer, "expected non-null buffer"); checkNotNull(scope, "expected non-null scope"); @@ -121,23 +121,21 @@ public final class LayoutBinary extends LayoutTypePrimitive { checkArgument(scope.scopeType() instanceof LayoutUDT); checkArgument(column.size() >= 0); - checkArgument(value.length == column.size()); if (scope.immutable()) { return Result.INSUFFICIENT_PERMISSIONS; } - final ByteBuf valueBuffer = Unpooled.wrappedBuffer(value).asReadOnly(); final int valueOffset = scope.start() + column.offset(); buffer.setBit(scope.start(), column.nullBit()); - buffer.writeFixedBinary(valueOffset, valueBuffer, column.size()); + buffer.writeFixedBinary(valueOffset, value, column.size()); return Result.SUCCESS; } @Override @Nonnull - public Result writeSparse(@Nonnull RowBuffer buffer, @Nonnull RowCursor edit, @Nonnull byte[] value) { + public Result writeSparse(@Nonnull RowBuffer buffer, @Nonnull RowCursor edit, @Nonnull ByteBuf value) { return this.writeSparse(buffer, edit, value, UpdateOptions.UPSERT); } @@ -146,16 +144,21 @@ public final class LayoutBinary extends LayoutTypePrimitive { public Result writeSparse( @Nonnull RowBuffer buffer, @Nonnull RowCursor edit, - @Nonnull byte[] value, + @Nonnull ByteBuf value, @Nonnull UpdateOptions options) { + checkNotNull(buffer, "expected non-null buffer"); + checkNotNull(edit, "expected non-null edit"); + checkNotNull(value, "expected non-null value"); + checkNotNull(options, "expected non-null options"); + Result result = LayoutType.prepareSparseWrite(buffer, edit, this.typeArg(), options); if (result != Result.SUCCESS) { return result; } - buffer.writeSparseBinary(edit, Unpooled.wrappedBuffer(value).asReadOnly(), options); + buffer.writeSparseBinary(edit, value, options); return Result.SUCCESS; } @@ -165,7 +168,12 @@ public final class LayoutBinary extends LayoutTypePrimitive { @Nonnull RowBuffer buffer, @Nonnull RowCursor scope, @Nonnull LayoutColumn column, - @Nonnull byte[] value) { + @Nonnull ByteBuf value) { + + checkNotNull(buffer, "expected non-null buffer"); + checkNotNull(scope, "expected non-null scope"); + checkNotNull(column, "expected non-null column"); + checkNotNull(value, "expected non-null value"); checkArgument(scope.scopeType() instanceof LayoutUDT); @@ -173,16 +181,15 @@ public final class LayoutBinary extends LayoutTypePrimitive { return Result.INSUFFICIENT_PERMISSIONS; } - if ((column.size() > 0) && (value.length > column.size())) { + if ((column.size() > 0) && (value.readableBytes() > column.size())) { return Result.TOO_BIG; } final boolean exists = buffer.readBit(scope.start(), column.nullBit()); - final ByteBuf valueBuffer = Unpooled.wrappedBuffer(value).asReadOnly(); final int valueOffset = buffer.computeVariableValueOffset(scope.layout(), scope.start(), column.offset()); final Out shift = new Out<>(); - buffer.writeVariableBinary(valueOffset, valueBuffer, exists, shift); + buffer.writeVariableBinary(valueOffset, value, exists, shift); buffer.setBit(scope.start(), column.nullBit()); scope.metaOffset(scope.metaOffset() + shift.get()); scope.valueOffset(scope.valueOffset() + shift.get()); diff --git a/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/layouts/LayoutTypedTuple.java b/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/layouts/LayoutTypedTuple.java index a275661..ea61ba0 100644 --- a/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/layouts/LayoutTypedTuple.java +++ b/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/layouts/LayoutTypedTuple.java @@ -50,7 +50,7 @@ public final class LayoutTypedTuple extends LayoutIndexedScope { @Nonnull final RowBuffer buffer, final int offset, @Nonnull final Out lengthInBytes) { checkNotNull(buffer, "expected non-null buffer"); - lengthInBytes + checkNotNull(lengthInBytes, "expected non-null lengthInBytes"); checkArgument(offset >= 0, "expected non-negative offset, not %s", offset); final int numTypeArgs = (int) buffer.readVariableUInt(offset, lengthInBytes); diff --git a/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/layouts/LayoutUniqueScope.java b/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/layouts/LayoutUniqueScope.java index 39eeb90..940ce1e 100644 --- a/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/layouts/LayoutUniqueScope.java +++ b/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/layouts/LayoutUniqueScope.java @@ -15,7 +15,7 @@ import javax.annotation.Nullable; import static com.google.common.base.Preconditions.checkNotNull; -public abstract class LayoutUniqueScope extends LayoutIndexedScope { +public abstract class LayoutUniqueScope extends LayoutIndexedScope implements ILayoutType { protected LayoutUniqueScope(LayoutCode code, boolean immutable, boolean isSizedScope, boolean isTypedScope) { super(code, immutable, isSizedScope, false, true, isTypedScope); diff --git a/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/layouts/LayoutUtf8.java b/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/layouts/LayoutUtf8.java index 2c0e9bb..aaca359 100644 --- a/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/layouts/LayoutUtf8.java +++ b/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/layouts/LayoutUtf8.java @@ -14,7 +14,8 @@ import javax.annotation.Nonnull; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; -public final class LayoutUtf8 extends LayoutTypePrimitive implements LayoutUtf8Readable, LayoutUtf8Writable { +public final class LayoutUtf8 extends LayoutTypePrimitive + implements LayoutUtf8Readable, LayoutUtf8Writable { public LayoutUtf8() { super(LayoutCode.UTF_8, 0); diff --git a/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/schemas/SchemaHash.java b/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/schemas/SchemaHash.java index 9cc75d3..8cc86f4 100644 --- a/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/schemas/SchemaHash.java +++ b/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/schemas/SchemaHash.java @@ -15,199 +15,199 @@ import static com.google.common.base.Strings.lenientFormat; public final class SchemaHash { - /** - * Computes the logical hash for a logical schema. - * - * @param namespace The namespace within which is defined. - * @param schema The logical schema to compute the hash of. - * @param seed The seed to initialized the hash function. - * @return The logical 128-bit hash as a two-tuple (low, high). - */ - public static HashCode128 computeHash(Namespace namespace, Schema schema, HashCode128 seed) { - HashCode128 hash = seed; + /** + * Computes the logical hash for a logical schema. + * + * @param namespace The namespace within which is defined. + * @param schema The logical schema to compute the hash of. + * @param seed The seed to initialized the hash function. + * @return The logical 128-bit hash as a two-tuple (low, high). + */ + public static HashCode128 computeHash(Namespace namespace, Schema schema, HashCode128 seed) { + HashCode128 hash = seed; - hash = Murmur3Hash.Hash128(schema.schemaId().value(), hash); - hash = Murmur3Hash.Hash128(schema.type().value(), hash); - hash = SchemaHash.computeHash(namespace, schema.options(), hash); + hash = Murmur3Hash.Hash128(schema.schemaId().value(), hash); + hash = Murmur3Hash.Hash128(schema.type().value(), hash); + hash = SchemaHash.computeHash(namespace, schema.options(), hash); - if (schema.partitionKeys() != null) { - for (PartitionKey partitionKey : schema.partitionKeys()) { - hash = SchemaHash.computeHash(namespace, partitionKey, hash); - } - } + if (schema.partitionKeys() != null) { + for (PartitionKey partitionKey : schema.partitionKeys()) { + hash = SchemaHash.computeHash(namespace, partitionKey, hash); + } + } - if (schema.primarySortKeys() != null) { - for (PrimarySortKey p : schema.primarySortKeys()) { - hash = SchemaHash.computeHash(namespace, p, hash); - } - } + if (schema.primarySortKeys() != null) { + for (PrimarySortKey p : schema.primarySortKeys()) { + hash = SchemaHash.computeHash(namespace, p, hash); + } + } - if (schema.staticKeys() != null) { - for (StaticKey p : schema.staticKeys()) { - hash = SchemaHash.computeHash(namespace, p, hash); - } - } + if (schema.staticKeys() != null) { + for (StaticKey p : schema.staticKeys()) { + hash = SchemaHash.computeHash(namespace, p, hash); + } + } - if (schema.properties() != null) { - for (Property p : schema.properties()) { - hash = SchemaHash.computeHash(namespace, p, hash); - } - } + if (schema.properties() != null) { + for (Property p : schema.properties()) { + hash = SchemaHash.computeHash(namespace, p, hash); + } + } - return hash; - } + return hash; + } - private static HashCode128 computeHash(Namespace namespace, SchemaOptions options, HashCode128 seed) { + private static HashCode128 computeHash(Namespace namespace, SchemaOptions options, HashCode128 seed) { - HashCode128 hash = seed; + HashCode128 hash = seed; - hash = Murmur3Hash.Hash128(options != null && options.disallowUnschematized(), hash); - hash = Murmur3Hash.Hash128(options != null && options.enablePropertyLevelTimestamp(), hash); - hash = Murmur3Hash.Hash128(options != null && options.disableSystemPrefix(), hash); + hash = Murmur3Hash.Hash128(options != null && options.disallowUnschematized(), hash); + hash = Murmur3Hash.Hash128(options != null && options.enablePropertyLevelTimestamp(), hash); + hash = Murmur3Hash.Hash128(options != null && options.disableSystemPrefix(), hash); - return hash; - } + return hash; + } - private static HashCode128 computeHash(Namespace ns, Property p, HashCode128 seed) { + private static HashCode128 computeHash(Namespace ns, Property p, HashCode128 seed) { - HashCode128 hash = seed; + HashCode128 hash = seed; - hash = Murmur3Hash.Hash128(p.path(), hash); - hash = SchemaHash.computeHash(ns, p.propertyType(), hash); + hash = Murmur3Hash.Hash128(p.path(), hash); + hash = SchemaHash.computeHash(ns, p.propertyType(), hash); - return hash; - } + return hash; + } - private static HashCode128 computeHash(Namespace namespace, PropertyType p, HashCode128 seed) { + private static HashCode128 computeHash(Namespace namespace, PropertyType p, HashCode128 seed) { - HashCode128 hash = seed; + HashCode128 hash = seed; - hash = Murmur3Hash.Hash128(p.type().value(), hash); - hash = Murmur3Hash.Hash128(p.nullable(), hash); + hash = Murmur3Hash.Hash128(p.type().value(), hash); + hash = Murmur3Hash.Hash128(p.nullable(), hash); - if (p.apiType() != null) { - hash = Murmur3Hash.Hash128(p.apiType(), hash); - } + if (p.apiType() != null) { + hash = Murmur3Hash.Hash128(p.apiType(), hash); + } - if (p instanceof PrimitivePropertyType) { + if (p instanceof PrimitivePropertyType) { - PrimitivePropertyType pp = (PrimitivePropertyType) p; + PrimitivePropertyType pp = (PrimitivePropertyType) p; - hash = Murmur3Hash.Hash128(pp.storage().value(), hash); - hash = Murmur3Hash.Hash128(pp.length(), hash); + hash = Murmur3Hash.Hash128(pp.storage().value(), hash); + hash = Murmur3Hash.Hash128(pp.length(), hash); - return hash; - } + return hash; + } - checkState(p instanceof ScopePropertyType); - ScopePropertyType pp = (ScopePropertyType) p; - hash = Murmur3Hash.Hash128(pp.immutable(), hash); + checkState(p instanceof ScopePropertyType); + ScopePropertyType pp = (ScopePropertyType) p; + hash = Murmur3Hash.Hash128(pp.immutable(), hash); - if (p instanceof ArrayPropertyType) { - ArrayPropertyType spp = (ArrayPropertyType) p; - if (spp.items() != null) { - hash = SchemaHash.computeHash(namespace, spp.items(), hash); - } - return hash; - } + if (p instanceof ArrayPropertyType) { + ArrayPropertyType spp = (ArrayPropertyType) p; + if (spp.items() != null) { + hash = SchemaHash.computeHash(namespace, spp.items(), hash); + } + return hash; + } - if (p instanceof ObjectPropertyType) { - ObjectPropertyType spp = (ObjectPropertyType) p; - if (spp.properties() != null) { - for (Property opp : spp.properties()) { - hash = SchemaHash.computeHash(namespace, opp, hash); - } - } - return hash; - } + if (p instanceof ObjectPropertyType) { + ObjectPropertyType spp = (ObjectPropertyType) p; + if (spp.properties() != null) { + for (Property opp : spp.properties()) { + hash = SchemaHash.computeHash(namespace, opp, hash); + } + } + return hash; + } - if (p instanceof MapPropertyType) { + if (p instanceof MapPropertyType) { - MapPropertyType spp = (MapPropertyType) p; + MapPropertyType spp = (MapPropertyType) p; - if (spp.keys() != null) { - hash = SchemaHash.computeHash(namespace, spp.keys(), hash); - } + if (spp.keys() != null) { + hash = SchemaHash.computeHash(namespace, spp.keys(), hash); + } - if (spp.values() != null) { - hash = SchemaHash.computeHash(namespace, spp.values(), hash); - } + if (spp.values() != null) { + hash = SchemaHash.computeHash(namespace, spp.values(), hash); + } - return hash; - } + return hash; + } - if (p instanceof SetPropertyType) { + if (p instanceof SetPropertyType) { - SetPropertyType spp = (SetPropertyType) p; + SetPropertyType spp = (SetPropertyType) p; - if (spp.items() != null) { - hash = SchemaHash.computeHash(namespace, spp.items(), hash); - } + if (spp.items() != null) { + hash = SchemaHash.computeHash(namespace, spp.items(), hash); + } - return hash; - } + return hash; + } - if (p instanceof TaggedPropertyType) { + if (p instanceof TaggedPropertyType) { - TaggedPropertyType spp = (TaggedPropertyType) p; + TaggedPropertyType spp = (TaggedPropertyType) p; - if (spp.items() != null) { - for (PropertyType pt : spp.items()) { - hash = SchemaHash.computeHash(namespace, pt, hash); - } - } + if (spp.items() != null) { + for (PropertyType pt : spp.items()) { + hash = SchemaHash.computeHash(namespace, pt, hash); + } + } - return hash; - } + return hash; + } - if (p instanceof TuplePropertyType) { + if (p instanceof TuplePropertyType) { - TuplePropertyType spp = (TuplePropertyType) p; + TuplePropertyType spp = (TuplePropertyType) p; - if (spp.items() != null) { - for (PropertyType pt : spp.items()) { - hash = SchemaHash.computeHash(namespace, pt, hash); - } - } + if (spp.items() != null) { + for (PropertyType pt : spp.items()) { + hash = SchemaHash.computeHash(namespace, pt, hash); + } + } - return hash; - } + return hash; + } - if (p instanceof UdtPropertyType) { + if (p instanceof UdtPropertyType) { - Stream schemaStream = namespace.schemas().stream(); - UdtPropertyType spp = (UdtPropertyType) p; - Optional udtSchema; + Stream schemaStream = namespace.schemas().stream(); + UdtPropertyType spp = (UdtPropertyType) p; + Optional udtSchema; - if (spp.schemaId() == SchemaId.INVALID) { - udtSchema = schemaStream.filter(schema -> schema.name().equals(spp.name())).findFirst(); - } else { - udtSchema = schemaStream.filter(schema -> schema.schemaId().equals(spp.schemaId())).findFirst(); - udtSchema.ifPresent(schema -> checkState(schema.name().equals(spp.name()), - "Ambiguous schema reference: '%s:%s'", spp.name(), spp.schemaId())); - } + if (spp.schemaId() == SchemaId.INVALID) { + udtSchema = schemaStream.filter(schema -> schema.name().equals(spp.name())).findFirst(); + } else { + udtSchema = schemaStream.filter(schema -> schema.schemaId().equals(spp.schemaId())).findFirst(); + udtSchema.ifPresent(schema -> checkState(schema.name().equals(spp.name()), + "Ambiguous schema reference: '%s:%s'", spp.name(), spp.schemaId())); + } - checkState(udtSchema.isPresent(), "Cannot resolve schema reference '{0}:{1}'", spp.name(), spp.schemaId()); - return SchemaHash.computeHash(namespace, udtSchema.get(), hash); - } + checkState(udtSchema.isPresent(), "Cannot resolve schema reference '{0}:{1}'", spp.name(), spp.schemaId()); + return SchemaHash.computeHash(namespace, udtSchema.get(), hash); + } - throw new IllegalStateException(lenientFormat("unrecognized property type: %s", p.getClass())); - } + throw new IllegalStateException(lenientFormat("unrecognized property type: %s", p.getClass())); + } - private static HashCode128 computeHash(Namespace namespace, PartitionKey key, HashCode128 seed) { - return key == null ? seed : Murmur3Hash.Hash128(key.path(), seed); - } + private static HashCode128 computeHash(Namespace namespace, PartitionKey key, HashCode128 seed) { + return key == null ? seed : Murmur3Hash.Hash128(key.path(), seed); + } - private static HashCode128 computeHash(Namespace namespace, PrimarySortKey key, HashCode128 seed) { - HashCode128 hash = seed; - if (key != null) { - hash = Murmur3Hash.Hash128(key.path(), hash); - hash = Murmur3Hash.Hash128(key.direction().value(), hash); - } - return hash; - } + private static HashCode128 computeHash(Namespace namespace, PrimarySortKey key, HashCode128 seed) { + HashCode128 hash = seed; + if (key != null) { + hash = Murmur3Hash.Hash128(key.path(), hash); + hash = Murmur3Hash.Hash128(key.direction().value(), hash); + } + return hash; + } - private static HashCode128 computeHash(Namespace ns, StaticKey key, HashCode128 seed) { - return key == null ? seed : Murmur3Hash.Hash128(key.path(), seed); - } + private static HashCode128 computeHash(Namespace ns, StaticKey key, HashCode128 seed) { + return key == null ? seed : Murmur3Hash.Hash128(key.path(), seed); + } } \ No newline at end of file diff --git a/java/src/main/java/tangible/StringHelper.java b/java/src/main/java/tangible/StringHelper.java index b7ab7fc..2cd63c3 100644 --- a/java/src/main/java/tangible/StringHelper.java +++ b/java/src/main/java/tangible/StringHelper.java @@ -5,7 +5,7 @@ package tangible; public final class StringHelper { //------------------------------------------------------------------------------------ - // This method replaces the .NET string method 'IndexOfAny' (1 parameter version). + // This method replaces the .NET string method 'IndexOfAny' (1 parameter version). //------------------------------------------------------------------------------------ public static int indexOfAny(String string, char[] anyOf) { int lowestIndex = -1; @@ -26,7 +26,7 @@ public final class StringHelper { } //------------------------------------------------------------------------------------ - // This method replaces the .NET string method 'IndexOfAny' (2 parameter version). + // This method replaces the .NET string method 'IndexOfAny' (2 parameter version). //------------------------------------------------------------------------------------ public static int indexOfAny(String string, char[] anyOf, int startIndex) { int indexInSubstring = indexOfAny(string.substring(startIndex), anyOf); @@ -38,7 +38,7 @@ public final class StringHelper { } //------------------------------------------------------------------------------------ - // This method replaces the .NET string method 'IndexOfAny' (3 parameter version). + // This method replaces the .NET string method 'IndexOfAny' (3 parameter version). //------------------------------------------------------------------------------------ public static int indexOfAny(String string, char[] anyOf, int startIndex, int count) { int endIndex = startIndex + count; @@ -51,14 +51,14 @@ public final class StringHelper { } //------------------------------------------------------------------------------------ - // This method replaces the .NET static string method 'IsNullOrEmpty'. + // This method replaces the .NET static string method 'IsNullOrEmpty'. //------------------------------------------------------------------------------------ public static boolean isNullOrEmpty(String string) { return string == null || string.length() == 0; } //------------------------------------------------------------------------------------ - // This method replaces the .NET static string method 'IsNullOrWhiteSpace'. + // This method replaces the .NET static string method 'IsNullOrWhiteSpace'. //------------------------------------------------------------------------------------ public static boolean isNullOrWhiteSpace(String string) { if (string == null) { @@ -75,7 +75,7 @@ public final class StringHelper { } //------------------------------------------------------------------------------------ - // This method replaces the .NET static string method 'Join' (2 parameter version). + // This method replaces the .NET static string method 'Join' (2 parameter version). //------------------------------------------------------------------------------------ public static String join(String separator, String[] stringArray) { if (stringArray == null) { @@ -86,7 +86,7 @@ public final class StringHelper { } //------------------------------------------------------------------------------------ - // This method replaces the .NET static string method 'Join' (4 parameter version). + // This method replaces the .NET static string method 'Join' (4 parameter version). //------------------------------------------------------------------------------------ public static String join(String separator, String[] stringArray, int startIndex, int count) { String result = ""; @@ -109,7 +109,7 @@ public final class StringHelper { } //------------------------------------------------------------------------------------ - // This method replaces the .NET string method 'LastIndexOf' (char version). + // This method replaces the .NET string method 'LastIndexOf' (char version). //------------------------------------------------------------------------------------ public static int lastIndexOf(String string, char value, int startIndex, int count) { int leftMost = startIndex + 1 - count; @@ -124,7 +124,7 @@ public final class StringHelper { } //------------------------------------------------------------------------------------ - // This method replaces the .NET string method 'LastIndexOf' (string version). + // This method replaces the .NET string method 'LastIndexOf' (string version). //------------------------------------------------------------------------------------ public static int lastIndexOf(String string, String value, int startIndex, int count) { int leftMost = startIndex + 1 - count; @@ -139,7 +139,7 @@ public final class StringHelper { } //------------------------------------------------------------------------------------ - // This method replaces the .NET string method 'LastIndexOfAny' (1 parameter version). + // This method replaces the .NET string method 'LastIndexOfAny' (1 parameter version). //------------------------------------------------------------------------------------ public static int lastIndexOfAny(String string, char[] anyOf) { int highestIndex = -1; @@ -158,7 +158,7 @@ public final class StringHelper { } //------------------------------------------------------------------------------------ - // This method replaces the .NET string method 'LastIndexOfAny' (2 parameter version). + // This method replaces the .NET string method 'LastIndexOfAny' (2 parameter version). //------------------------------------------------------------------------------------ public static int lastIndexOfAny(String string, char[] anyOf, int startIndex) { String substring = string.substring(0, startIndex + 1); @@ -171,7 +171,7 @@ public final class StringHelper { } //------------------------------------------------------------------------------------ - // This method replaces the .NET string method 'LastIndexOfAny' (3 parameter version). + // This method replaces the .NET string method 'LastIndexOfAny' (3 parameter version). //------------------------------------------------------------------------------------ public static int lastIndexOfAny(String string, char[] anyOf, int startIndex, int count) { int leftMost = startIndex + 1 - count; @@ -186,14 +186,14 @@ public final class StringHelper { } //------------------------------------------------------------------------------------ - // This method replaces the .NET string method 'PadLeft' (1 parameter version). + // This method replaces the .NET string method 'PadLeft' (1 parameter version). //------------------------------------------------------------------------------------ public static String padLeft(String string, int totalWidth) { return padLeft(string, totalWidth, ' '); } //------------------------------------------------------------------------------------ - // This method replaces the .NET string method 'PadLeft' (2 parameter version). + // This method replaces the .NET string method 'PadLeft' (2 parameter version). //------------------------------------------------------------------------------------ public static String padLeft(String string, int totalWidth, char paddingChar) { StringBuilder sb = new StringBuilder(); @@ -207,14 +207,14 @@ public final class StringHelper { } //------------------------------------------------------------------------------------ - // This method replaces the .NET string method 'PadRight' (1 parameter version). + // This method replaces the .NET string method 'PadRight' (1 parameter version). //------------------------------------------------------------------------------------ public static String padRight(String string, int totalWidth) { return padRight(string, totalWidth, ' '); } //------------------------------------------------------------------------------------ - // This method replaces the .NET string method 'PadRight' (2 parameter version). + // This method replaces the .NET string method 'PadRight' (2 parameter version). //------------------------------------------------------------------------------------ public static String padRight(String string, int totalWidth, char paddingChar) { StringBuilder sb = new StringBuilder(string); @@ -227,21 +227,21 @@ public final class StringHelper { } //------------------------------------------------------------------------------------ - // This method replaces the .NET string method 'Remove' (1 parameter version). + // This method replaces the .NET string method 'Remove' (1 parameter version). //------------------------------------------------------------------------------------ public static String remove(String string, int start) { return string.substring(0, start); } //------------------------------------------------------------------------------------ - // This method replaces the .NET string method 'Remove' (2 parameter version). + // This method replaces the .NET string method 'Remove' (2 parameter version). //------------------------------------------------------------------------------------ public static String remove(String string, int start, int count) { return string.substring(0, start) + string.substring(start + count); } //------------------------------------------------------------------------------------ - // This method replaces the .NET string constructor which repeats a character. + // This method replaces the .NET string constructor which repeats a character. //------------------------------------------------------------------------------------ public static String repeatChar(char charToRepeat, int count) { String newString = ""; @@ -252,9 +252,9 @@ public final class StringHelper { } //------------------------------------------------------------------------------------ - // This method is used for string equality comparisons when the option - // 'Use helper 'stringsEqual' method to handle null strings' is selected - // (The Java String 'equals' method can't be called on a null instance). + // This method is used for string equality comparisons when the option + // 'Use helper 'stringsEqual' method to handle null strings' is selected + // (The Java String 'equals' method can't be called on a null instance). //------------------------------------------------------------------------------------ public static boolean stringsEqual(String s1, String s2) { if (s1 == null && s2 == null) { @@ -265,8 +265,8 @@ public final class StringHelper { } //------------------------------------------------------------------------------------ - // This method replaces the .NET string method 'Substring' when 'start' is a method - // call or calculated value to ensure that 'start' is obtained just once. + // This method replaces the .NET string method 'Substring' when 'start' is a method + // call or calculated value to ensure that 'start' is obtained just once. //------------------------------------------------------------------------------------ public static String substring(String string, int start, int length) { if (length < 0) { @@ -277,14 +277,14 @@ public final class StringHelper { } //------------------------------------------------------------------------------------ - // This method replaces the .NET string method 'Trim' when arguments are used. + // This method replaces the .NET string method 'Trim' when arguments are used. //------------------------------------------------------------------------------------ public static String trim(String string, Character... charsToTrim) { return trimEnd(trimStart(string, charsToTrim), charsToTrim); } //------------------------------------------------------------------------------------ - // This method replaces the .NET string method 'TrimEnd'. + // This method replaces the .NET string method 'TrimEnd'. //------------------------------------------------------------------------------------ public static String trimEnd(String string, Character... charsToTrim) { if (string == null || charsToTrim == null) { @@ -316,7 +316,7 @@ public final class StringHelper { } //------------------------------------------------------------------------------------ - // This method replaces the .NET string method 'TrimStart'. + // This method replaces the .NET string method 'TrimStart'. //------------------------------------------------------------------------------------ public static String trimStart(String string, Character... charsToTrim) { if (string == null || charsToTrim == null) { diff --git a/java/src/test/java/com/azure/data/cosmos/serialization/hybridrow/perf/JsonModelRowGenerator.java b/java/src/test/java/com/azure/data/cosmos/serialization/hybridrow/perf/JsonModelRowGenerator.java index 8fcf0d5..766989f 100644 --- a/java/src/test/java/com/azure/data/cosmos/serialization/hybridrow/perf/JsonModelRowGenerator.java +++ b/java/src/test/java/com/azure/data/cosmos/serialization/hybridrow/perf/JsonModelRowGenerator.java @@ -80,7 +80,7 @@ public final class JsonModelRowGenerator { new Reference(this.row); // TODO: C# TO JAVA CONVERTER: The following lambda contained an unresolved 'ref' keyword - these are not // converted by C# to Java Converter: - Result tempVar = RowWriter.WriteBuffer(tempReference_row, value, (RowWriter RowWriter writer, TypeArgument typeArg, + Result tempVar = RowWriter.writeBuffer(tempReference_row, value, (RowWriter RowWriter writer, TypeArgument typeArg, HashMap dict) -> { for ((Utf8String propPath,Object propValue) :dict) @@ -118,7 +118,7 @@ public final class JsonModelRowGenerator { //ORIGINAL LINE: case bool x: case boolean x: - return writer.get().WriteBoolean(path, x); + return writer.get().writeBoolean(path, x); // TODO: C# TO JAVA CONVERTER: Java has no equivalent to C# pattern variables in 'case' statements: //ORIGINAL LINE: case long x: case @@ -155,7 +155,7 @@ public final class JsonModelRowGenerator { case HashMap < Utf8String, Object > x: // TODO: C# TO JAVA CONVERTER: The following lambda contained an unresolved 'ref' keyword - these // are not converted by C# to Java Converter: - return writer.get().WriteScope(path, new TypeArgument(LayoutType.Object), x, + return writer.get().writeScope(path, new TypeArgument(LayoutType.Object), x, (RowWriter RowWriter writer2, TypeArgument typeArg, HashMap dict) -> { for ((Utf8String propPath,Object propValue) :dict) @@ -172,7 +172,7 @@ public final class JsonModelRowGenerator { //ORIGINAL LINE: case List x: case ArrayList < Object > x: // TODO: C# TO JAVA CONVERTER: The following lambda contained an unresolved 'ref' keyword - these are not converted by C# to Java Converter: - return writer.get().WriteScope(path, new TypeArgument(LayoutType.Array), x, (RowWriter RowWriter writer2, TypeArgument typeArg, ArrayList list) -> + return writer.get().writeScope(path, new TypeArgument(LayoutType.Array), x, (RowWriter RowWriter writer2, TypeArgument typeArg, ArrayList list) -> { for (Object elm : list) { Reference tempReference_writer2 = new Reference(writer2); diff --git a/java/src/test/java/com/azure/data/cosmos/serialization/hybridrow/unit/AssertThrowsException.java b/java/src/test/java/com/azure/data/cosmos/serialization/hybridrow/unit/AssertThrowsException.java index f62a6e2..a77c3a5 100644 --- a/java/src/test/java/com/azure/data/cosmos/serialization/hybridrow/unit/AssertThrowsException.java +++ b/java/src/test/java/com/azure/data/cosmos/serialization/hybridrow/unit/AssertThrowsException.java @@ -16,7 +16,6 @@ public final class AssertThrowsException { if (input1 == null) { return "(null)"; } - return Assert.ReplaceNullChars(input1); } diff --git a/java/src/test/java/com/azure/data/cosmos/serialization/hybridrow/unit/CustomerExampleUnitTests.java b/java/src/test/java/com/azure/data/cosmos/serialization/hybridrow/unit/CustomerExampleUnitTests.java index 0d1bde6..1b15590 100644 --- a/java/src/test/java/com/azure/data/cosmos/serialization/hybridrow/unit/CustomerExampleUnitTests.java +++ b/java/src/test/java/com/azure/data/cosmos/serialization/hybridrow/unit/CustomerExampleUnitTests.java @@ -10,6 +10,7 @@ import com.azure.data.cosmos.serialization.hybridrow.Result; import com.azure.data.cosmos.serialization.hybridrow.RowBuffer; import com.azure.data.cosmos.serialization.hybridrow.RowCursor; import com.azure.data.cosmos.serialization.hybridrow.RowCursors; +import com.azure.data.cosmos.serialization.hybridrow.unit.customerschema.Hotel; import java.nio.file.Files; import java.util.ArrayList; @@ -25,16 +26,18 @@ import java.util.UUID; // are anonymous.")][DeploymentItem("TestData\\CustomerSchema.json", "TestData")] public sealed class // CustomerExampleUnitTests public final class CustomerExampleUnitTests { - private final Hotel hotelExample = new Hotel() { - Id ="The-Westin-St-John-Resort-Villas-1187",Name ="The Westin St. John Resort Villas",Phone ="+1 340-693-8000" - ,Address =new Address - { + private final Hotel hotelExample = new Hotel() { + Id = "The-Westin-St-John-Resort-Villas-1187", + Name ="The Westin St. John Resort Villas", + Phone ="+1 340-693-8000", + Address = new Address { Street = "300B Chocolate Hole", City = "Great Cruz Bay", State = "VI", PostalCode = new PostalCode { - Zip = 00830, Plus4 = 0001 - } + Zip = 00830, Plus4 = 0001 + } } }; + private LayoutResolver customerResolver; private Namespace customerSchema; private Layout guestLayout; diff --git a/java/src/test/java/com/azure/data/cosmos/serialization/hybridrow/unit/RowWriterUnitTests.java b/java/src/test/java/com/azure/data/cosmos/serialization/hybridrow/unit/RowWriterUnitTests.java index 89c3ea9..fa8a3ce 100644 --- a/java/src/test/java/com/azure/data/cosmos/serialization/hybridrow/unit/RowWriterUnitTests.java +++ b/java/src/test/java/com/azure/data/cosmos/serialization/hybridrow/unit/RowWriterUnitTests.java @@ -57,7 +57,7 @@ public final class RowWriterUnitTests { new Reference(row); // TODO: C# TO JAVA CONVERTER: The following lambda contained an unresolved 'ref' keyword - these are not // converted by C# to Java Converter: - ResultAssert.IsSuccess(RowWriter.WriteBuffer(tempReference_row, null, (RowWriter RowWriter writer, + ResultAssert.IsSuccess(RowWriter.writeBuffer(tempReference_row, null, (RowWriter RowWriter writer, TypeArgument rootTypeArg, Object ignored) -> { ResultAssert.IsSuccess(writer.WriteNull("null"));