pax_global_header00006660000000000000000000000064126147431730014522gustar00rootroot0000000000000052 comment=97bc29d77689246ee22263c2b3bfec95da82f41a slice-0.16/000077500000000000000000000000001261474317300125475ustar00rootroot00000000000000slice-0.16/.gitignore000066400000000000000000000001611261474317300145350ustar00rootroot00000000000000*.iml *.ipr *.iws target/ /var pom.xml.versionsBackup test-output/ /atlassian-ide-plugin.xml .idea .*.swp .*.swo slice-0.16/.travis.yml000066400000000000000000000000441261474317300146560ustar00rootroot00000000000000language: java jdk: - oraclejdk8 slice-0.16/LICENSE000066400000000000000000000261361261474317300135640ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. slice-0.16/benchmarks.md000066400000000000000000000116221261474317300152100ustar00rootroot00000000000000Memory Copy Microbenchmark ========================== Throughput numbers: higher is better Mac Pro Early 2009 -- 2x2.66GHz Xeon -- OS 10.9 ----------------------------------------------- Benchmark Mode Thr Cnt Sec Mean Mean error Units i.a.s.MemoryCopyBenchmark.b00sliceZero thrpt 1 5 1 33180.705 525.792 ops/ms i.a.s.MemoryCopyBenchmark.b01customLoopZero thrpt 1 5 1 44505.121 223.078 ops/ms i.a.s.MemoryCopyBenchmark.b02unsafeZero thrpt 1 5 1 33298.713 741.633 ops/ms i.a.s.MemoryCopyBenchmark.b03slice32B thrpt 1 5 1 3620.478 26.610 ops/ms i.a.s.MemoryCopyBenchmark.b04customLoop32B thrpt 1 5 1 7469.741 1860.961 ops/ms i.a.s.MemoryCopyBenchmark.b05unsafe32B thrpt 1 5 1 3748.963 30.115 ops/ms i.a.s.MemoryCopyBenchmark.b06slice128B thrpt 1 5 1 3450.564 35.321 ops/ms i.a.s.MemoryCopyBenchmark.b07customLoop128B thrpt 1 5 1 5439.138 90.792 ops/ms i.a.s.MemoryCopyBenchmark.b08unsafe128B thrpt 1 5 1 3504.716 9.448 ops/ms i.a.s.MemoryCopyBenchmark.b09slice512B thrpt 1 5 1 2965.151 44.551 ops/ms i.a.s.MemoryCopyBenchmark.b10customLoop512B thrpt 1 5 1 2325.568 113.557 ops/ms i.a.s.MemoryCopyBenchmark.b11unsafe512B thrpt 1 5 1 2996.845 16.525 ops/ms i.a.s.MemoryCopyBenchmark.b12slice1K thrpt 1 5 1 2006.529 4.079 ops/ms i.a.s.MemoryCopyBenchmark.b13customLoop1K thrpt 1 5 1 1484.227 0.831 ops/ms i.a.s.MemoryCopyBenchmark.b14unsafe1K thrpt 1 5 1 2039.754 9.237 ops/ms i.a.s.MemoryCopyBenchmark.b15slice1M thrpt 1 5 1 3.993 0.005 ops/ms i.a.s.MemoryCopyBenchmark.b16customLoop1M thrpt 1 5 1 3.531 0.011 ops/ms i.a.s.MemoryCopyBenchmark.b17unsafe1M thrpt 1 5 1 3.978 0.052 ops/ms i.a.s.MemoryCopyBenchmark.b18slice128M thrpt 1 5 1 0.029 0.000 ops/ms i.a.s.MemoryCopyBenchmark.b19customLoop128M thrpt 1 5 1 0.027 0.001 ops/ms i.a.s.MemoryCopyBenchmark.b20unsafe128M thrpt 1 5 1 0.029 0.000 ops/ms Xeon X5670 2.93GHz -- CentOS 6.4 -------------------------------- Benchmark Mode Thr Cnt Sec Mean Mean error Units i.a.s.MemoryCopyBenchmark.b00sliceZero thrpt 1 7 1 32019.795 14.552 ops/ms i.a.s.MemoryCopyBenchmark.b01customLoopZero thrpt 1 7 1 42989.712 151.868 ops/ms i.a.s.MemoryCopyBenchmark.b02unsafeZero thrpt 1 7 1 31491.911 33.982 ops/ms i.a.s.MemoryCopyBenchmark.b03slice32B thrpt 1 7 1 8324.091 1.213 ops/ms i.a.s.MemoryCopyBenchmark.b04customLoop32B thrpt 1 7 1 13790.033 18.228 ops/ms i.a.s.MemoryCopyBenchmark.b05unsafe32B thrpt 1 7 1 8997.760 3.275 ops/ms i.a.s.MemoryCopyBenchmark.b06slice128B thrpt 1 7 1 7517.828 7.459 ops/ms i.a.s.MemoryCopyBenchmark.b07customLoop128B thrpt 1 7 1 8225.268 49.770 ops/ms i.a.s.MemoryCopyBenchmark.b08unsafe128B thrpt 1 7 1 7996.823 40.365 ops/ms i.a.s.MemoryCopyBenchmark.b09slice512B thrpt 1 7 1 5854.990 53.925 ops/ms i.a.s.MemoryCopyBenchmark.b10customLoop512B thrpt 1 7 1 3553.523 21.415 ops/ms i.a.s.MemoryCopyBenchmark.b11unsafe512B thrpt 1 7 1 6106.234 37.416 ops/ms i.a.s.MemoryCopyBenchmark.b12slice1K thrpt 1 7 1 3377.940 26.430 ops/ms i.a.s.MemoryCopyBenchmark.b13customLoop1K thrpt 1 7 1 2879.045 51.883 ops/ms i.a.s.MemoryCopyBenchmark.b14unsafe1K thrpt 1 7 1 3426.431 4.206 ops/ms i.a.s.MemoryCopyBenchmark.b15slice1M thrpt 1 7 1 4.958 0.017 ops/ms i.a.s.MemoryCopyBenchmark.b16customLoop1M thrpt 1 7 1 4.313 0.032 ops/ms i.a.s.MemoryCopyBenchmark.b17unsafe1M thrpt 1 7 1 4.942 0.050 ops/ms i.a.s.MemoryCopyBenchmark.b18slice128M thrpt 1 7 1 0.037 0.001 ops/ms i.a.s.MemoryCopyBenchmark.b19customLoop128M thrpt 1 7 1 0.033 0.001 ops/ms i.a.s.MemoryCopyBenchmark.b20unsafe128M thrpt 1 7 1 0.037 0.001 ops/ms slice-0.16/pom.xml000066400000000000000000000056051261474317300140720ustar00rootroot00000000000000 4.0.0 slice 0.16 jar slice Library for efficiently working with heap and off-heap memory https://github.com/airlift/slice io.airlift airbase 38 2012 true false -missing 0.9.4 com.google.code.findbugs annotations true org.testng testng test com.google.guava guava test org.openjdk.jmh jmh-core ${dep.jmh.version} test org.openjdk.jmh jmh-generator-annprocess ${dep.jmh.version} test com.mycila license-maven-plugin src/main/java/io/airlift/slice/Preconditions.java src/main/java/io/airlift/slice/CountingInputStream.java src/main/java/io/airlift/slice/CountingOutputStream.java src/main/java/io/airlift/slice/LittleEndianDataInputStream.java src/main/java/io/airlift/slice/LittleEndianDataOutputStream.java 0.16 slice-0.16/src/000077500000000000000000000000001261474317300133365ustar00rootroot00000000000000slice-0.16/src/license/000077500000000000000000000000001261474317300147605ustar00rootroot00000000000000slice-0.16/src/license/LICENSE-HEADER.txt000066400000000000000000000010141261474317300175250ustar00rootroot00000000000000Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. slice-0.16/src/main/000077500000000000000000000000001261474317300142625ustar00rootroot00000000000000slice-0.16/src/main/java/000077500000000000000000000000001261474317300152035ustar00rootroot00000000000000slice-0.16/src/main/java/io/000077500000000000000000000000001261474317300156125ustar00rootroot00000000000000slice-0.16/src/main/java/io/airlift/000077500000000000000000000000001261474317300172445ustar00rootroot00000000000000slice-0.16/src/main/java/io/airlift/slice/000077500000000000000000000000001261474317300203435ustar00rootroot00000000000000slice-0.16/src/main/java/io/airlift/slice/BasicSliceInput.java000066400000000000000000000137651261474317300242430ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import java.io.IOException; import java.io.OutputStream; import java.nio.charset.Charset; import static io.airlift.slice.Preconditions.checkNotNull; import static io.airlift.slice.Preconditions.checkPositionIndex; import static io.airlift.slice.SizeOf.SIZE_OF_DOUBLE; import static io.airlift.slice.SizeOf.SIZE_OF_FLOAT; import static io.airlift.slice.SizeOf.SIZE_OF_INT; import static io.airlift.slice.SizeOf.SIZE_OF_LONG; import static io.airlift.slice.SizeOf.SIZE_OF_SHORT; @SuppressWarnings("JavaDoc") // IDEA-81310 public final class BasicSliceInput extends FixedLengthSliceInput { private final Slice slice; private int position; public BasicSliceInput(Slice slice) { this.slice = checkNotNull(slice, "slice is null"); } @Override public long length() { return slice.length(); } @Override public long position() { return position; } @Override public void setPosition(long position) { checkPositionIndex(position, slice.length()); this.position = (int) position; } @Override public boolean isReadable() { return position < slice.length(); } @Override public int available() { return slice.length() - position; } @Override public boolean readBoolean() { return readByte() != 0; } @Override public int read() { if (position >= slice.length()) { return -1; } int result = slice.getByte(position) & 0xFF; position++; return result; } @Override public byte readByte() { int value = read(); if (value == -1) { throw new IndexOutOfBoundsException(); } return (byte) value; } @Override public int readUnsignedByte() { return readByte() & 0xFF; } @Override public short readShort() { short v = slice.getShort(position); position += SIZE_OF_SHORT; return v; } @Override public int readUnsignedShort() { return readShort() & 0xFFFF; } @Override public int readInt() { int v = slice.getInt(position); position += SIZE_OF_INT; return v; } @Override public long readLong() { long v = slice.getLong(position); position += SIZE_OF_LONG; return v; } @Override public float readFloat() { float v = slice.getFloat(position); position += SIZE_OF_FLOAT; return v; } @Override public double readDouble() { double v = slice.getDouble(position); position += SIZE_OF_DOUBLE; return v; } @Override public Slice readSlice(int length) { if (length == 0) { return Slices.EMPTY_SLICE; } Slice newSlice = slice.slice(position, length); position += length; return newSlice; } @Override public int read(byte[] destination, int destinationIndex, int length) { if (length == 0) { return 0; } length = Math.min(length, available()); if (length == 0) { return -1; } readBytes(destination, destinationIndex, length); return length; } @Override public void readBytes(byte[] destination, int destinationIndex, int length) { slice.getBytes(position, destination, destinationIndex, length); position += length; } @Override public void readBytes(Slice destination, int destinationIndex, int length) { slice.getBytes(position, destination, destinationIndex, length); position += length; } @Override public void readBytes(OutputStream out, int length) throws IOException { slice.getBytes(position, out, length); position += length; } @Override public long skip(long length) { length = Math.min(length, available()); position += length; return length; } @Override public int skipBytes(int length) { length = Math.min(length, available()); position += length; return length; } /** * Returns a slice of this buffer's readable bytes. Modifying the content * of the returned buffer or this buffer affects each other's content * while they maintain separate indexes and marks. This method is * identical to {@code buf.slice(buf.position(), buf.available()())}. * This method does not modify {@code position} or {@code writerIndex} of * this buffer. */ public Slice slice() { return slice.slice(position, slice.length() - position); } /** * Decodes this buffer's readable bytes into a string with the specified * character set name. This method is identical to * {@code buf.toString(buf.position(), buf.available()(), charsetName)}. * This method does not modify {@code position} or {@code writerIndex} of * this buffer. */ public String toString(Charset charset) { return slice.toString(position, available(), charset); } @Override public String toString() { StringBuilder builder = new StringBuilder("BasicSliceInput{"); builder.append("position=").append(position); builder.append(", capacity=").append(slice.length()); builder.append('}'); return builder.toString(); } } slice-0.16/src/main/java/io/airlift/slice/BasicSliceOutput.java000066400000000000000000000113431261474317300244320ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; import static io.airlift.slice.Preconditions.checkNotNull; import static io.airlift.slice.SizeOf.SIZE_OF_BYTE; import static io.airlift.slice.SizeOf.SIZE_OF_DOUBLE; import static io.airlift.slice.SizeOf.SIZE_OF_FLOAT; import static io.airlift.slice.SizeOf.SIZE_OF_INT; import static io.airlift.slice.SizeOf.SIZE_OF_LONG; import static io.airlift.slice.SizeOf.SIZE_OF_SHORT; public class BasicSliceOutput extends SliceOutput { private final Slice slice; private int size; protected BasicSliceOutput(Slice slice) { this.slice = checkNotNull(slice, "slice is null"); } @Override public void reset() { size = 0; } @Override public int size() { return size; } @Override public boolean isWritable() { return writableBytes() > 0; } @Override public int writableBytes() { return slice.length() - size; } @Override public void writeByte(int value) { slice.setByte(size, value); size += SIZE_OF_BYTE; } @Override public void writeShort(int value) { slice.setShort(size, value); size += SIZE_OF_SHORT; } @Override public void writeInt(int value) { slice.setInt(size, value); size += SIZE_OF_INT; } @Override public void writeLong(long value) { slice.setLong(size, value); size += SIZE_OF_LONG; } @Override public void writeFloat(float value) { slice.setFloat(size, value); size += SIZE_OF_FLOAT; } @Override public void writeDouble(double value) { slice.setDouble(size, value); size += SIZE_OF_DOUBLE; } @Override public void writeBytes(byte[] source, int sourceIndex, int length) { slice.setBytes(size, source, sourceIndex, length); size += length; } @Override public void writeBytes(byte[] source) { writeBytes(source, 0, source.length); } @Override public void writeBytes(Slice source) { writeBytes(source, 0, source.length()); } @Override public void writeBytes(Slice source, int sourceIndex, int length) { slice.setBytes(size, source, sourceIndex, length); size += length; } @Override public void writeBytes(InputStream in, int length) throws IOException { slice.setBytes(size, in, length); size += length; } @Override public BasicSliceOutput appendLong(long value) { writeLong(value); return this; } @Override public SliceOutput appendDouble(double value) { writeDouble(value); return this; } @Override public BasicSliceOutput appendInt(int value) { writeInt(value); return this; } @Override public BasicSliceOutput appendShort(int value) { writeShort(value); return this; } @Override public BasicSliceOutput appendByte(int value) { writeByte(value); return this; } @Override public BasicSliceOutput appendBytes(byte[] source, int sourceIndex, int length) { write(source, sourceIndex, length); return this; } @Override public BasicSliceOutput appendBytes(byte[] source) { writeBytes(source); return this; } @Override public BasicSliceOutput appendBytes(Slice slice) { writeBytes(slice); return this; } @Override public Slice slice() { return slice.slice(0, size); } @Override public Slice getUnderlyingSlice() { return slice; } @Override public String toString() { StringBuilder builder = new StringBuilder("BasicSliceOutput{"); builder.append("size=").append(size); builder.append(", capacity=").append(slice.length()); builder.append('}'); return builder.toString(); } @Override public String toString(Charset charset) { return slice.toString(0, size, charset); } } slice-0.16/src/main/java/io/airlift/slice/ByteArrays.java000066400000000000000000000044051261474317300232760ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import static io.airlift.slice.JvmUtils.unsafe; import static io.airlift.slice.Preconditions.checkPositionIndexes; import static io.airlift.slice.SizeOf.SIZE_OF_DOUBLE; import static io.airlift.slice.SizeOf.SIZE_OF_FLOAT; import static io.airlift.slice.SizeOf.SIZE_OF_INT; import static io.airlift.slice.SizeOf.SIZE_OF_LONG; import static io.airlift.slice.SizeOf.SIZE_OF_SHORT; import static sun.misc.Unsafe.ARRAY_BYTE_BASE_OFFSET; public final class ByteArrays { private ByteArrays() {} public static short getShort(byte[] bytes, int index) { checkIndexLength(bytes.length, index, SIZE_OF_SHORT); return unsafe.getShort(bytes, ((long) ARRAY_BYTE_BASE_OFFSET) + index); } public static int getInt(byte[] bytes, int index) { checkIndexLength(bytes.length, index, SIZE_OF_INT); return unsafe.getInt(bytes, ((long) ARRAY_BYTE_BASE_OFFSET) + index); } public static long getLong(byte[] bytes, int index) { checkIndexLength(bytes.length, index, SIZE_OF_LONG); return unsafe.getLong(bytes, ((long) ARRAY_BYTE_BASE_OFFSET) + index); } public static float getFloat(byte[] bytes, int index) { checkIndexLength(bytes.length, index, SIZE_OF_FLOAT); return unsafe.getFloat(bytes, ((long) ARRAY_BYTE_BASE_OFFSET) + index); } public static double getDouble(byte[] bytes, int index) { checkIndexLength(bytes.length, index, SIZE_OF_DOUBLE); return unsafe.getDouble(bytes, ((long) ARRAY_BYTE_BASE_OFFSET) + index); } private static void checkIndexLength(int arrayLength, int index, int typeLength) { checkPositionIndexes(index, index + typeLength, arrayLength); } } slice-0.16/src/main/java/io/airlift/slice/ChunkedSliceInput.java000066400000000000000000000230441261474317300245720ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import java.io.Closeable; import java.io.IOException; import java.io.OutputStream; import static io.airlift.slice.Preconditions.checkArgument; import static io.airlift.slice.SizeOf.SIZE_OF_BYTE; import static io.airlift.slice.SizeOf.SIZE_OF_DOUBLE; import static io.airlift.slice.SizeOf.SIZE_OF_FLOAT; import static io.airlift.slice.SizeOf.SIZE_OF_INT; import static io.airlift.slice.SizeOf.SIZE_OF_LONG; import static io.airlift.slice.SizeOf.SIZE_OF_SHORT; import static java.util.Objects.requireNonNull; @SuppressWarnings("JavaDoc") // IDEA-81310 public final class ChunkedSliceInput extends FixedLengthSliceInput { private final InternalLoader loader; private final Slice buffer; private final long globalLength; private long globalPosition; private int bufferPosition; private int bufferLength; public ChunkedSliceInput(SliceLoader loader, int bufferSize) { this.loader = new InternalLoader<>(requireNonNull(loader, "loader is null"), bufferSize); this.buffer = this.loader.getBufferSlice(); this.globalLength = loader.getSize(); } @Override public long length() { return globalLength; } @Override public long position() { return globalPosition + bufferPosition; } @Override public void setPosition(long position) { if (position < 0 || position > globalLength) { throw new IndexOutOfBoundsException("Invalid position " + position + " for slice with length " + globalLength); } this.globalPosition = position; this.bufferLength = 0; this.bufferPosition = 0; } @Override public boolean isReadable() { return bufferPosition < bufferLength; } @Override public int available() { return bufferLength - bufferPosition; } public void ensureAvailable(int size) { if (available() >= size) { return; } checkArgument(size <= buffer.length(), "Size is larger than buffer"); checkBound(position() + size, globalLength, "End of stream"); // advance position globalPosition += bufferPosition; bufferPosition = 0; // this will reread unused data in the buffer long readSize = Math.min(buffer.length(), globalLength - globalPosition); if (readSize > Integer.MAX_VALUE) { readSize = Integer.MAX_VALUE; } bufferLength = (int) readSize; loader.load(globalPosition, bufferLength); } @Override public boolean readBoolean() { return readByte() != 0; } @Override public int read() { if (position() >= globalLength) { return -1; } ensureAvailable(SIZE_OF_BYTE); int result = buffer.getByte(bufferPosition) & 0xFF; bufferPosition++; return result; } @Override public byte readByte() { int value = read(); if (value == -1) { throw new IndexOutOfBoundsException(); } return (byte) value; } @Override public int readUnsignedByte() { return readByte() & 0xFF; } @Override public short readShort() { ensureAvailable(SIZE_OF_SHORT); short v = buffer.getShort(bufferPosition); bufferPosition += SIZE_OF_SHORT; return v; } @Override public int readUnsignedShort() { return readShort() & 0xFFFF; } @Override public int readInt() { ensureAvailable(SIZE_OF_INT); int v = buffer.getInt(bufferPosition); bufferPosition += SIZE_OF_INT; return v; } @Override public long readLong() { ensureAvailable(SIZE_OF_LONG); long v = buffer.getLong(bufferPosition); bufferPosition += SIZE_OF_LONG; return v; } @Override public float readFloat() { ensureAvailable(SIZE_OF_FLOAT); float v = buffer.getFloat(bufferPosition); bufferPosition += SIZE_OF_FLOAT; return v; } @Override public double readDouble() { ensureAvailable(SIZE_OF_DOUBLE); double v = buffer.getDouble(bufferPosition); bufferPosition += SIZE_OF_DOUBLE; return v; } @Override public Slice readSlice(int length) { if (length == 0) { return Slices.EMPTY_SLICE; } Slice slice = Slices.allocate(length); readBytes(slice); return slice; } @Override public void readBytes(Slice destination, int destinationIndex, int length) { checkBound(position() + length, globalLength, "End of stream"); while (length > 0) { int bytesToRead = Math.min(available(), length); buffer.getBytes(bufferPosition, destination, destinationIndex, bytesToRead); bufferPosition += bytesToRead; length -= bytesToRead; destinationIndex += bytesToRead; ensureAvailable(Math.min(length, buffer.length())); } } @Override public int read(byte[] destination, int destinationIndex, int length) { if (length == 0) { return 0; } if (globalLength - position() == 0) { return -1; } // limit read to stream size length = (int) Math.min(length, globalLength - position()); // do a full read of the available data readBytes(destination, destinationIndex, length); return length; } @Override public void readBytes(byte[] destination, int destinationIndex, int length) { checkBound(position() + length, globalLength, "End of stream"); while (length > 0) { int bytesToRead = Math.min(available(), length); buffer.getBytes(bufferPosition, destination, destinationIndex, bytesToRead); bufferPosition += bytesToRead; length -= bytesToRead; destinationIndex += bytesToRead; ensureAvailable(Math.min(length, buffer.length())); } } @Override public void readBytes(OutputStream out, int length) throws IOException { checkBound(position() + length, globalLength, "End of stream"); while (length > 0) { int bytesToRead = Math.min(available(), length); buffer.getBytes(bufferPosition, out, bytesToRead); bufferPosition += bytesToRead; length -= bytesToRead; ensureAvailable(Math.min(length, buffer.length())); } } @Override public long skip(long length) { // is skip within the current buffer? if (available() >= length) { bufferPosition += length; return length; } // drop current buffer globalPosition += bufferPosition; bufferPosition = 0; bufferLength = 0; // trim length to stream size length = Math.min(length, remaining()); // skip globalPosition += length; return length; } @Override public int skipBytes(int length) { return (int) skip(length); } @Override public void close() { globalPosition = globalLength; bufferPosition = 0; bufferLength = 0; loader.close(); } @Override public String toString() { StringBuilder builder = new StringBuilder("SliceStreamInput{"); builder.append("globalLength=").append(globalLength); builder.append(", globalPosition=").append(globalPosition); builder.append(", bufferLength=").append(bufferLength); builder.append(", bufferPosition=").append(bufferPosition); builder.append('}'); return builder.toString(); } private static void checkBound(long index, long size, String message) { if (index > size) { throw new IndexOutOfBoundsException(message); } } public interface SliceLoader extends Closeable { B createBuffer(int bufferSize); long getSize(); void load(long position, B bufferReference, int length); @Override void close(); } public interface BufferReference { Slice getSlice(); } private static class InternalLoader { private final SliceLoader loader; private final T bufferReference; public InternalLoader(SliceLoader loader, int bufferSize) { this.loader = loader; checkArgument(bufferSize >= 128, "Buffer size must be at least 128"); this.bufferReference = loader.createBuffer(bufferSize); } public Slice getBufferSlice() { return bufferReference.getSlice(); } public void load(long position, int length) { loader.load(position, bufferReference, length); } public void close() { loader.close(); } } } slice-0.16/src/main/java/io/airlift/slice/CountingInputStream.java000066400000000000000000000046451261474317300252010ustar00rootroot00000000000000/* * Copyright (C) 2007 The Guava Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import javax.annotation.Nullable; import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; /** * An {@link java.io.InputStream} that counts the number of bytes read. * * @author Chris Nokleberg */ final class CountingInputStream extends FilterInputStream { private long count; private long mark = -1; /** * Wraps another input stream, counting the number of bytes read. * * @param in the input stream to be wrapped */ public CountingInputStream(@Nullable InputStream in) { super(in); } /** * Returns the number of bytes read. */ public long getCount() { return count; } @Override public int read() throws IOException { int result = in.read(); if (result != -1) { count++; } return result; } @Override public int read(byte[] b, int off, int len) throws IOException { int result = in.read(b, off, len); if (result != -1) { count += result; } return result; } @Override public long skip(long n) throws IOException { long result = in.skip(n); count += result; return result; } @Override public synchronized void mark(int readlimit) { in.mark(readlimit); mark = count; // it's okay to mark even if mark isn't supported, as reset won't work } @Override public synchronized void reset() throws IOException { if (!in.markSupported()) { throw new IOException("Mark not supported"); } if (mark == -1) { throw new IOException("Mark not set"); } in.reset(); count = mark; } } slice-0.16/src/main/java/io/airlift/slice/CountingOutputStream.java000066400000000000000000000031001261474317300253630ustar00rootroot00000000000000/* * Copyright (C) 2007 The Guava Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import javax.annotation.Nullable; import java.io.FilterOutputStream; import java.io.IOException; import java.io.OutputStream; /** * An OutputStream that counts the number of bytes written. * * @author Chris Nokleberg */ final class CountingOutputStream extends FilterOutputStream { private long count; /** * Wraps another output stream, counting the number of bytes written. * * @param out the output stream to be wrapped */ public CountingOutputStream(@Nullable OutputStream out) { super(out); } /** * Returns the number of bytes written. */ public long getCount() { return count; } @Override public void write(byte[] b, int off, int len) throws IOException { out.write(b, off, len); count += len; } @Override public void write(int b) throws IOException { out.write(b); count++; } } slice-0.16/src/main/java/io/airlift/slice/DynamicSliceOutput.java000066400000000000000000000130071261474317300247740ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; import static io.airlift.slice.SizeOf.SIZE_OF_BYTE; import static io.airlift.slice.SizeOf.SIZE_OF_DOUBLE; import static io.airlift.slice.SizeOf.SIZE_OF_FLOAT; import static io.airlift.slice.SizeOf.SIZE_OF_INT; import static io.airlift.slice.SizeOf.SIZE_OF_LONG; import static io.airlift.slice.SizeOf.SIZE_OF_SHORT; public class DynamicSliceOutput extends SliceOutput { private Slice slice; private int size; public DynamicSliceOutput(int estimatedSize) { this.slice = Slices.allocate(estimatedSize); } @Override public void reset() { size = 0; } @Override public int size() { return size; } @Override public boolean isWritable() { return writableBytes() > 0; } @Override public int writableBytes() { return slice.length() - size; } @Override public void writeByte(int value) { slice = Slices.ensureSize(slice, size + SIZE_OF_BYTE); slice.setByte(size, value); size += SIZE_OF_BYTE; } @Override public void writeShort(int value) { slice = Slices.ensureSize(slice, size + SIZE_OF_SHORT); slice.setShort(size, value); size += SIZE_OF_SHORT; } @Override public void writeInt(int value) { slice = Slices.ensureSize(slice, size + SIZE_OF_INT); slice.setInt(size, value); size += SIZE_OF_INT; } @Override public void writeLong(long value) { slice = Slices.ensureSize(slice, size + SIZE_OF_LONG); slice.setLong(size, value); size += SIZE_OF_LONG; } @Override public void writeFloat(float value) { slice = Slices.ensureSize(slice, size + SIZE_OF_FLOAT); slice.setFloat(size, value); size += SIZE_OF_FLOAT; } @Override public void writeDouble(double value) { slice = Slices.ensureSize(slice, size + SIZE_OF_DOUBLE); slice.setDouble(size, value); size += SIZE_OF_DOUBLE; } @Override public void writeBytes(byte[] source) { writeBytes(source, 0, source.length); } @Override public void writeBytes(byte[] source, int sourceIndex, int length) { slice = Slices.ensureSize(slice, size + length); slice.setBytes(size, source, sourceIndex, length); size += length; } @Override public void writeBytes(Slice source) { writeBytes(source, 0, source.length()); } @Override public void writeBytes(Slice source, int sourceIndex, int length) { slice = Slices.ensureSize(slice, size + length); slice.setBytes(size, source, sourceIndex, length); size += length; } @Override public void writeBytes(InputStream in, int length) throws IOException { slice = Slices.ensureSize(slice, size + length); slice.setBytes(size, in, length); size += length; } @Override public void writeZero(int length) { slice = Slices.ensureSize(slice, size + length); super.writeZero(length); } @Override public DynamicSliceOutput appendLong(long value) { writeLong(value); return this; } @Override public DynamicSliceOutput appendDouble(double value) { writeDouble(value); return this; } @Override public DynamicSliceOutput appendInt(int value) { writeInt(value); return this; } @Override public DynamicSliceOutput appendShort(int value) { writeShort(value); return this; } @Override public DynamicSliceOutput appendByte(int value) { writeByte(value); return this; } @Override public DynamicSliceOutput appendBytes(byte[] source, int sourceIndex, int length) { write(source, sourceIndex, length); return this; } @Override public DynamicSliceOutput appendBytes(byte[] source) { writeBytes(source); return this; } @Override public DynamicSliceOutput appendBytes(Slice slice) { writeBytes(slice); return this; } @Override public Slice slice() { return slice.slice(0, size); } public Slice copySlice() { Slice copy = Slices.allocate(size); slice.getBytes(0, copy); return copy; } @Override public Slice getUnderlyingSlice() { return slice; } @Override public String toString() { StringBuilder builder = new StringBuilder("BasicSliceOutput{"); builder.append("size=").append(size); builder.append(", capacity=").append(slice.length()); builder.append('}'); return builder.toString(); } @Override public String toString(Charset charset) { return slice.toString(0, size, charset); } } slice-0.16/src/main/java/io/airlift/slice/FixedLengthSliceInput.java000066400000000000000000000016661261474317300254200ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; public abstract class FixedLengthSliceInput extends SliceInput { /** * Gets the total size of this input stream. */ public abstract long length(); /** * Gets the number of bytes remaining after the current position in this stream. */ public final long remaining() { return length() - position(); } } slice-0.16/src/main/java/io/airlift/slice/InputStreamSliceInput.java000066400000000000000000000175051261474317300254710ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PushbackInputStream; import static io.airlift.slice.Preconditions.checkNotNull; public final class InputStreamSliceInput extends SliceInput { private final PushbackInputStream pushbackInputStream; private final CountingInputStream countingInputStream; private final LittleEndianDataInputStream dataInputStream; @SuppressWarnings("IOResourceOpenedButNotSafelyClosed") public InputStreamSliceInput(InputStream inputStream) { checkNotNull(inputStream, "inputStream is null"); pushbackInputStream = new PushbackInputStream(inputStream); countingInputStream = new CountingInputStream(pushbackInputStream); dataInputStream = new LittleEndianDataInputStream(countingInputStream); } @Override public long position() { return (int) countingInputStream.getCount(); } @Override public void setPosition(long position) { throw new UnsupportedOperationException(); } @Override public boolean isReadable() { try { int value = pushbackInputStream.read(); if (value == -1) { return false; } pushbackInputStream.unread(value); return true; } catch (IOException e) { throw new RuntimeIOException(e); } } @Override public int skipBytes(int n) { try { return dataInputStream.skipBytes(n); } catch (IOException e) { throw new RuntimeIOException(e); } } @Override public float readFloat() { try { return dataInputStream.readFloat(); } catch (EOFException e) { throw new IndexOutOfBoundsException(); } catch (IOException e) { throw new RuntimeIOException(e); } } @Override public double readDouble() { try { return dataInputStream.readDouble(); } catch (EOFException e) { throw new IndexOutOfBoundsException(); } catch (IOException e) { throw new RuntimeIOException(e); } } @Override public int readUnsignedByte() { try { return dataInputStream.readUnsignedByte(); } catch (IOException e) { throw new RuntimeIOException(e); } } @Override public int readUnsignedShort() { try { return dataInputStream.readUnsignedShort(); } catch (EOFException e) { throw new IndexOutOfBoundsException(); } catch (IOException e) { throw new RuntimeIOException(e); } } @Override public int readInt() { try { return dataInputStream.readInt(); } catch (EOFException e) { throw new IndexOutOfBoundsException(); } catch (IOException e) { throw new RuntimeIOException(e); } } @Override public long readLong() { try { return dataInputStream.readLong(); } catch (EOFException e) { throw new IndexOutOfBoundsException(); } catch (IOException e) { throw new RuntimeIOException(e); } } @Override public short readShort() { try { return dataInputStream.readShort(); } catch (EOFException e) { throw new IndexOutOfBoundsException(); } catch (IOException e) { throw new RuntimeIOException(e); } } @Override public byte readByte() { try { return dataInputStream.readByte(); } catch (EOFException e) { throw new IndexOutOfBoundsException(); } catch (IOException e) { throw new RuntimeIOException(e); } } @Override public boolean readBoolean() { try { return dataInputStream.readBoolean(); } catch (EOFException e) { throw new IndexOutOfBoundsException(); } catch (IOException e) { throw new RuntimeIOException(e); } } @Override public int read() { try { return dataInputStream.read(); } catch (EOFException e) { throw new IndexOutOfBoundsException(); } catch (IOException e) { throw new RuntimeIOException(e); } } @Override public int read(byte[] b, int off, int len) { try { return dataInputStream.read(b, off, len); } catch (IOException e) { throw new RuntimeIOException(e); } } @Override public long skip(long n) { try { return dataInputStream.skip(n); } catch (IOException e) { throw new RuntimeIOException(e); } } @Override public int available() { try { return countingInputStream.available(); } catch (IOException e) { throw new RuntimeIOException(e); } } @Override public void close() { try { dataInputStream.close(); } catch (IOException e) { throw new RuntimeIOException(e); } } @Override public void readBytes(byte[] destination, int destinationIndex, int length) { try { while (length > 0) { int bytesRead = dataInputStream.read(destination, destinationIndex, length); if (bytesRead < 0) { throw new IndexOutOfBoundsException("End of stream"); } length -= bytesRead; destinationIndex += bytesRead; } } catch (IOException e) { throw new RuntimeIOException(e); } } @Override public Slice readSlice(int length) { if (length == 0) { return Slices.EMPTY_SLICE; } try { Slice newSlice = Slices.allocate(length); newSlice.setBytes(0, countingInputStream, length); return newSlice; } catch (EOFException e) { throw new IndexOutOfBoundsException(); } catch (IOException e) { throw new RuntimeIOException(e); } } @Override public void readBytes(Slice destination, int destinationIndex, int length) { try { destination.setBytes(destinationIndex, countingInputStream, length); } catch (EOFException e) { throw new IndexOutOfBoundsException(); } catch (IOException e) { throw new RuntimeIOException(e); } } @Override public void readBytes(OutputStream out, int length) throws IOException { try { SliceStreamUtils.copyStreamFully(this, out, length); } catch (EOFException e) { // EOFException is thrown if this stream does not have the requested data available throw new IndexOutOfBoundsException(); } } } slice-0.16/src/main/java/io/airlift/slice/InvalidCodePointException.java000066400000000000000000000017511261474317300262640ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import static java.lang.Integer.toHexString; public class InvalidCodePointException extends IllegalArgumentException { private final int codePoint; public InvalidCodePointException(int codePoint) { super("Invalid code point 0x" + toHexString(codePoint).toUpperCase()); this.codePoint = codePoint; } public int getCodePoint() { return codePoint; } } slice-0.16/src/main/java/io/airlift/slice/InvalidUtf8Exception.java000066400000000000000000000013601261474317300252220ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; public class InvalidUtf8Exception extends IllegalArgumentException { public InvalidUtf8Exception(String message) { super(message); } } slice-0.16/src/main/java/io/airlift/slice/JvmUtils.java000066400000000000000000000062661261474317300227750ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import sun.misc.Unsafe; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.nio.ByteBuffer; import static sun.misc.Unsafe.ARRAY_BOOLEAN_INDEX_SCALE; import static sun.misc.Unsafe.ARRAY_BYTE_INDEX_SCALE; import static sun.misc.Unsafe.ARRAY_DOUBLE_INDEX_SCALE; import static sun.misc.Unsafe.ARRAY_FLOAT_INDEX_SCALE; import static sun.misc.Unsafe.ARRAY_INT_INDEX_SCALE; import static sun.misc.Unsafe.ARRAY_LONG_INDEX_SCALE; import static sun.misc.Unsafe.ARRAY_SHORT_INDEX_SCALE; final class JvmUtils { static final Unsafe unsafe; static final MethodHandle newByteBuffer; static { try { // fetch theUnsafe object Field field = Unsafe.class.getDeclaredField("theUnsafe"); field.setAccessible(true); unsafe = (Unsafe) field.get(null); if (unsafe == null) { throw new RuntimeException("Unsafe access not available"); } // verify the stride of arrays matches the width of primitives assertArrayIndexScale("Boolean", ARRAY_BOOLEAN_INDEX_SCALE, 1); assertArrayIndexScale("Byte", ARRAY_BYTE_INDEX_SCALE, 1); assertArrayIndexScale("Short", ARRAY_SHORT_INDEX_SCALE, 2); assertArrayIndexScale("Int", ARRAY_INT_INDEX_SCALE, 4); assertArrayIndexScale("Long", ARRAY_LONG_INDEX_SCALE, 8); assertArrayIndexScale("Float", ARRAY_FLOAT_INDEX_SCALE, 4); assertArrayIndexScale("Double", ARRAY_DOUBLE_INDEX_SCALE, 8); // fetch a method handle for the hidden constructor for DirectByteBuffer Class directByteBufferClass = ClassLoader.getSystemClassLoader().loadClass("java.nio.DirectByteBuffer"); Constructor constructor = directByteBufferClass.getDeclaredConstructor(long.class, int.class, Object.class); constructor.setAccessible(true); newByteBuffer = MethodHandles.lookup().unreflectConstructor(constructor) .asType(MethodType.methodType(ByteBuffer.class, long.class, int.class, Object.class)); } catch (Exception e) { throw new RuntimeException(e); } } private static void assertArrayIndexScale(final String name, int actualIndexScale, int expectedIndexScale) { if (actualIndexScale != expectedIndexScale) { throw new IllegalStateException(name + " array index scale must be " + expectedIndexScale + ", but is " + actualIndexScale); } } private JvmUtils() {} } slice-0.16/src/main/java/io/airlift/slice/LittleEndianDataInputStream.java000066400000000000000000000203401261474317300265470ustar00rootroot00000000000000/* * Copyright (C) 2007 The Guava Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import java.io.DataInput; import java.io.DataInputStream; import java.io.EOFException; import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; import static io.airlift.slice.Preconditions.checkNotNull; /** * An implementation of {@link java.io.DataInput} that uses little-endian byte ordering * for reading {@code short}, {@code int}, {@code float}, {@code double}, and * {@code long} values. *

* Note: This class intentionally violates the specification of its * supertype {@code DataInput}, which explicitly requires big-endian byte order. * * @author Chris Nokleberg * @author Keith Bottner * @since 8.0 */ final class LittleEndianDataInputStream extends FilterInputStream implements DataInput { /** * Creates a {@code LittleEndianDataInputStream} that wraps the given stream. * * @param in the stream to delegate to */ public LittleEndianDataInputStream(InputStream in) { super(checkNotNull(in, "in is null")); } /** * This method will throw an {@link UnsupportedOperationException}. */ @Override public String readLine() { throw new UnsupportedOperationException("readLine is not supported"); } @Override public void readFully(byte[] b) throws IOException { readFully(b, 0, b.length); } @Override public void readFully(byte[] b, int offset, int length) throws IOException { checkNotNull(b, "byte array is null"); if (length < 0) { throw new IndexOutOfBoundsException("length is negative"); } int total = 0; while (total < length) { int result = read(b, offset + total, length - total); if (result == -1) { break; } total += result; } if (total != length) { throw new EOFException("reached end of stream after reading " + total + " bytes; " + length + " bytes expected"); } } @Override public int skipBytes(int n) throws IOException { return (int) in.skip(n); } @Override public int readUnsignedByte() throws IOException { int b1 = in.read(); if (0 > b1) { throw new EOFException(); } return b1; } /** * Reads an unsigned {@code short} as specified by * {@link java.io.DataInputStream#readUnsignedShort()}, except using little-endian * byte order. * * @return the next two bytes of the input stream, interpreted as an * unsigned 16-bit integer in little-endian byte order * @throws java.io.IOException if an I/O error occurs */ @Override public int readUnsignedShort() throws IOException { byte b1 = readAndCheckByte(); byte b2 = readAndCheckByte(); return intFromBytes(b1, b2, (byte) 0, (byte) 0); } /** * Reads an integer as specified by {@link java.io.DataInputStream#readInt()}, except * using little-endian byte order. * * @return the next four bytes of the input stream, interpreted as an * {@code int} in little-endian byte order * @throws java.io.IOException if an I/O error occurs */ @Override public int readInt() throws IOException { byte b1 = readAndCheckByte(); byte b2 = readAndCheckByte(); byte b3 = readAndCheckByte(); byte b4 = readAndCheckByte(); return intFromBytes(b1, b2, b3, b4); } /** * Reads a {@code long} as specified by {@link java.io.DataInputStream#readLong()}, * except using little-endian byte order. * * @return the next eight bytes of the input stream, interpreted as a * {@code long} in little-endian byte order * @throws java.io.IOException if an I/O error occurs */ @Override public long readLong() throws IOException { byte b1 = readAndCheckByte(); byte b2 = readAndCheckByte(); byte b3 = readAndCheckByte(); byte b4 = readAndCheckByte(); byte b5 = readAndCheckByte(); byte b6 = readAndCheckByte(); byte b7 = readAndCheckByte(); byte b8 = readAndCheckByte(); return longFromBytes(b1, b2, b3, b4, b5, b6, b7, b8); } /** * Reads a {@code float} as specified by {@link java.io.DataInputStream#readFloat()}, * except using little-endian byte order. * * @return the next four bytes of the input stream, interpreted as a * {@code float} in little-endian byte order * @throws java.io.IOException if an I/O error occurs */ @Override public float readFloat() throws IOException { return Float.intBitsToFloat(readInt()); } /** * Reads a {@code double} as specified by * {@link java.io.DataInputStream#readDouble()}, except using little-endian byte * order. * * @return the next eight bytes of the input stream, interpreted as a * {@code double} in little-endian byte order * @throws java.io.IOException if an I/O error occurs */ @Override public double readDouble() throws IOException { return Double.longBitsToDouble(readLong()); } @Override public String readUTF() throws IOException { return new DataInputStream(in).readUTF(); } /** * Reads a {@code short} as specified by {@link java.io.DataInputStream#readShort()}, * except using little-endian byte order. * * @return the next two bytes of the input stream, interpreted as a * {@code short} in little-endian byte order. * @throws java.io.IOException if an I/O error occurs. */ @Override public short readShort() throws IOException { return (short) readUnsignedShort(); } /** * Reads a char as specified by {@link java.io.DataInputStream#readChar()}, except * using little-endian byte order. * * @return the next two bytes of the input stream, interpreted as a * {@code char} in little-endian byte order * @throws java.io.IOException if an I/O error occurs */ @Override public char readChar() throws IOException { return (char) readUnsignedShort(); } @Override public byte readByte() throws IOException { return (byte) readUnsignedByte(); } @Override public boolean readBoolean() throws IOException { return readUnsignedByte() != 0; } /** * Reads a byte from the input stream checking that the end of file (EOF) * has not been encountered. * * @return byte read from input * @throws java.io.IOException if an error is encountered while reading * @throws java.io.EOFException if the end of file (EOF) is encountered. */ private byte readAndCheckByte() throws IOException { int b1 = in.read(); if (-1 == b1) { throw new EOFException(); } return (byte) b1; } private static int intFromBytes(byte b1, byte b2, byte b3, byte b4) { return b4 << 24 | (b3 & 0xFF) << 16 | (b2 & 0xFF) << 8 | (b1 & 0xFF); } private static long longFromBytes(byte b1, byte b2, byte b3, byte b4, byte b5, byte b6, byte b7, byte b8) { return (b8 & 0xFFL) << 56 | (b7 & 0xFFL) << 48 | (b6 & 0xFFL) << 40 | (b5 & 0xFFL) << 32 | (b4 & 0xFFL) << 24 | (b3 & 0xFFL) << 16 | (b2 & 0xFFL) << 8 | (b1 & 0xFFL); } } slice-0.16/src/main/java/io/airlift/slice/LittleEndianDataOutputStream.java000066400000000000000000000127441261474317300267610ustar00rootroot00000000000000/* * Copyright (C) 2007 The Guava Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import java.io.DataOutput; import java.io.DataOutputStream; import java.io.FilterOutputStream; import java.io.IOException; import java.io.OutputStream; import static io.airlift.slice.Preconditions.checkNotNull; /** * An implementation of {@link java.io.DataOutput} that uses little-endian byte ordering * for writing {@code char}, {@code short}, {@code int}, {@code float}, {@code * double}, and {@code long} values. *

* Note: This class intentionally violates the specification of its * supertype {@code DataOutput}, which explicitly requires big-endian byte * order. * * @author Chris Nokleberg * @author Keith Bottner */ final class LittleEndianDataOutputStream extends FilterOutputStream implements DataOutput { /** * Creates a {@code LittleEndianDataOutputStream} that wraps the given stream. * * @param out the stream to delegate to */ public LittleEndianDataOutputStream(OutputStream out) { super(new DataOutputStream(checkNotNull(out, "out is null"))); } @Override public void write(byte[] b, int off, int len) throws IOException { // Override slow FilterOutputStream impl out.write(b, off, len); } @Override public void writeBoolean(boolean v) throws IOException { ((DataOutputStream) out).writeBoolean(v); } @Override public void writeByte(int v) throws IOException { ((DataOutputStream) out).writeByte(v); } /** * @deprecated The semantics of {@code writeBytes(String s)} are considered * dangerous. Please use {@link #writeUTF(String s)}, * {@link #writeChars(String s)} or another write method instead. */ @Deprecated @Override public void writeBytes(String s) throws IOException { ((DataOutputStream) out).writeBytes(s); } /** * Writes a char as specified by {@link java.io.DataOutputStream#writeChar(int)}, * except using little-endian byte order. * * @throws java.io.IOException if an I/O error occurs */ @Override public void writeChar(int v) throws IOException { writeShort(v); } /** * Writes a {@code String} as specified by * {@link java.io.DataOutputStream#writeChars(String)}, except each character is * written using little-endian byte order. * * @throws java.io.IOException if an I/O error occurs */ @Override public void writeChars(String s) throws IOException { for (int i = 0; i < s.length(); i++) { writeChar(s.charAt(i)); } } /** * Writes a {@code double} as specified by * {@link java.io.DataOutputStream#writeDouble(double)}, except using little-endian * byte order. * * @throws java.io.IOException if an I/O error occurs */ @Override public void writeDouble(double v) throws IOException { writeLong(Double.doubleToLongBits(v)); } /** * Writes a {@code float} as specified by * {@link java.io.DataOutputStream#writeFloat(float)}, except using little-endian byte * order. * * @throws java.io.IOException if an I/O error occurs */ @Override public void writeFloat(float v) throws IOException { writeInt(Float.floatToIntBits(v)); } /** * Writes an {@code int} as specified by * {@link java.io.DataOutputStream#writeInt(int)}, except using little-endian byte * order. * * @throws java.io.IOException if an I/O error occurs */ @Override public void writeInt(int v) throws IOException { out.write(0xFF & v); out.write(0xFF & (v >> 8)); out.write(0xFF & (v >> 16)); out.write(0xFF & (v >> 24)); } /** * Writes a {@code long} as specified by * {@link java.io.DataOutputStream#writeLong(long)}, except using little-endian byte * order. * * @throws java.io.IOException if an I/O error occurs */ @Override public void writeLong(long value) throws IOException { value = Long.reverseBytes(value); byte[] bytes = new byte[8]; for (int i = 7; i >= 0; i--) { bytes[i] = (byte) (value & 0xffL); value >>= 8; } write(bytes, 0, bytes.length); } /** * Writes a {@code short} as specified by * {@link java.io.DataOutputStream#writeShort(int)}, except using little-endian byte * order. * * @throws java.io.IOException if an I/O error occurs */ @Override public void writeShort(int v) throws IOException { out.write(0xFF & v); out.write(0xFF & (v >> 8)); } @Override public void writeUTF(String str) throws IOException { ((DataOutputStream) out).writeUTF(str); } } slice-0.16/src/main/java/io/airlift/slice/Murmur3.java000066400000000000000000000032721261474317300225640ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; @Deprecated public class Murmur3 { public static Slice hash(Slice data) { return Murmur3Hash128.hash(data); } public static Slice hash(Slice data, int offset, int length) { return Murmur3Hash128.hash(data, offset, length); } public static Slice hash(long seed, Slice data, int offset, int length) { return Murmur3Hash128.hash(seed, data, offset, length); } /** * Returns the 64 most significant bits of the Murmur128 hash of the provided value */ public static long hash64(Slice data) { return Murmur3Hash128.hash64(data); } public static long hash64(Slice data, int offset, int length) { return Murmur3Hash128.hash64(data, offset, length); } public static long hash64(long seed, Slice data, int offset, int length) { return Murmur3Hash128.hash64(seed, data, offset, length); } /** * Special-purpose version for hashing a single long value. Value is treated as little-endian */ public static long hash64(long value) { return Murmur3Hash128.hash64(value); } } slice-0.16/src/main/java/io/airlift/slice/Murmur3Hash128.java000066400000000000000000000166701261474317300236310ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; public class Murmur3Hash128 { private static final long C1 = 0x87c37b91114253d5L; private static final long C2 = 0x4cf5ad432745937fL; private final static long DEFAULT_SEED = 0; public static Slice hash(Slice data) { return hash(data, 0, data.length()); } public static Slice hash(Slice data, int offset, int length) { return hash(DEFAULT_SEED, data, offset, length); } public static Slice hash(long seed, Slice data, int offset, int length) { final int fastLimit = offset + length - (2 * SizeOf.SIZE_OF_LONG) + 1; long h1 = seed; long h2 = seed; int current = offset; while (current < fastLimit) { long k1 = data.getLong(current); current += SizeOf.SIZE_OF_LONG; long k2 = data.getLong(current); current += SizeOf.SIZE_OF_LONG; k1 *= C1; k1 = Long.rotateLeft(k1, 31); k1 *= C2; h1 ^= k1; h1 = Long.rotateLeft(h1, 27); h1 += h2; h1 = h1 * 5 + 0x52dce729L; k2 *= C2; k2 = Long.rotateLeft(k2, 33); k2 *= C1; h2 ^= k2; h2 = Long.rotateLeft(h2, 31); h2 += h1; h2 = h2 * 5 + 0x38495ab5L; } long k1 = 0; long k2 = 0; switch (length & 15) { case 15: k2 ^= ((long) data.getUnsignedByte(current + 14)) << 48; case 14: k2 ^= ((long) data.getUnsignedByte(current + 13)) << 40; case 13: k2 ^= ((long) data.getUnsignedByte(current + 12)) << 32; case 12: k2 ^= ((long) data.getUnsignedByte(current + 11)) << 24; case 11: k2 ^= ((long) data.getUnsignedByte(current + 10)) << 16; case 10: k2 ^= ((long) data.getUnsignedByte(current + 9)) << 8; case 9: k2 ^= ((long) data.getUnsignedByte(current + 8)) << 0; k2 *= C2; k2 = Long.rotateLeft(k2, 33); k2 *= C1; h2 ^= k2; case 8: k1 ^= ((long) data.getUnsignedByte(current + 7)) << 56; case 7: k1 ^= ((long) data.getUnsignedByte(current + 6)) << 48; case 6: k1 ^= ((long) data.getUnsignedByte(current + 5)) << 40; case 5: k1 ^= ((long) data.getUnsignedByte(current + 4)) << 32; case 4: k1 ^= ((long) data.getUnsignedByte(current + 3)) << 24; case 3: k1 ^= ((long) data.getUnsignedByte(current + 2)) << 16; case 2: k1 ^= ((long) data.getUnsignedByte(current + 1)) << 8; case 1: k1 ^= ((long) data.getUnsignedByte(current + 0)) << 0; k1 *= C1; k1 = Long.rotateLeft(k1, 31); k1 *= C2; h1 ^= k1; } h1 ^= length; h2 ^= length; h1 += h2; h2 += h1; h1 = mix64(h1); h2 = mix64(h2); h1 += h2; h2 += h1; Slice result = Slices.allocate(16); result.setLong(0, h1); result.setLong(8, h2); return result; } /** * Returns the 64 most significant bits of the Murmur128 hash of the provided value */ public static long hash64(Slice data) { return hash64(data, 0, data.length()); } public static long hash64(Slice data, int offset, int length) { return hash64(DEFAULT_SEED, data, offset, length); } public static long hash64(long seed, Slice data, int offset, int length) { final int fastLimit = offset + length - (2 * SizeOf.SIZE_OF_LONG) + 1; long h1 = seed; long h2 = seed; int current = offset; while (current < fastLimit) { long k1 = data.getLong(current); current += SizeOf.SIZE_OF_LONG; long k2 = data.getLong(current); current += SizeOf.SIZE_OF_LONG; k1 *= C1; k1 = Long.rotateLeft(k1, 31); k1 *= C2; h1 ^= k1; h1 = Long.rotateLeft(h1, 27); h1 += h2; h1 = h1 * 5 + 0x52dce729L; k2 *= C2; k2 = Long.rotateLeft(k2, 33); k2 *= C1; h2 ^= k2; h2 = Long.rotateLeft(h2, 31); h2 += h1; h2 = h2 * 5 + 0x38495ab5L; } long k1 = 0; long k2 = 0; switch (length & 15) { case 15: k2 ^= ((long) data.getUnsignedByte(current + 14)) << 48; case 14: k2 ^= ((long) data.getUnsignedByte(current + 13)) << 40; case 13: k2 ^= ((long) data.getUnsignedByte(current + 12)) << 32; case 12: k2 ^= ((long) data.getUnsignedByte(current + 11)) << 24; case 11: k2 ^= ((long) data.getUnsignedByte(current + 10)) << 16; case 10: k2 ^= ((long) data.getUnsignedByte(current + 9)) << 8; case 9: k2 ^= ((long) data.getUnsignedByte(current + 8)) << 0; k2 *= C2; k2 = Long.rotateLeft(k2, 33); k2 *= C1; h2 ^= k2; case 8: k1 ^= ((long) data.getUnsignedByte(current + 7)) << 56; case 7: k1 ^= ((long) data.getUnsignedByte(current + 6)) << 48; case 6: k1 ^= ((long) data.getUnsignedByte(current + 5)) << 40; case 5: k1 ^= ((long) data.getUnsignedByte(current + 4)) << 32; case 4: k1 ^= ((long) data.getUnsignedByte(current + 3)) << 24; case 3: k1 ^= ((long) data.getUnsignedByte(current + 2)) << 16; case 2: k1 ^= ((long) data.getUnsignedByte(current + 1)) << 8; case 1: k1 ^= ((long) data.getUnsignedByte(current + 0)) << 0; k1 *= C1; k1 = Long.rotateLeft(k1, 31); k1 *= C2; h1 ^= k1; } h1 ^= length; h2 ^= length; h1 += h2; h2 += h1; h1 = mix64(h1); h2 = mix64(h2); return h1 + h2; } /** * Special-purpose version for hashing a single long value. Value is treated as little-endian */ public static long hash64(long value) { long h2 = DEFAULT_SEED ^ SizeOf.SIZE_OF_LONG; long h1 = h2 + (h2 ^ (Long.rotateLeft(value * C1, 31) * C2)); return mix64(h1) + mix64(h1 + h2); } private static long mix64(long k) { k ^= k >>> 33; k *= 0xff51afd7ed558ccdL; k ^= k >>> 33; k *= 0xc4ceb9fe1a85ec53L; k ^= k >>> 33; return k; } } slice-0.16/src/main/java/io/airlift/slice/Murmur3Hash32.java000066400000000000000000000057471261474317300235460ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; public final class Murmur3Hash32 { private static final int C1 = 0xcc9e2d51; private static final int C2 = 0x1b873593; private final static int DEFAULT_SEED = 0; private Murmur3Hash32() {} public static int hash(Slice data) { return hash(data, 0, data.length()); } public static int hash(Slice data, int offset, int length) { return hash(DEFAULT_SEED, data, offset, length); } public static int hash(int seed, Slice data, int offset, int length) { final int fastLimit = offset + length - SizeOf.SIZE_OF_INT + 1; int h1 = seed; int current = offset; while (current < fastLimit) { int k1 = mixK1(data.getInt(current)); current += SizeOf.SIZE_OF_INT; h1 = mixH1(h1, k1); } int k1 = 0; switch (length & 3) { case 3: k1 ^= ((int) data.getUnsignedByte(current + 2)) << 16; case 2: k1 ^= ((int) data.getUnsignedByte(current + 1)) << 8; case 1: k1 ^= ((int) data.getUnsignedByte(current + 0)) << 0; } h1 ^= mixK1(k1); return fmix(h1, length); } /** * Special-purpose version for hashing a single int value. Value is treated as little-endian */ public static int hash(int input) { int k1 = mixK1(input); int h1 = mixH1(DEFAULT_SEED, k1); return fmix(h1, SizeOf.SIZE_OF_INT); } /** * Special-purpose version for hashing a single long value. Value is treated as little-endian */ public static int hash(long input) { int low = (int) input; int high = (int) (input >>> 32); int k1 = mixK1(low); int h1 = mixH1(DEFAULT_SEED, k1); k1 = mixK1(high); h1 = mixH1(h1, k1); return fmix(h1, SizeOf.SIZE_OF_LONG); } private static int mixK1(int k1) { k1 *= C1; k1 = Integer.rotateLeft(k1, 15); k1 *= C2; return k1; } private static int mixH1(int h1, int k1) { h1 ^= k1; h1 = Integer.rotateLeft(h1, 13); h1 = h1 * 5 + 0xe6546b64; return h1; } private static int fmix(int h1, int length) { h1 ^= length; h1 ^= h1 >>> 16; h1 *= 0x85ebca6b; h1 ^= h1 >>> 13; h1 *= 0xc2b2ae35; h1 ^= h1 >>> 16; return h1; } } slice-0.16/src/main/java/io/airlift/slice/OutputStreamSliceOutput.java000066400000000000000000000141441261474317300260670ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.charset.Charset; import static io.airlift.slice.Preconditions.checkArgument; import static io.airlift.slice.Preconditions.checkNotNull; public class OutputStreamSliceOutput extends SliceOutput { private final CountingOutputStream countingOutputStream; // Used only to track byte usage private final LittleEndianDataOutputStream dataOutputStream; @SuppressWarnings("IOResourceOpenedButNotSafelyClosed") public OutputStreamSliceOutput(OutputStream outputStream) { checkNotNull(outputStream, "outputStream is null"); countingOutputStream = new CountingOutputStream(outputStream); dataOutputStream = new LittleEndianDataOutputStream(countingOutputStream); } @Override public void flush() throws IOException { countingOutputStream.flush(); } @Override public void close() throws IOException { countingOutputStream.close(); } @Override public void reset() { throw new UnsupportedOperationException("OutputStream can not be reset"); } @Override public int size() { return checkedCast(countingOutputStream.getCount()); } @Override public int writableBytes() { return Integer.MAX_VALUE; } @Override public boolean isWritable() { return true; } @Override public void writeByte(int value) { try { dataOutputStream.writeByte(value); } catch (IOException e) { throw new RuntimeIOException(e); } } @Override public void writeShort(int value) { try { dataOutputStream.writeShort(value); } catch (IOException e) { throw new RuntimeIOException(e); } } @Override public void writeInt(int value) { try { dataOutputStream.writeInt(value); } catch (IOException e) { throw new RuntimeIOException(e); } } @Override public void writeLong(long value) { try { dataOutputStream.writeLong(value); } catch (IOException e) { throw new RuntimeIOException(e); } } @Override public void writeFloat(float value) { try { dataOutputStream.writeFloat(value); } catch (IOException e) { throw new RuntimeIOException(e); } } @Override public void writeDouble(double value) { try { dataOutputStream.writeDouble(value); } catch (IOException e) { throw new RuntimeIOException(e); } } @Override public void writeBytes(Slice source) { writeBytes(source, 0, source.length()); } @Override public void writeBytes(Slice source, int sourceIndex, int length) { try { source.getBytes(sourceIndex, dataOutputStream, length); } catch (IOException e) { throw new RuntimeIOException(e); } } @Override public void writeBytes(byte[] source) { writeBytes(source, 0, source.length); } @Override public void writeBytes(byte[] source, int sourceIndex, int length) { try { dataOutputStream.write(source, sourceIndex, length); } catch (IOException e) { throw new RuntimeIOException(e); } } @Override public void writeBytes(InputStream in, int length) throws IOException { SliceStreamUtils.copyStreamFully(in, this, length); } @Override public SliceOutput appendLong(long value) { writeLong(value); return this; } @Override public SliceOutput appendDouble(double value) { writeDouble(value); return this; } @Override public SliceOutput appendInt(int value) { writeInt(value); return this; } @Override public SliceOutput appendShort(int value) { writeShort(value); return this; } @Override public SliceOutput appendByte(int value) { writeByte(value); return this; } @Override public SliceOutput appendBytes(byte[] source, int sourceIndex, int length) { writeBytes(source, sourceIndex, length); return this; } @Override public SliceOutput appendBytes(byte[] source) { writeBytes(source); return this; } @Override public SliceOutput appendBytes(Slice slice) { writeBytes(slice); return this; } @Override public Slice slice() { throw new UnsupportedOperationException(); } @Override public Slice getUnderlyingSlice() { throw new UnsupportedOperationException(); } @Override public String toString(Charset charset) { return toString(); } @Override public String toString() { StringBuilder builder = new StringBuilder("BasicSliceOutput{"); builder.append("countingOutputStream=").append(countingOutputStream); builder.append(", dataOutputStream=").append(dataOutputStream); builder.append('}'); return builder.toString(); } private static int checkedCast(long value) { int result = (int) value; checkArgument(result == value, "Size is greater than maximum int value"); return result; } } slice-0.16/src/main/java/io/airlift/slice/Preconditions.java000066400000000000000000000112651261474317300240330ustar00rootroot00000000000000/* * Copyright (C) 2007 The Guava Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import javax.annotation.Nullable; // forked from com.google.common.base.Preconditions final class Preconditions { private Preconditions() { } public static T checkNotNull(T reference, String errorMessage) { if (reference == null) { throw new NullPointerException(errorMessage); } return reference; } public static void checkArgument(boolean expression, String errorMessage) { if (!expression) { throw new IllegalArgumentException(errorMessage); } } public static void checkArgument(boolean expression, @Nullable String errorMessageTemplate, @Nullable Object... errorMessageArgs) { if (!expression) { throw new IllegalArgumentException(format(errorMessageTemplate, errorMessageArgs)); } } public static int checkPositionIndex(int index, int size) { return checkPositionIndex(index, size, "index"); } public static int checkPositionIndex(int index, int size, @Nullable String desc) { // Carefully optimized for execution by hotspot (explanatory comment above) if (index < 0 || index > size) { throw new IndexOutOfBoundsException(badPositionIndex(index, size, desc)); } return index; } public static long checkPositionIndex(long index, long size) { return checkPositionIndex(index, size, "index"); } public static long checkPositionIndex(long index, long size, @Nullable String desc) { // Carefully optimized for execution by hotspot (explanatory comment above) if (index < 0 || index > size) { throw new IndexOutOfBoundsException(badPositionIndex(index, size, desc)); } return index; } private static String badPositionIndex(long index, long size, String desc) { if (index < 0) { return format("%s (%s) must not be negative", desc, index); } else if (size < 0) { throw new IllegalArgumentException("negative size: " + size); } else { // index > size return format("%s (%s) must not be greater than size (%s)", desc, index, size); } } public static void checkPositionIndexes(int start, int end, int size) { // Carefully optimized for execution by hotspot (explanatory comment above) if (start < 0 || end < start || end > size) { throw new IndexOutOfBoundsException(badPositionIndexes(start, end, size)); } } private static String badPositionIndexes(int start, int end, int size) { if (start < 0 || start > size) { return badPositionIndex(start, size, "start index"); } if (end < 0 || end > size) { return badPositionIndex(end, size, "end index"); } // end < start return format("end index (%s) must not be less than start index (%s)", end, start); } private static String format(String template, Object... args) { template = String.valueOf(template); // null -> "null" // start substituting the arguments into the '%s' placeholders StringBuilder builder = new StringBuilder(template.length() + 16 * args.length); int templateStart = 0; int i = 0; while (i < args.length) { int placeholderStart = template.indexOf("%s", templateStart); if (placeholderStart == -1) { break; } builder.append(template.substring(templateStart, placeholderStart)); builder.append(args[i++]); templateStart = placeholderStart + 2; } builder.append(template.substring(templateStart)); // if we run out of placeholders, append the extra args in square braces if (i < args.length) { builder.append(" ["); builder.append(args[i++]); while (i < args.length) { builder.append(", "); builder.append(args[i++]); } builder.append(']'); } return builder.toString(); } } slice-0.16/src/main/java/io/airlift/slice/RuntimeIOException.java000066400000000000000000000014021261474317300247350ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import java.io.IOException; public class RuntimeIOException extends RuntimeException { public RuntimeIOException(IOException cause) { super(cause); } } slice-0.16/src/main/java/io/airlift/slice/SizeOf.java000066400000000000000000000120741261474317300224110ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import static sun.misc.Unsafe.ARRAY_BOOLEAN_BASE_OFFSET; import static sun.misc.Unsafe.ARRAY_BOOLEAN_INDEX_SCALE; import static sun.misc.Unsafe.ARRAY_BYTE_BASE_OFFSET; import static sun.misc.Unsafe.ARRAY_BYTE_INDEX_SCALE; import static sun.misc.Unsafe.ARRAY_CHAR_BASE_OFFSET; import static sun.misc.Unsafe.ARRAY_CHAR_INDEX_SCALE; import static sun.misc.Unsafe.ARRAY_DOUBLE_BASE_OFFSET; import static sun.misc.Unsafe.ARRAY_DOUBLE_INDEX_SCALE; import static sun.misc.Unsafe.ARRAY_FLOAT_BASE_OFFSET; import static sun.misc.Unsafe.ARRAY_FLOAT_INDEX_SCALE; import static sun.misc.Unsafe.ARRAY_INT_BASE_OFFSET; import static sun.misc.Unsafe.ARRAY_INT_INDEX_SCALE; import static sun.misc.Unsafe.ARRAY_LONG_BASE_OFFSET; import static sun.misc.Unsafe.ARRAY_LONG_INDEX_SCALE; import static sun.misc.Unsafe.ARRAY_OBJECT_BASE_OFFSET; import static sun.misc.Unsafe.ARRAY_OBJECT_INDEX_SCALE; import static sun.misc.Unsafe.ARRAY_SHORT_BASE_OFFSET; import static sun.misc.Unsafe.ARRAY_SHORT_INDEX_SCALE; public final class SizeOf { public static final byte SIZE_OF_BYTE = 1; public static final byte SIZE_OF_SHORT = 2; public static final byte SIZE_OF_INT = 4; public static final byte SIZE_OF_LONG = 8; public static final byte SIZE_OF_FLOAT = 4; public static final byte SIZE_OF_DOUBLE = 8; public static long sizeOf(boolean[] array) { if (array == null) { return 0; } return ARRAY_BOOLEAN_BASE_OFFSET + (((long) ARRAY_BOOLEAN_INDEX_SCALE) * array.length); } public static long sizeOf(byte[] array) { if (array == null) { return 0; } return ARRAY_BYTE_BASE_OFFSET + (((long) ARRAY_BYTE_INDEX_SCALE) * array.length); } public static long sizeOf(short[] array) { if (array == null) { return 0; } return ARRAY_SHORT_BASE_OFFSET + (((long) ARRAY_SHORT_INDEX_SCALE) * array.length); } public static long sizeOf(char[] array) { if (array == null) { return 0; } return ARRAY_CHAR_BASE_OFFSET + (((long) ARRAY_CHAR_INDEX_SCALE) * array.length); } public static long sizeOf(int[] array) { if (array == null) { return 0; } return ARRAY_INT_BASE_OFFSET + (((long) ARRAY_INT_INDEX_SCALE) * array.length); } public static long sizeOf(long[] array) { if (array == null) { return 0; } return ARRAY_LONG_BASE_OFFSET + (((long) ARRAY_LONG_INDEX_SCALE) * array.length); } public static long sizeOf(float[] array) { if (array == null) { return 0; } return ARRAY_FLOAT_BASE_OFFSET + (((long) ARRAY_FLOAT_INDEX_SCALE) * array.length); } public static long sizeOf(double[] array) { if (array == null) { return 0; } return ARRAY_DOUBLE_BASE_OFFSET + (((long) ARRAY_DOUBLE_INDEX_SCALE) * array.length); } public static long sizeOf(Object[] array) { if (array == null) { return 0; } return ARRAY_OBJECT_BASE_OFFSET + (((long) ARRAY_OBJECT_INDEX_SCALE) * array.length); } public static long sizeOfBooleanArray(int length) { return ARRAY_BOOLEAN_BASE_OFFSET + (((long) ARRAY_BOOLEAN_INDEX_SCALE) * length); } public static long sizeOfByteArray(int length) { return ARRAY_BYTE_BASE_OFFSET + (((long) ARRAY_BYTE_INDEX_SCALE) * length); } public static long sizeOfShortArray(int length) { return ARRAY_SHORT_BASE_OFFSET + (((long) ARRAY_SHORT_INDEX_SCALE) * length); } public static long sizeOfCharArray(int length) { return ARRAY_CHAR_BASE_OFFSET + (((long) ARRAY_CHAR_INDEX_SCALE) * length); } public static long sizeOfIntArray(int length) { return ARRAY_INT_BASE_OFFSET + (((long) ARRAY_INT_INDEX_SCALE) * length); } public static long sizeOfLongArray(int length) { return ARRAY_LONG_BASE_OFFSET + (((long) ARRAY_LONG_INDEX_SCALE) * length); } public static long sizeOfFloatArray(int length) { return ARRAY_FLOAT_BASE_OFFSET + (((long) ARRAY_FLOAT_INDEX_SCALE) * length); } public static long sizeOfDoubleArray(int length) { return ARRAY_DOUBLE_BASE_OFFSET + (((long) ARRAY_DOUBLE_INDEX_SCALE) * length); } public static long sizeOfObjectArray(int length) { return ARRAY_OBJECT_BASE_OFFSET + (((long) ARRAY_OBJECT_INDEX_SCALE) * length); } private SizeOf() { } } slice-0.16/src/main/java/io/airlift/slice/Slice.java000066400000000000000000001136741261474317300222610ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import sun.misc.Unsafe; import javax.annotation.Nullable; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.charset.Charset; import static io.airlift.slice.JvmUtils.newByteBuffer; import static io.airlift.slice.JvmUtils.unsafe; import static io.airlift.slice.Preconditions.checkArgument; import static io.airlift.slice.Preconditions.checkNotNull; import static io.airlift.slice.Preconditions.checkPositionIndexes; import static io.airlift.slice.SizeOf.SIZE_OF_BYTE; import static io.airlift.slice.SizeOf.SIZE_OF_DOUBLE; import static io.airlift.slice.SizeOf.SIZE_OF_FLOAT; import static io.airlift.slice.SizeOf.SIZE_OF_INT; import static io.airlift.slice.SizeOf.SIZE_OF_LONG; import static io.airlift.slice.SizeOf.SIZE_OF_SHORT; import static io.airlift.slice.StringDecoder.decodeString; import static java.lang.Math.min; import static java.lang.String.format; import static java.nio.charset.StandardCharsets.UTF_8; import static sun.misc.Unsafe.ARRAY_BOOLEAN_BASE_OFFSET; import static sun.misc.Unsafe.ARRAY_BOOLEAN_INDEX_SCALE; import static sun.misc.Unsafe.ARRAY_BYTE_BASE_OFFSET; import static sun.misc.Unsafe.ARRAY_DOUBLE_BASE_OFFSET; import static sun.misc.Unsafe.ARRAY_DOUBLE_INDEX_SCALE; import static sun.misc.Unsafe.ARRAY_FLOAT_BASE_OFFSET; import static sun.misc.Unsafe.ARRAY_FLOAT_INDEX_SCALE; import static sun.misc.Unsafe.ARRAY_INT_BASE_OFFSET; import static sun.misc.Unsafe.ARRAY_INT_INDEX_SCALE; import static sun.misc.Unsafe.ARRAY_LONG_BASE_OFFSET; import static sun.misc.Unsafe.ARRAY_LONG_INDEX_SCALE; import static sun.misc.Unsafe.ARRAY_SHORT_BASE_OFFSET; import static sun.misc.Unsafe.ARRAY_SHORT_INDEX_SCALE; public final class Slice implements Comparable { /** * @deprecated use {@link Slices#wrappedBuffer(java.nio.ByteBuffer)} */ @Deprecated public static Slice toUnsafeSlice(ByteBuffer byteBuffer) { return Slices.wrappedBuffer(byteBuffer); } /** * Base object for relative addresses. If null, the address is an * absolute location in memory. */ private final Object base; /** * If base is null, address is the absolute memory location of data for * this slice; otherwise, address is the offset from the base object. * This base plus relative offset addressing is taken directly from * the Unsafe interface. *

* Note: if base object is a byte array, this address ARRAY_BYTE_BASE_OFFSET, * since the byte array data starts AFTER the byte array object header. */ private final long address; /** * Size of the slice */ private final int size; /** * Bytes retained by the slice */ private final int retainedSize; /** * Reference is typically a ByteBuffer object, but can be any object this * slice must hold onto to assure that the underlying memory is not * freed by the garbage collector. */ private final Object reference; private int hash; /** * Creates an empty slice. */ Slice() { this.base = null; this.address = 0; this.size = 0; this.retainedSize = 0; this.reference = null; } /** * Creates a slice over the specified array. */ Slice(byte[] base) { checkNotNull(base, "base is null"); this.base = base; this.address = ARRAY_BYTE_BASE_OFFSET; this.size = base.length; this.retainedSize = base.length; this.reference = null; } /** * Creates a slice over the specified array range. */ Slice(byte[] base, int offset, int length) { checkNotNull(base, "base is null"); checkPositionIndexes(offset, offset + length, base.length); this.base = base; this.address = ARRAY_BYTE_BASE_OFFSET + offset; this.size = length; this.retainedSize = base.length; this.reference = null; } /** * Creates a slice over the specified array range. */ Slice(boolean[] base, int offset, int length) { checkNotNull(base, "base is null"); checkPositionIndexes(offset, offset + length, base.length); this.base = base; this.address = ARRAY_BOOLEAN_BASE_OFFSET + offset; this.size = length * ARRAY_BOOLEAN_INDEX_SCALE; this.retainedSize = base.length * ARRAY_BOOLEAN_INDEX_SCALE; this.reference = null; } /** * Creates a slice over the specified array range. */ Slice(short[] base, int offset, int length) { checkNotNull(base, "base is null"); checkPositionIndexes(offset, offset + length, base.length); this.base = base; this.address = ARRAY_SHORT_BASE_OFFSET + offset; this.size = length * ARRAY_SHORT_INDEX_SCALE; this.retainedSize = base.length * ARRAY_SHORT_INDEX_SCALE; this.reference = null; } /** * Creates a slice over the specified array range. */ Slice(int[] base, int offset, int length) { checkNotNull(base, "base is null"); checkPositionIndexes(offset, offset + length, base.length); this.base = base; this.address = ARRAY_INT_BASE_OFFSET + offset; this.size = length * ARRAY_INT_INDEX_SCALE; this.retainedSize = base.length * ARRAY_INT_INDEX_SCALE; this.reference = null; } /** * Creates a slice over the specified array range. */ Slice(long[] base, int offset, int length) { checkNotNull(base, "base is null"); checkPositionIndexes(offset, offset + length, base.length); this.base = base; this.address = ARRAY_LONG_BASE_OFFSET + offset; this.size = length * ARRAY_LONG_INDEX_SCALE; this.retainedSize = base.length * ARRAY_LONG_INDEX_SCALE; this.reference = null; } /** * Creates a slice over the specified array range. */ Slice(float[] base, int offset, int length) { checkNotNull(base, "base is null"); checkPositionIndexes(offset, offset + length, base.length); this.base = base; this.address = ARRAY_FLOAT_BASE_OFFSET + offset; this.size = length * ARRAY_FLOAT_INDEX_SCALE; this.retainedSize = base.length * ARRAY_FLOAT_INDEX_SCALE; this.reference = null; } /** * Creates a slice over the specified array range. */ Slice(double[] base, int offset, int length) { checkNotNull(base, "base is null"); checkPositionIndexes(offset, offset + length, base.length); this.base = base; this.address = ARRAY_DOUBLE_BASE_OFFSET + offset; this.size = length * ARRAY_DOUBLE_INDEX_SCALE; this.retainedSize = base.length * ARRAY_DOUBLE_INDEX_SCALE; this.reference = null; } /** * Creates a slice for directly accessing the base object. */ Slice(@Nullable Object base, long address, int size, int retainedSize, @Nullable Object reference) { if (address <= 0) { throw new IllegalArgumentException(format("Invalid address: %s", address)); } if (size <= 0) { throw new IllegalArgumentException(format("Invalid size: %s", size)); } checkArgument((address + size) >= size, "Address + size is greater than 64 bits"); this.reference = reference; this.base = base; this.address = address; this.size = size; this.retainedSize = retainedSize; } /** * Returns the base object of this Slice, or null. This is appropriate for use * with {@link Unsafe} if you wish to avoid all the safety belts e.g. bounds checks. */ public Object getBase() { return base; } /** * Return the address offset of this Slice. This is appropriate for use * with {@link Unsafe} if you wish to avoid all the safety belts e.g. bounds checks. */ public long getAddress() { return address; } /** * Length of this slice. */ public int length() { return size; } /** * Approximate number of bytes retained by this slice. */ public int getRetainedSize() { return retainedSize; } /** * Fill the slice with the specified value; */ public void fill(byte value) { int offset = 0; int length = size; long longValue = fillLong(value); while (length >= SIZE_OF_LONG) { unsafe.putLong(base, address + offset, longValue); offset += SIZE_OF_LONG; length -= SIZE_OF_LONG; } while (length > 0) { unsafe.putByte(base, address + offset, value); offset++; length--; } } /** * Fill the slice with zeros; */ public void clear() { clear(0, size); } public void clear(int offset, int length) { while (length >= SIZE_OF_LONG) { unsafe.putLong(base, address + offset, 0); offset += SIZE_OF_LONG; length -= SIZE_OF_LONG; } while (length > 0) { unsafe.putByte(base, address + offset, (byte) 0); offset++; length--; } } /** * Gets a byte at the specified absolute {@code index} in this buffer. * * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0} or * {@code index + 1} is greater than {@code this.length()} */ public byte getByte(int index) { checkIndexLength(index, SIZE_OF_BYTE); return getByteUnchecked(index); } byte getByteUnchecked(int index) { return unsafe.getByte(base, address + index); } /** * Gets an unsigned byte at the specified absolute {@code index} in this * buffer. * * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0} or * {@code index + 1} is greater than {@code this.length()} */ public short getUnsignedByte(int index) { return (short) (getByte(index) & 0xFF); } /** * Gets a 16-bit short integer at the specified absolute {@code index} in * this slice. * * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0} or * {@code index + 2} is greater than {@code this.length()} */ public short getShort(int index) { checkIndexLength(index, SIZE_OF_SHORT); return getShortUnchecked(index); } short getShortUnchecked(int index) { return unsafe.getShort(base, address + index); } /** * Gets a 32-bit integer at the specified absolute {@code index} in * this buffer. * * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0} or * {@code index + 4} is greater than {@code this.length()} */ public int getInt(int index) { checkIndexLength(index, SIZE_OF_INT); return getIntUnchecked(index); } public int getIntUnchecked(int index) { return unsafe.getInt(base, address + index); } /** * Gets a 64-bit long integer at the specified absolute {@code index} in * this buffer. * * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0} or * {@code index + 8} is greater than {@code this.length()} */ public long getLong(int index) { checkIndexLength(index, SIZE_OF_LONG); return getLongUnchecked(index); } long getLongUnchecked(int index) { return unsafe.getLong(base, address + index); } /** * Gets a 32-bit float at the specified absolute {@code index} in * this buffer. * * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0} or * {@code index + 4} is greater than {@code this.length()} */ public float getFloat(int index) { checkIndexLength(index, SIZE_OF_FLOAT); return unsafe.getFloat(base, address + index); } /** * Gets a 64-bit double at the specified absolute {@code index} in * this buffer. * * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0} or * {@code index + 8} is greater than {@code this.length()} */ public double getDouble(int index) { checkIndexLength(index, SIZE_OF_DOUBLE); return unsafe.getDouble(base, address + index); } /** * Transfers portion of data from this slice into the specified destination starting at * the specified absolute {@code index}. * * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0}, or * if {@code index + destination.length()} is greater than {@code this.length()} */ public void getBytes(int index, Slice destination) { getBytes(index, destination, 0, destination.length()); } /** * Transfers portion of data from this slice into the specified destination starting at * the specified absolute {@code index}. * * @param destinationIndex the first index of the destination * @param length the number of bytes to transfer * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0}, * if the specified {@code destinationIndex} is less than {@code 0}, * if {@code index + length} is greater than * {@code this.length()}, or * if {@code destinationIndex + length} is greater than * {@code destination.length()} */ public void getBytes(int index, Slice destination, int destinationIndex, int length) { destination.setBytes(destinationIndex, this, index, length); } /** * Transfers portion of data from this slice into the specified destination starting at * the specified absolute {@code index}. * * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0}, or * if {@code index + destination.length} is greater than {@code this.length()} */ public void getBytes(int index, byte[] destination) { getBytes(index, destination, 0, destination.length); } /** * Transfers portion of data from this slice into the specified destination starting at * the specified absolute {@code index}. * * @param destinationIndex the first index of the destination * @param length the number of bytes to transfer * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0}, * if the specified {@code destinationIndex} is less than {@code 0}, * if {@code index + length} is greater than * {@code this.length()}, or * if {@code destinationIndex + length} is greater than * {@code destination.length} */ public void getBytes(int index, byte[] destination, int destinationIndex, int length) { checkIndexLength(index, length); checkPositionIndexes(destinationIndex, destinationIndex + length, destination.length); copyMemory(base, address + index, destination, (long) ARRAY_BYTE_BASE_OFFSET + destinationIndex, length); } /** * Returns a copy of this buffer as a byte array. */ public byte[] getBytes() { return getBytes(0, length()); } /** * Returns a copy of this buffer as a byte array. * * @param index the absolute index to start at * @param length the number of bytes to return * @throws IndexOutOfBoundsException if the specified {@code index} is less then {@code 0}, * or if the specified {@code index + length} is greater than {@code this.length()} */ public byte[] getBytes(int index, int length) { byte[] bytes = new byte[length]; getBytes(index, bytes, 0, length); return bytes; } /** * Transfers a portion of data from this slice into the specified stream starting at the * specified absolute {@code index}. * * @param length the number of bytes to transfer * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0} or * if {@code index + length} is greater than * {@code this.length()} * @throws java.io.IOException if the specified stream threw an exception during I/O */ public void getBytes(int index, OutputStream out, int length) throws IOException { checkIndexLength(index, length); if (base instanceof byte[]) { out.write((byte[]) base, (int) ((address - ARRAY_BYTE_BASE_OFFSET) + index), length); return; } byte[] buffer = new byte[4096]; while (length > 0) { int size = min(buffer.length, length); getBytes(index, buffer, 0, size); out.write(buffer, 0, size); length -= size; index += size; } } /** * Sets the specified byte at the specified absolute {@code index} in this * buffer. The 24 high-order bits of the specified value are ignored. * * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0} or * {@code index + 1} is greater than {@code this.length()} */ public void setByte(int index, int value) { checkIndexLength(index, SIZE_OF_BYTE); setByteUnchecked(index, value); } void setByteUnchecked(int index, int value) { unsafe.putByte(base, address + index, (byte) (value & 0xFF)); } /** * Sets the specified 16-bit short integer at the specified absolute * {@code index} in this buffer. The 16 high-order bits of the specified * value are ignored. * * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0} or * {@code index + 2} is greater than {@code this.length()} */ public void setShort(int index, int value) { checkIndexLength(index, SIZE_OF_SHORT); setShortUnchecked(index, value); } void setShortUnchecked(int index, int value) { unsafe.putShort(base, address + index, (short) (value & 0xFFFF)); } /** * Sets the specified 32-bit integer at the specified absolute * {@code index} in this buffer. * * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0} or * {@code index + 4} is greater than {@code this.length()} */ public void setInt(int index, int value) { checkIndexLength(index, SIZE_OF_INT); setIntUnchecked(index, value); } void setIntUnchecked(int index, int value) { unsafe.putInt(base, address + index, value); } /** * Sets the specified 64-bit long integer at the specified absolute * {@code index} in this buffer. * * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0} or * {@code index + 8} is greater than {@code this.length()} */ public void setLong(int index, long value) { checkIndexLength(index, SIZE_OF_LONG); unsafe.putLong(base, address + index, value); } /** * Sets the specified 32-bit float at the specified absolute * {@code index} in this buffer. * * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0} or * {@code index + 4} is greater than {@code this.length()} */ public void setFloat(int index, float value) { checkIndexLength(index, SIZE_OF_FLOAT); unsafe.putFloat(base, address + index, value); } /** * Sets the specified 64-bit double at the specified absolute * {@code index} in this buffer. * * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0} or * {@code index + 8} is greater than {@code this.length()} */ public void setDouble(int index, double value) { checkIndexLength(index, SIZE_OF_DOUBLE); unsafe.putDouble(base, address + index, value); } /** * Transfers data from the specified slice into this buffer starting at * the specified absolute {@code index}. * * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0}, or * if {@code index + source.length()} is greater than {@code this.length()} */ public void setBytes(int index, Slice source) { setBytes(index, source, 0, source.length()); } /** * Transfers data from the specified slice into this buffer starting at * the specified absolute {@code index}. * * @param sourceIndex the first index of the source * @param length the number of bytes to transfer * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0}, * if the specified {@code sourceIndex} is less than {@code 0}, * if {@code index + length} is greater than * {@code this.length()}, or * if {@code sourceIndex + length} is greater than * {@code source.length()} */ public void setBytes(int index, Slice source, int sourceIndex, int length) { checkIndexLength(index, length); checkPositionIndexes(sourceIndex, sourceIndex + length, source.length()); copyMemory(source.base, source.address + sourceIndex, base, address + index, length); } /** * Transfers data from the specified slice into this buffer starting at * the specified absolute {@code index}. * * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0}, or * if {@code index + source.length} is greater than {@code this.length()} */ public void setBytes(int index, byte[] source) { setBytes(index, source, 0, source.length); } /** * Transfers data from the specified array into this buffer starting at * the specified absolute {@code index}. * * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0}, * if the specified {@code sourceIndex} is less than {@code 0}, * if {@code index + length} is greater than * {@code this.length()}, or * if {@code sourceIndex + length} is greater than {@code source.length} */ public void setBytes(int index, byte[] source, int sourceIndex, int length) { checkPositionIndexes(sourceIndex, sourceIndex + length, source.length); copyMemory(source, (long) ARRAY_BYTE_BASE_OFFSET + sourceIndex, base, address + index, length); } /** * Transfers data from the specified input stream into this slice starting at * the specified absolute {@code index}. * * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0}, or * if {@code index + source.length} is greater than {@code this.length()} */ public void setBytes(int index, InputStream in, int length) throws IOException { checkIndexLength(index, length); byte[] bytes = new byte[4096]; while (length > 0) { int bytesRead = in.read(bytes, 0, min(bytes.length, length)); if (bytesRead < 0) { throw new IndexOutOfBoundsException("End of stream"); } copyMemory(bytes, ARRAY_BYTE_BASE_OFFSET, base, address + index, bytesRead); length -= bytesRead; index += bytesRead; } } /** * Returns a slice of this buffer's sub-region. Modifying the content of * the returned buffer or this buffer affects each other's content. */ public Slice slice(int index, int length) { if ((index == 0) && (length == length())) { return this; } checkIndexLength(index, length); if (length == 0) { return Slices.EMPTY_SLICE; } return new Slice(base, address + index, length, retainedSize, reference); } public int indexOfByte(int b) { b = b & 0xFF; for (int i = 0; i < size; i++) { if (getByteUnchecked(i) == b) { return i; } } return -1; } /** * Returns the index of the first occurrence of the pattern with this slice. * If the pattern is not found -1 is returned. If patten is empty, zero is * returned. */ public int indexOf(Slice slice) { return indexOf(slice, 0); } /** * Returns the index of the first occurrence of the pattern with this slice. * If the pattern is not found -1 is returned If patten is empty, the offset * is returned. */ public int indexOf(Slice pattern, int offset) { if (size == 0 || offset >= size) { return -1; } if (pattern.length() == 0) { return offset; } // Do we have enough characters if (pattern.length() < SIZE_OF_INT || size < SIZE_OF_LONG) { return indexOfBruteForce(pattern, offset); } // Using first four bytes for faster search. We are not using eight bytes for long // because we want more strings to get use of fast search. int head = pattern.getIntUnchecked(0); // Take the first byte of head for faster skipping int firstByteMask = head & 0xff; firstByteMask |= firstByteMask << 8; firstByteMask |= firstByteMask << 16; int lastValidIndex = size - pattern.length(); int index = offset; while (index <= lastValidIndex) { // Read four bytes in sequence int value = getIntUnchecked(index); // Compare all bytes of value with first byte of search data // see https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord int valueXor = value ^ firstByteMask; int hasZeroBytes = (valueXor - 0x01010101) & ~valueXor & 0x80808080; // If valueXor doesn't not have any zero byte then there is no match and we can advance if (hasZeroBytes == 0) { index += SIZE_OF_INT; continue; } // Try fast match of head and the rest if (value == head && equalsUnchecked(index, pattern, 0, pattern.length())) { return index; } index++; } return -1; } int indexOfBruteForce(Slice pattern, int offset) { if (size == 0 || offset >= size) { return -1; } if (pattern.length() == 0) { return offset; } byte firstByte = pattern.getByteUnchecked(0); int lastValidIndex = size - pattern.length(); int index = offset; while (true) { // seek to first byte match while (index < lastValidIndex && getByteUnchecked(index) != firstByte) { index++; } if (index > lastValidIndex) { break; } if (equalsUnchecked(index, pattern, 0, pattern.length())) { return index; } index++; } return -1; } /** * Compares the content of the specified buffer to the content of this * buffer. This comparison is performed byte by byte using an unsigned * comparison. */ @SuppressWarnings("ObjectEquality") @Override public int compareTo(Slice that) { if (this == that) { return 0; } return compareTo(0, size, that, 0, that.size); } /** * Compares a portion of this slice with a portion of the specified slice. Equality is * solely based on the contents of the slice. */ @SuppressWarnings("ObjectEquality") public int compareTo(int offset, int length, Slice that, int otherOffset, int otherLength) { if ((this == that) && (offset == otherOffset) && (length == otherLength)) { return 0; } checkIndexLength(offset, length); that.checkIndexLength(otherOffset, otherLength); int compareLength = min(length, otherLength); while (compareLength >= SIZE_OF_LONG) { long thisLong = getLongUnchecked(offset); thisLong = Long.reverseBytes(thisLong); long thatLong = that.getLongUnchecked(otherOffset); thatLong = Long.reverseBytes(thatLong); int v = compareUnsignedLongs(thisLong, thatLong); if (v != 0) { return v; } offset += SIZE_OF_LONG; otherOffset += SIZE_OF_LONG; compareLength -= SIZE_OF_LONG; } while (compareLength > 0) { byte thisByte = getByteUnchecked(offset); byte thatByte = that.getByteUnchecked(otherOffset); int v = compareUnsignedBytes(thisByte, thatByte); if (v != 0) { return v; } offset++; otherOffset++; compareLength--; } return Integer.compare(length, otherLength); } /** * Compares the specified object with this slice for equality. Equality is * solely based on the contents of the slice. */ @Override public boolean equals(Object o) { if (this == o) { return true; } if (!(o instanceof Slice)) { return false; } Slice that = (Slice) o; if (length() != that.length()) { return false; } int offset = 0; int length = size; while (length >= SIZE_OF_LONG) { long thisLong = getLongUnchecked(offset); long thatLong = that.getLongUnchecked(offset); if (thisLong != thatLong) { return false; } offset += SIZE_OF_LONG; length -= SIZE_OF_LONG; } while (length > 0) { byte thisByte = getByteUnchecked(offset); byte thatByte = that.getByteUnchecked(offset); if (thisByte != thatByte) { return false; } offset++; length--; } return true; } /** * Returns the hash code of this slice. The hash code is cached once calculated * and any future changes to the slice will not effect the hash code. */ @SuppressWarnings("NonFinalFieldReferencedInHashCode") @Override public int hashCode() { if (hash != 0) { return hash; } hash = hashCode(0, size); return hash; } /** * Returns the hash code of a portion of this slice. */ public int hashCode(int offset, int length) { return (int) XxHash64.hash(this, offset, length); } /** * Compares a portion of this slice with a portion of the specified slice. Equality is * solely based on the contents of the slice. */ @SuppressWarnings("ObjectEquality") public boolean equals(int offset, int length, Slice that, int otherOffset, int otherLength) { if (length != otherLength) { return false; } checkIndexLength(offset, length); that.checkIndexLength(otherOffset, otherLength); return equalsUnchecked(offset, that, otherOffset, length); } boolean equalsUnchecked(int offset, Slice that, int otherOffset, int length) { if ((this == that) && (offset == otherOffset)) { return true; } while (length >= SIZE_OF_LONG) { long thisLong = getLongUnchecked(offset); long thatLong = that.getLongUnchecked(otherOffset); if (thisLong != thatLong) { return false; } offset += SIZE_OF_LONG; otherOffset += SIZE_OF_LONG; length -= SIZE_OF_LONG; } while (length > 0) { byte thisByte = getByteUnchecked(offset); byte thatByte = that.getByteUnchecked(otherOffset); if (thisByte != thatByte) { return false; } offset++; otherOffset++; length--; } return true; } /** * Creates a slice input backed by this slice. Any changes to this slice * will be immediately visible to the slice input. */ public BasicSliceInput getInput() { return new BasicSliceInput(this); } /** * Creates a slice output backed by this slice. Any data written to the * slice output will be immediately visible in this slice. */ public SliceOutput getOutput() { return new BasicSliceOutput(this); } /** * Decodes the contents of this slice into a string with the specified * character set name. */ public String toString(Charset charset) { return toString(0, length(), charset); } /** * Decodes the contents of this slice into a string using the UTF-8 * character set. */ public String toStringUtf8() { return toString(UTF_8); } /** * Decodes the contents of this slice into a string using the US_ASCII * character set. The low order 7 bits if each byte are converted directly * into a code point for the string. */ public String toStringAscii() { return toStringAscii(0, size); } public String toStringAscii(int index, int length) { checkIndexLength(index, length); if (length == 0) { return ""; } if (base instanceof byte[]) { //noinspection deprecation return new String((byte[]) base, 0, (int) ((address - ARRAY_BYTE_BASE_OFFSET) + index), length); } char[] chars = new char[length]; for (int pos = index; pos < length; pos++) { chars[pos] = (char) (getByteUnchecked(pos) & 0x7F); } return new String(chars); } /** * Decodes the a portion of this slice into a string with the specified * character set name. */ public String toString(int index, int length, Charset charset) { if (length == 0) { return ""; } if (base instanceof byte[]) { return new String((byte[]) base, (int) ((address - ARRAY_BYTE_BASE_OFFSET) + index), length, charset); } // direct memory can only be converted to a string using a ByteBuffer return decodeString(toByteBuffer(index, length), charset); } public ByteBuffer toByteBuffer() { return toByteBuffer(0, size); } public ByteBuffer toByteBuffer(int index, int length) { checkIndexLength(index, length); if (base instanceof byte[]) { return ByteBuffer.wrap((byte[]) base, (int) ((address - ARRAY_BYTE_BASE_OFFSET) + index), length); } try { return (ByteBuffer) newByteBuffer.invokeExact(address + index, length, (Object) reference); } catch (Throwable throwable) { if (throwable instanceof Error) { throw (Error) throwable; } if (throwable instanceof RuntimeException) { throw (RuntimeException) throwable; } if (throwable instanceof InterruptedException) { Thread.currentThread().interrupt(); } throw new RuntimeException(throwable); } } /** * Decodes the a portion of this slice into a string with the specified * character set name. */ @Override public String toString() { StringBuilder builder = new StringBuilder("Slice{"); if (base != null) { builder.append("base=").append(identityToString(base)).append(", "); } builder.append("address=").append(address); builder.append(", length=").append(length()); builder.append('}'); return builder.toString(); } private static String identityToString(Object o) { if (o == null) { return null; } return o.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(o)); } private static void copyMemory(Object src, long srcAddress, Object dest, long destAddress, int length) { // The Unsafe Javadoc specifies that the transfer size is 8 iff length % 8 == 0 // so ensure that we copy big chunks whenever possible, even at the expense of two separate copy operations int bytesToCopy = length - (length % 8); unsafe.copyMemory(src, srcAddress, dest, destAddress, bytesToCopy); unsafe.copyMemory(src, srcAddress + bytesToCopy, dest, destAddress + bytesToCopy, length - bytesToCopy); } private void checkIndexLength(int index, int length) { checkPositionIndexes(index, index + length, length()); } // // The following methods were forked from Guava primitives // private static long fillLong(byte value) { return (value & 0xFFL) << 56 | (value & 0xFFL) << 48 | (value & 0xFFL) << 40 | (value & 0xFFL) << 32 | (value & 0xFFL) << 24 | (value & 0xFFL) << 16 | (value & 0xFFL) << 8 | (value & 0xFFL); } private static int compareUnsignedBytes(byte thisByte, byte thatByte) { return unsignedByteToInt(thisByte) - unsignedByteToInt(thatByte); } private static int unsignedByteToInt(byte thisByte) { return thisByte & 0xFF; } private static int compareUnsignedLongs(long thisLong, long thatLong) { return Long.compare(flipUnsignedLong(thisLong), flipUnsignedLong(thatLong)); } private static long flipUnsignedLong(long thisLong) { return thisLong ^ Long.MIN_VALUE; } } slice-0.16/src/main/java/io/airlift/slice/SliceInput.java000066400000000000000000000244621261474317300232750ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import java.io.DataInput; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @SuppressWarnings("JavaDoc") // IDEA-81310 public abstract class SliceInput extends InputStream implements DataInput { /** * Returns the {@code position} of this buffer. */ public abstract long position(); /** * Sets the {@code position} of this buffer. * * @throws IndexOutOfBoundsException if the specified {@code position} is * less than {@code 0} or * greater than {@code this.writerIndex} */ public abstract void setPosition(long position); /** * Returns {@code true} * if and only if {@code available()} is greater * than {@code 0}. */ public abstract boolean isReadable(); /** * Returns the number of bytes that can be read without blocking. */ @SuppressWarnings("AbstractMethodOverridesConcreteMethod") @Override public abstract int available(); @Override public abstract int read(); /** * Returns true if the byte at the current {@code position} is not {@code 0} and increases * the {@code position} by {@code 1} in this buffer. * * @throws IndexOutOfBoundsException if {@code this.available()} is less than {@code 1} */ @Override public abstract boolean readBoolean(); /** * Gets a byte at the current {@code position} and increases * the {@code position} by {@code 1} in this buffer. * * @throws IndexOutOfBoundsException if {@code this.available()} is less than {@code 1} */ @Override public abstract byte readByte(); /** * Gets an unsigned byte at the current {@code position} and increases * the {@code position} by {@code 1} in this buffer. * * @throws IndexOutOfBoundsException if {@code this.available()} is less than {@code 1} */ @Override public abstract int readUnsignedByte(); /** * Gets a 16-bit short integer at the current {@code position} * and increases the {@code position} by {@code 2} in this buffer. * * @throws IndexOutOfBoundsException if {@code this.available()} is less than {@code 2} */ @Override public abstract short readShort(); /** * Gets an unsigned 16-bit short integer at the current {@code position} * and increases the {@code position} by {@code 2} in this buffer. * * @throws IndexOutOfBoundsException if {@code this.available()} is less than {@code 2} */ @Override public abstract int readUnsignedShort(); /** * Gets a 32-bit integer at the current {@code position} * and increases the {@code position} by {@code 4} in this buffer. * * @throws IndexOutOfBoundsException if {@code this.available()} is less than {@code 4} */ @Override public abstract int readInt(); /** * Gets an unsigned 32-bit integer at the current {@code position} * and increases the {@code position} by {@code 4} in this buffer. * * @throws IndexOutOfBoundsException if {@code this.available()} is less than {@code 4} */ public final long readUnsignedInt() { return readInt() & 0xFFFFFFFFL; } /** * Gets a 64-bit long at the current {@code position} * and increases the {@code position} by {@code 8} in this buffer. * * @throws IndexOutOfBoundsException if {@code this.available()} is less than {@code 8} */ @Override public abstract long readLong(); /** * Gets a 32-bit float at the current {@code position} * and increases the {@code position} by {@code 4} in this buffer. * * @throws IndexOutOfBoundsException if {@code this.available()} is less than {@code 4} */ @Override public abstract float readFloat(); /** * Gets a 64-bit double at the current {@code position} * and increases the {@code position} by {@code 8} in this buffer. * * @throws IndexOutOfBoundsException if {@code this.available()} is less than {@code 8} */ @Override public abstract double readDouble(); /** * Returns a new slice of this buffer's sub-region starting at the current * {@code position} and increases the {@code position} by the size * of the new slice (= {@code length}). * * @param length the size of the new slice * @return the newly created slice * @throws IndexOutOfBoundsException if {@code length} is greater than {@code this.available()} */ public abstract Slice readSlice(int length); @Override public final void readFully(byte[] destination) { readBytes(destination); } @Override public final int read(byte[] destination) { return read(destination, 0, destination.length); } @Override public abstract int read(byte[] destination, int destinationIndex, int length); /** * Transfers this buffer's data to the specified destination starting at * the current {@code position} and increases the {@code position} * by the number of the transferred bytes (= {@code dst.length}). * * @throws IndexOutOfBoundsException if {@code dst.length} is greater than {@code this.available()} */ public final void readBytes(byte[] destination) { readBytes(destination, 0, destination.length); } @Override public final void readFully(byte[] destination, int offset, int length) { readBytes(destination, offset, length); } /** * Transfers this buffer's data to the specified destination starting at * the current {@code position} and increases the {@code position} * by the number of the transferred bytes (= {@code length}). * * @param destinationIndex the first index of the destination * @param length the number of bytes to transfer * @throws IndexOutOfBoundsException if the specified {@code destinationIndex} is less than {@code 0}, * if {@code length} is greater than {@code this.available()}, or * if {@code destinationIndex + length} is greater than {@code destination.length} */ public abstract void readBytes(byte[] destination, int destinationIndex, int length); /** * Transfers this buffer's data to the specified destination starting at * the current {@code position} until the destination becomes * non-writable, and increases the {@code position} by the number of the * transferred bytes. This method is basically same with * {@link #readBytes(Slice, int, int)}, except that this method * increases the {@code writerIndex} of the destination by the number of * the transferred bytes while {@link #readBytes(Slice, int, int)} * does not. * * @throws IndexOutOfBoundsException if {@code destination.writableBytes} is greater than * {@code this.available()} */ public final void readBytes(Slice destination) { readBytes(destination, 0, destination.length()); } /** * Transfers this buffer's data to the specified destination starting at * the current {@code position} and increases the {@code position} * by the number of the transferred bytes (= {@code length}). This method * is basically same with {@link #readBytes(Slice, int, int)}, * except that this method increases the {@code writerIndex} of the * destination by the number of the transferred bytes (= {@code length}) * while {@link #readBytes(Slice, int, int)} does not. * * @throws IndexOutOfBoundsException if {@code length} is greater than {@code this.available()} or * if {@code length} is greater than {@code destination.writableBytes} */ public final void readBytes(Slice destination, int length) { readBytes(destination, 0, length); } /** * Transfers this buffer's data to the specified destination starting at * the current {@code position} and increases the {@code position} * by the number of the transferred bytes (= {@code length}). * * @param destinationIndex the first index of the destination * @param length the number of bytes to transfer * @throws IndexOutOfBoundsException if the specified {@code destinationIndex} is less than {@code 0}, * if {@code length} is greater than {@code this.available()}, or * if {@code destinationIndex + length} is greater than * {@code destination.capacity} */ public abstract void readBytes(Slice destination, int destinationIndex, int length); /** * Transfers this buffer's data to the specified stream starting at the * current {@code position}. * * @param length the number of bytes to transfer * @throws IndexOutOfBoundsException if {@code length} is greater than {@code this.available()} * @throws java.io.IOException if the specified stream threw an exception during I/O */ public abstract void readBytes(OutputStream out, int length) throws IOException; @Override public abstract long skip(long length); @Override public abstract int skipBytes(int length); @Override public void close() { } // // Unsupported operations // @Override public final void mark(int readLimit) { throw new UnsupportedOperationException(); } @Override public final void reset() { throw new UnsupportedOperationException(); } @Override public final boolean markSupported() { throw new UnsupportedOperationException(); } @Override public final char readChar() { throw new UnsupportedOperationException(); } @Override public final String readLine() { throw new UnsupportedOperationException(); } @Override public final String readUTF() { throw new UnsupportedOperationException(); } } slice-0.16/src/main/java/io/airlift/slice/SliceOutput.java000066400000000000000000000247061261474317300234770ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import java.io.DataOutput; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.charset.Charset; @SuppressWarnings("JavaDoc") // IDEA-81310 public abstract class SliceOutput extends OutputStream implements DataOutput { /** * Resets this stream to the initial position. */ public abstract void reset(); /** * Returns the {@code writerIndex} of this buffer. */ public abstract int size(); /** * Returns the number of writable bytes which is equal to * {@code (this.capacity - this.writerIndex)}. */ public abstract int writableBytes(); /** * Returns {@code true} * if and only if {@code (this.capacity - this.writerIndex)} is greater * than {@code 0}. */ public abstract boolean isWritable(); @Override public final void writeBoolean(boolean value) { writeByte(value ? 1 : 0); } @Override public final void write(int value) { writeByte(value); } /** * Sets the specified byte at the current {@code writerIndex} * and increases the {@code writerIndex} by {@code 1} in this buffer. * The 24 high-order bits of the specified value are ignored. * * @throws IndexOutOfBoundsException if {@code this.writableBytes} is less than {@code 1} */ @Override public abstract void writeByte(int value); /** * Sets the specified 16-bit short integer at the current * {@code writerIndex} and increases the {@code writerIndex} by {@code 2} * in this buffer. The 16 high-order bits of the specified value are ignored. * * @throws IndexOutOfBoundsException if {@code this.writableBytes} is less than {@code 2} */ @Override public abstract void writeShort(int value); /** * Sets the specified 32-bit integer at the current {@code writerIndex} * and increases the {@code writerIndex} by {@code 4} in this buffer. * * @throws IndexOutOfBoundsException if {@code this.writableBytes} is less than {@code 4} */ @Override public abstract void writeInt(int value); /** * Sets the specified 64-bit long integer at the current * {@code writerIndex} and increases the {@code writerIndex} by {@code 8} * in this buffer. * * @throws IndexOutOfBoundsException if {@code this.writableBytes} is less than {@code 8} */ @Override public abstract void writeLong(long value); /** * Sets the specified 32-bit float at the current * {@code writerIndex} and increases the {@code writerIndex} by {@code 4} * in this buffer. * * @throws IndexOutOfBoundsException if {@code this.writableBytes} is less than {@code 4} */ @Override public abstract void writeFloat(float v); /** * Sets the specified 64-bit double at the current * {@code writerIndex} and increases the {@code writerIndex} by {@code 8} * in this buffer. * * @throws IndexOutOfBoundsException if {@code this.writableBytes} is less than {@code 8} */ @Override public abstract void writeDouble(double value); /** * Transfers the specified source buffer's data to this buffer starting at * the current {@code writerIndex} until the source buffer becomes * unreadable, and increases the {@code writerIndex} by the number of * the transferred bytes. This method is basically same with * {@link #writeBytes(Slice, int, int)}, except that this method * increases the {@code readerIndex} of the source buffer by the number of * the transferred bytes while {@link #writeBytes(Slice, int, int)} * does not. * * @throws IndexOutOfBoundsException if {@code source.readableBytes} is greater than {@code this.writableBytes} */ public abstract void writeBytes(Slice source); /** * Transfers the specified source buffer's data to this buffer starting at * the current {@code writerIndex} and increases the {@code writerIndex} * by the number of the transferred bytes (= {@code length}). * * @param sourceIndex the first index of the source * @param length the number of bytes to transfer * @throws IndexOutOfBoundsException if the specified {@code sourceIndex} is less than {@code 0}, * if {@code sourceIndex + length} is greater than {@code source.capacity}, or * if {@code length} is greater than {@code this.writableBytes} */ public abstract void writeBytes(Slice source, int sourceIndex, int length); @Override public final void write(byte[] source) throws IOException { writeBytes(source); } /** * Transfers the specified source array's data to this buffer starting at * the current {@code writerIndex} and increases the {@code writerIndex} * by the number of the transferred bytes (= {@code source.length}). * * @throws IndexOutOfBoundsException if {@code source.length} is greater than {@code this.writableBytes} */ public abstract void writeBytes(byte[] source); @Override public final void write(byte[] source, int sourceIndex, int length) { writeBytes(source, sourceIndex, length); } /** * Transfers the specified source array's data to this buffer starting at * the current {@code writerIndex} and increases the {@code writerIndex} * by the number of the transferred bytes (= {@code length}). * * @param sourceIndex the first index of the source * @param length the number of bytes to transfer * @throws IndexOutOfBoundsException if the specified {@code sourceIndex} is less than {@code 0}, * if {@code sourceIndex + length} is greater than {@code source.length}, or * if {@code length} is greater than {@code this.writableBytes} */ public abstract void writeBytes(byte[] source, int sourceIndex, int length); /** * Transfers the content of the specified stream to this buffer * starting at the current {@code writerIndex} and increases the * {@code writerIndex} by the number of the transferred bytes. * * @param length the number of bytes to transfer * @throws IndexOutOfBoundsException if {@code length} is greater than {@code this.writableBytes} * @throws java.io.IOException if the specified stream threw an exception during I/O */ public abstract void writeBytes(InputStream in, int length) throws IOException; /** * Fills this buffer with NUL (0x00) starting at the current * {@code writerIndex} and increases the {@code writerIndex} by the * specified {@code length}. * * @param length the number of NULs to write to the buffer * @throws IndexOutOfBoundsException if {@code length} is greater than {@code this.writableBytes} */ public void writeZero(int length) { if (length == 0) { return; } if (length < 0) { throw new IllegalArgumentException( "length must be 0 or greater than 0."); } int nLong = length >>> 3; int nBytes = length & 7; for (int i = nLong; i > 0; i--) { writeLong(0); } if (nBytes == 4) { writeInt(0); } else if (nBytes < 4) { for (int i = nBytes; i > 0; i--) { writeByte((byte) 0); } } else { writeInt(0); for (int i = nBytes - 4; i > 0; i--) { writeByte((byte) 0); } } } /** * Returns a slice of this buffer's readable bytes. Modifying the content * of the returned buffer or this buffer affects each other's content * while they maintain separate indexes and marks. This method is * identical to {@code buf.slice(buf.readerIndex(), buf.readableBytes())}. * This method does not modify {@code readerIndex} or {@code writerIndex} of * this buffer. */ public abstract Slice slice(); /** * Returns the raw underlying slice of this output stream. The slice may * be larger than the size of this stream. */ public abstract Slice getUnderlyingSlice(); /** * Decodes this buffer's readable bytes into a string with the specified * character set name. This method is identical to * {@code buf.toString(buf.readerIndex(), buf.readableBytes(), charsetName)}. * This method does not modify {@code readerIndex} or {@code writerIndex} of * this buffer. */ public abstract String toString(Charset charset); public abstract SliceOutput appendLong(long value); public abstract SliceOutput appendDouble(double value); public abstract SliceOutput appendInt(int value); public abstract SliceOutput appendShort(int value); public abstract SliceOutput appendByte(int value); public abstract SliceOutput appendBytes(byte[] source, int sourceIndex, int length); public abstract SliceOutput appendBytes(byte[] source); public abstract SliceOutput appendBytes(Slice slice); // // Unsupported operations // /** * Unsupported operation * * @throws UnsupportedOperationException always */ @Override public void writeChar(int value) { throw new UnsupportedOperationException(); } /** * Unsupported operation * * @throws UnsupportedOperationException always */ @Override public void writeChars(String s) { throw new UnsupportedOperationException(); } /** * Unsupported operation * * @throws UnsupportedOperationException always */ @Override public void writeUTF(String s) { throw new UnsupportedOperationException(); } /** * Unsupported operation * * @throws UnsupportedOperationException always */ @Override public void writeBytes(String s) { throw new UnsupportedOperationException(); } } slice-0.16/src/main/java/io/airlift/slice/SliceStreamUtils.java000066400000000000000000000023141261474317300244420ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; final class SliceStreamUtils { private SliceStreamUtils() { } public static void copyStreamFully(InputStream in, OutputStream out, int length) throws IOException { byte[] bytes = new byte[4096]; while (length > 0) { int newBytes = in.read(bytes, 0, Math.min(bytes.length, length)); if (newBytes < 0) { throw new EOFException(); } out.write(bytes, 0, newBytes); length -= newBytes; } } } slice-0.16/src/main/java/io/airlift/slice/SliceUtf8.java000066400000000000000000001023771261474317300230260ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import java.util.OptionalInt; import static io.airlift.slice.Preconditions.checkArgument; import static io.airlift.slice.Preconditions.checkPositionIndex; import static io.airlift.slice.Preconditions.checkPositionIndexes; import static java.lang.Character.MAX_CODE_POINT; import static java.lang.Character.MAX_SURROGATE; import static java.lang.Character.MIN_SURROGATE; import static java.lang.Integer.toHexString; /** * Utility methods for UTF-8 encoded slices. */ public final class SliceUtf8 { private SliceUtf8() {} private static final int REPLACEMENT_CODE_POINT = 0xFFFD; private static final int TOP_MASK32 = 0x8080_8080; private static final long TOP_MASK64 = 0x8080_8080_8080_8080L; private static final int[] LOWER_CODE_POINTS; private static final int[] UPPER_CODE_POINTS; private static final boolean[] WHITESPACE_CODE_POINTS; static { LOWER_CODE_POINTS = new int[MAX_CODE_POINT + 1]; UPPER_CODE_POINTS = new int[MAX_CODE_POINT + 1]; WHITESPACE_CODE_POINTS = new boolean[MAX_CODE_POINT + 1]; for (int codePoint = 0; codePoint <= MAX_CODE_POINT; codePoint++) { int type = Character.getType(codePoint); if (type != Character.SURROGATE) { LOWER_CODE_POINTS[codePoint] = Character.toLowerCase(codePoint); UPPER_CODE_POINTS[codePoint] = Character.toUpperCase(codePoint); WHITESPACE_CODE_POINTS[codePoint] = Character.isWhitespace(codePoint); } else { LOWER_CODE_POINTS[codePoint] = REPLACEMENT_CODE_POINT; UPPER_CODE_POINTS[codePoint] = REPLACEMENT_CODE_POINT; WHITESPACE_CODE_POINTS[codePoint] = false; } } } /** * Does the slice contain only 7-bit ASCII characters. */ public static boolean isAscii(Slice utf8) { int length = utf8.length(); int offset = 0; // Length rounded to 8 bytes int length8 = length & 0x7FFF_FFF8; for (; offset < length8; offset += 8) { if ((utf8.getLongUnchecked(offset) & TOP_MASK64) != 0) { return false; } } // Enough bytes left for 32 bits? if (offset + 4 < length) { if ((utf8.getIntUnchecked(offset) & TOP_MASK32) != 0) { return false; } offset += 4; } // Do the rest one by one for (; offset < length; offset++) { if ((utf8.getByteUnchecked(offset) & 0x80) != 0) { return false; } } return true; } /** * Counts the code points within UTF-8 encoded slice. *

* Note: This method does not explicitly check for valid UTF-8, and may * return incorrect results or throw an exception for invalid UTF-8. */ public static int countCodePoints(Slice utf8) { return countCodePoints(utf8, 0, utf8.length()); } /** * Counts the code points within UTF-8 encoded slice up to {@code length}. *

* Note: This method does not explicitly check for valid UTF-8, and may * return incorrect results or throw an exception for invalid UTF-8. */ public static int countCodePoints(Slice utf8, int offset, int length) { checkPositionIndexes(offset, offset + length, utf8.length()); // Quick exit if empty string if (length == 0) { return 0; } int continuationBytesCount = 0; // Length rounded to 8 bytes int length8 = length & 0x7FFF_FFF8; for (; offset < length8; offset += 8) { // Count bytes which are NOT the start of a code point continuationBytesCount += countContinuationBytes(utf8.getLongUnchecked(offset)); } // Enough bytes left for 32 bits? if (offset + 4 < length) { // Count bytes which are NOT the start of a code point continuationBytesCount += countContinuationBytes(utf8.getIntUnchecked(offset)); offset += 4; } // Do the rest one by one for (; offset < length; offset++) { // Count bytes which are NOT the start of a code point continuationBytesCount += countContinuationBytes(utf8.getByteUnchecked(offset)); } assert continuationBytesCount <= length; return length - continuationBytesCount; } /** * Gets the substring starting at {@code codePointStart} and extending for * {@code codePointLength} code points. *

* Note: This method does not explicitly check for valid UTF-8, and may * return incorrect results or throw an exception for invalid UTF-8. */ public static Slice substring(Slice utf8, int codePointStart, int codePointLength) { checkArgument(codePointStart >= 0, "codePointStart is negative"); checkArgument(codePointLength >= 0, "codePointLength is negative"); int indexStart = offsetOfCodePoint(utf8, codePointStart); if (indexStart < 0) { throw new IllegalArgumentException("UTF-8 does not contain " + codePointStart + " code points"); } if (codePointLength == 0) { return Slices.EMPTY_SLICE; } int indexEnd = offsetOfCodePoint(utf8, indexStart, codePointLength - 1); if (indexEnd < 0) { throw new IllegalArgumentException("UTF-8 does not contain " + (codePointStart + codePointLength) + " code points"); } indexEnd += lengthOfCodePoint(utf8, indexEnd); if (indexEnd > utf8.length()) { throw new InvalidUtf8Exception("UTF-8 is not well formed"); } return utf8.slice(indexStart, indexEnd - indexStart); } /** * Reverses the slice code point by code point. *

* Note: Invalid UTF-8 sequences are copied directly to the output. */ public static Slice reverse(Slice utf8) { int length = utf8.length(); Slice reverse = Slices.allocate(length); int forwardPosition = 0; int reversePosition = length; while (forwardPosition < length) { int codePointLength = lengthOfCodePointSafe(utf8, forwardPosition); // backup the reverse pointer reversePosition -= codePointLength; if (reversePosition < 0) { // this should not happen throw new InvalidUtf8Exception("UTF-8 is not well formed"); } // copy the character copyUtf8SequenceUnsafe(utf8, forwardPosition, reverse, reversePosition, codePointLength); forwardPosition += codePointLength; } return reverse; } /** * Converts slice to upper case code point by code point. This method does * not perform perform locale-sensitive, context-sensitive, or one-to-many * mappings required for some languages. Specifically, this will return * incorrect results for Lithuanian, Turkish, and Azeri. *

* Note: Invalid UTF-8 sequences are copied directly to the output. */ public static Slice toUpperCase(Slice utf8) { return translateCodePoints(utf8, UPPER_CODE_POINTS); } /** * Converts slice to lower case code point by code point. This method does * not perform perform locale-sensitive, context-sensitive, or one-to-many * mappings required for some languages. Specifically, this will return * incorrect results for Lithuanian, Turkish, and Azeri. *

* Note: Invalid UTF-8 sequences are copied directly to the output. */ public static Slice toLowerCase(Slice utf8) { return translateCodePoints(utf8, LOWER_CODE_POINTS); } private static Slice translateCodePoints(Slice utf8, int[] codePointTranslationMap) { int length = utf8.length(); Slice newUtf8 = Slices.allocate(length); int position = 0; int upperPosition = 0; while (position < length) { int codePoint = tryGetCodePointAt(utf8, position); if (codePoint >= 0) { int upperCodePoint = codePointTranslationMap[codePoint]; // grow slice if necessary int nextUpperPosition = upperPosition + lengthOfCodePoint(upperCodePoint); if (nextUpperPosition > length) { newUtf8 = Slices.ensureSize(newUtf8, nextUpperPosition); } // write new byte setCodePointAt(upperCodePoint, newUtf8, upperPosition); position += lengthOfCodePoint(codePoint); upperPosition = nextUpperPosition; } else { int skipLength = -codePoint; // grow slice if necessary int nextUpperPosition = upperPosition + skipLength; if (nextUpperPosition > length) { newUtf8 = Slices.ensureSize(newUtf8, nextUpperPosition); } copyUtf8SequenceUnsafe(utf8, position, newUtf8, upperPosition, skipLength); position += skipLength; upperPosition = nextUpperPosition; } } return newUtf8.slice(0, upperPosition); } private static void copyUtf8SequenceUnsafe(Slice source, int sourcePosition, Slice destination, int destinationPosition, int length) { switch (length) { case 1: destination.setByteUnchecked(destinationPosition, source.getByteUnchecked(sourcePosition)); break; case 2: destination.setShortUnchecked(destinationPosition, source.getShortUnchecked(sourcePosition)); break; case 3: destination.setShortUnchecked(destinationPosition, source.getShortUnchecked(sourcePosition)); destination.setByteUnchecked(destinationPosition + 2, source.getByteUnchecked(sourcePosition + 2)); break; case 4: destination.setIntUnchecked(destinationPosition, source.getIntUnchecked(sourcePosition)); break; case 5: destination.setIntUnchecked(destinationPosition, source.getIntUnchecked(sourcePosition)); destination.setByteUnchecked(destinationPosition + 4, source.getByteUnchecked(sourcePosition + 4)); break; case 6: destination.setIntUnchecked(destinationPosition, source.getIntUnchecked(sourcePosition)); destination.setShortUnchecked(destinationPosition + 4, source.getShortUnchecked(sourcePosition + 4)); break; default: throw new IllegalStateException("Invalid code point length " + length); } } /** * Removes all white space characters from the left string of the string. *

* Note: Invalid UTF-8 sequences are not trimmed. */ public static Slice leftTrim(Slice utf8) { int length = utf8.length(); int position = firstNonWhitespacePosition(utf8); return utf8.slice(position, length - position); } private static int firstNonWhitespacePosition(Slice utf8) { int length = utf8.length(); int position = 0; while (position < length) { int codePoint = tryGetCodePointAt(utf8, position); if (codePoint < 0) { break; } if (!WHITESPACE_CODE_POINTS[codePoint]) { break; } position += lengthOfCodePoint(codePoint); } return position; } /** * Removes all white space characters from the right side of the string. *

* Note: Invalid UTF-8 sequences are not trimmed. */ public static Slice rightTrim(Slice utf8) { int position = lastNonWhitespacePosition(utf8, 0); return utf8.slice(0, position); } private static int lastNonWhitespacePosition(Slice utf8, int minPosition) { int length = utf8.length(); int position = length; while (minPosition < position) { // decode the code point before position if possible int codePoint; byte unsignedByte = utf8.getByte(position - 1); if (!isContinuationByte(unsignedByte)) { codePoint = unsignedByte & 0xFF; } else if (minPosition <= position -2 && !isContinuationByte(utf8.getByte(position - 2))) { codePoint = tryGetCodePointAt(utf8, position - 2); } else if (minPosition <= position -3 && !isContinuationByte(utf8.getByte(position - 3))) { codePoint = tryGetCodePointAt(utf8, position - 3); } else if (minPosition <= position -4 && !isContinuationByte(utf8.getByte(position - 4))) { codePoint = tryGetCodePointAt(utf8, position - 4); } else { break; } if (codePoint < 0 || !WHITESPACE_CODE_POINTS[codePoint]) { break; } position -= lengthOfCodePoint(codePoint); } return position; } /** * Removes all white space characters from the left and right side of the string. *

* Note: Invalid UTF-8 sequences are not trimmed. */ public static Slice trim(Slice utf8) { int start = firstNonWhitespacePosition(utf8); int end = lastNonWhitespacePosition(utf8, start); return utf8.slice(start, end - start); } public static Slice fixInvalidUtf8(Slice slice) { return fixInvalidUtf8(slice, OptionalInt.of(REPLACEMENT_CODE_POINT)); } public static Slice fixInvalidUtf8(Slice slice, OptionalInt replacementCodePoint) { if (isAscii(slice)) { return slice; } int replacementCodePointValue = -1; int replacementCodePointLength = 0; if (replacementCodePoint.isPresent()) { replacementCodePointValue = replacementCodePoint.getAsInt(); replacementCodePointLength = lengthOfCodePoint(replacementCodePointValue); } int length = slice.length(); Slice utf8 = Slices.allocate(length); int dataPosition = 0; int utf8Position = 0; while (dataPosition < length) { int codePoint = tryGetCodePointAt(slice, dataPosition); int codePointLength; if (codePoint >= 0) { codePointLength = lengthOfCodePoint(codePoint); dataPosition += codePointLength; } else { // negative number carries the number of invalid bytes dataPosition += (-codePoint); if (replacementCodePointValue < 0) { continue; } codePoint = replacementCodePointValue; codePointLength = replacementCodePointLength; } utf8 = Slices.ensureSize(utf8, utf8Position + codePointLength); utf8Position += setCodePointAt(codePoint, utf8, utf8Position); } return utf8.slice(0, utf8Position); } /** * Tries to get the UTF-8 encoded code point at the {@code position}. A positive * return value means the UTF-8 sequence at the position is valid, and the result * is the code point. A negative return value means the UTF-8 sequence at the * position is invalid, and the length of the invalid sequence is the absolute * value of the result. * @return the code point or negative the number of bytes in the invalid UTF-8 sequence. */ public static int tryGetCodePointAt(Slice utf8, int position) { // // Process first byte byte firstByte = utf8.getByte(position); int length = lengthOfCodePointFromStartByteSafe(firstByte); if (length < 0) { return length; } if (length == 1) { // normal ASCII // 0xxx_xxxx return firstByte; } // // Process second byte if (position + 1 >= utf8.length()) { return -1; } byte secondByte = utf8.getByteUnchecked(position + 1); if (!isContinuationByte(secondByte)) { return -1; } if (length == 2) { // 110x_xxxx 10xx_xxxx return ((firstByte & 0b0001_1111) << 6) | (secondByte & 0b0011_1111); } // // Process third byte if (position + 2 >= utf8.length()) { return -2; } byte thirdByte = utf8.getByteUnchecked(position + 2); if (!isContinuationByte(thirdByte)) { return -2; } if (length == 3) { // 1110_xxxx 10xx_xxxx 10xx_xxxx int codePoint = ((firstByte & 0b0000_1111) << 12) | ((secondByte & 0b0011_1111) << 6) | (thirdByte & 0b0011_1111); // surrogates are invalid if (MIN_SURROGATE <= codePoint && codePoint <= MAX_SURROGATE) { return -3; } return codePoint; } // // Process forth byte if (position + 3 >= utf8.length()) { return -3; } byte forthByte = utf8.getByteUnchecked(position + 3); if (!isContinuationByte(forthByte)) { return -3; } if (length == 4) { // 1111_0xxx 10xx_xxxx 10xx_xxxx 10xx_xxxx int codePoint = ((firstByte & 0b0000_0111) << 18) | ((secondByte & 0b0011_1111) << 12) | ((thirdByte & 0b0011_1111) << 6) | (forthByte & 0b0011_1111); // 4 byte code points have a limited valid range if (codePoint < 0x11_0000) { return codePoint; } return -4; } // // Process fifth byte if (position + 4 >= utf8.length()) { return -4; } byte fifthByte = utf8.getByteUnchecked(position + 4); if (!isContinuationByte(fifthByte)) { return -4; } if (length == 5) { // Per RFC3629, UTF-8 is limited to 4 bytes, so more bytes are illegal return -5; } // // Process sixth byte if (position + 5 >= utf8.length()) { return -5; } byte sixthByte = utf8.getByteUnchecked(position + 5); if (!isContinuationByte(sixthByte)) { return -5; } if (length == 6) { // Per RFC3629, UTF-8 is limited to 4 bytes, so more bytes are illegal return -6; } // for longer sequence, which can't happen return -1; } static int lengthOfCodePointFromStartByteSafe(byte startByte) { int unsignedStartByte = startByte & 0xFF; if (unsignedStartByte < 0b1000_0000) { // normal ASCII // 0xxx_xxxx return 1; } if (unsignedStartByte < 0b1100_0000) { // illegal bytes // 10xx_xxxx return -1; } if (unsignedStartByte < 0b1110_0000) { // 110x_xxxx 10xx_xxxx return 2; } if (unsignedStartByte < 0b1111_0000) { // 1110_xxxx 10xx_xxxx 10xx_xxxx return 3; } if (unsignedStartByte < 0b1111_1000) { // 1111_0xxx 10xx_xxxx 10xx_xxxx 10xx_xxxx return 4; } if (unsignedStartByte < 0b1111_1100) { // 1111_10xx 10xx_xxxx 10xx_xxxx 10xx_xxxx 10xx_xxxx return 5; } if (unsignedStartByte < 0b1111_1110) { // 1111_110x 10xx_xxxx 10xx_xxxx 10xx_xxxx 10xx_xxxx 10xx_xxxx return 6; } return -1; } /** * Finds the index of the first byte of the code point at a position, or * {@code -1} if the position is not withing the slice. *

* Note: This method does not explicitly check for valid UTF-8, and may * return incorrect results or throw an exception for invalid UTF-8. */ public static int offsetOfCodePoint(Slice utf8, int codePointCount) { return offsetOfCodePoint(utf8, 0, codePointCount); } /** * Starting from {@code position} bytes in {@code utf8}, finds the * index of the first byte of the code point {@code codePointCount} * in the slice. If the slice does not contain * {@code codePointCount} code points after {@code position}, {@code -1} * is returned. *

* Note: This method does not explicitly check for valid UTF-8, and may * return incorrect results or throw an exception for invalid UTF-8. */ public static int offsetOfCodePoint(Slice utf8, int position, int codePointCount) { checkPositionIndex(position, utf8.length()); checkArgument(codePointCount >= 0, "codePointPosition is negative"); // Quick exit if we are sure that the position is after the end if (utf8.length() - position <= codePointCount) { return -1; } if (codePointCount == 0) { return position; } int correctIndex = codePointCount + position; // Length rounded to 8 bytes int length8 = utf8.length() & 0x7FFF_FFF8; // While we have enough bytes left and we need at least 8 characters process 8 bytes at once while (position < length8 && correctIndex >= position + 8) { // Count bytes which are NOT the start of a code point correctIndex += countContinuationBytes(utf8.getLongUnchecked(position)); position += 8; } // Length rounded to 4 bytes int length4 = utf8.length() & 0x7FFF_FFFC; // While we have enough bytes left and we need at least 4 characters process 4 bytes at once while (position < length4 && correctIndex >= position + 4) { // Count bytes which are NOT the start of a code point correctIndex += countContinuationBytes(utf8.getIntUnchecked(position)); position += 4; } // Do the rest one by one, always check the last byte to find the end of the code point while (position < utf8.length()) { // Count bytes which are NOT the start of a code point correctIndex += countContinuationBytes(utf8.getByteUnchecked(position)); if (position == correctIndex) { break; } position++; } if (position == correctIndex && correctIndex < utf8.length()) { return correctIndex; } return -1; } /** * Gets the UTF-8 sequence length of the code point at {@code position}. *

* Note: This method does not explicitly check for valid UTF-8, and may * return incorrect results or throw an exception for invalid UTF-8. */ public static int lengthOfCodePoint(Slice utf8, int position) { return lengthOfCodePointFromStartByte(utf8.getByte(position)); } /** * Gets the UTF-8 sequence length of the code point at {@code position}. *

* Truncated UTF-8 sequences, 5 and 6 byte sequences, and invalid code points * are handled by this method without throwing an exception. */ public static int lengthOfCodePointSafe(Slice utf8, int position) { int length = lengthOfCodePointFromStartByteSafe(utf8.getByte(position)); if (length < 0) { return -length; } if (length == 1 || position + 1 >= utf8.length() || !isContinuationByte(utf8.getByteUnchecked(position + 1))) { return 1; } if (length == 2 || position + 2 >= utf8.length() || !isContinuationByte(utf8.getByteUnchecked(position + 2))) { return 2; } if (length == 3 || position + 3 >= utf8.length() || !isContinuationByte(utf8.getByteUnchecked(position + 3))) { return 3; } if (length == 4 || position + 4 >= utf8.length() || !isContinuationByte(utf8.getByteUnchecked(position + 4))) { return 4; } if (length == 5 || position + 5 >= utf8.length() || !isContinuationByte(utf8.getByteUnchecked(position + 5))) { return 5; } if (length == 6) { return 6; } return 1; } /** * Gets the UTF-8 sequence length of the code point. * * @throws InvalidCodePointException if code point is not within a valid range */ public static int lengthOfCodePoint(int codePoint) { if (codePoint < 0) { throw new InvalidCodePointException(codePoint); } if (codePoint < 0x80) { // normal ASCII // 0xxx_xxxx return 1; } if (codePoint < 0x800) { return 2; } if (codePoint < 0x1_0000) { return 3; } if (codePoint < 0x11_0000) { return 4; } // Per RFC3629, UTF-8 is limited to 4 bytes, so more bytes are illegal throw new InvalidCodePointException(codePoint); } /** * Gets the UTF-8 sequence length using the sequence start byte. *

* Note: This method does not explicitly check for valid UTF-8, and may * return incorrect results or throw an exception for invalid UTF-8. */ public static int lengthOfCodePointFromStartByte(byte startByte) { int unsignedStartByte = startByte & 0xFF; if (unsignedStartByte < 0x80) { // normal ASCII // 0xxx_xxxx return 1; } if (unsignedStartByte < 0xc0) { // illegal bytes // 10xx_xxxx throw new InvalidUtf8Exception("Illegal start 0x" + toHexString(unsignedStartByte).toUpperCase() + " of code point"); } if (unsignedStartByte < 0xe0) { // 110x_xxxx 10xx_xxxx return 2; } if (unsignedStartByte < 0xf0) { // 1110_xxxx 10xx_xxxx 10xx_xxxx return 3; } if (unsignedStartByte < 0xf8) { // 1111_0xxx 10xx_xxxx 10xx_xxxx 10xx_xxxx return 4; } // Per RFC3629, UTF-8 is limited to 4 bytes, so more bytes are illegal throw new InvalidUtf8Exception("Illegal start 0x" + toHexString(unsignedStartByte).toUpperCase() + " of code point"); } /** * Gets the UTF-8 encoded code point at the {@code position}. *

* Note: This method does not explicitly check for valid UTF-8, and may * return incorrect results or throw an exception for invalid UTF-8. */ public static int getCodePointAt(Slice utf8, int position) { int unsignedStartByte = utf8.getByte(position) & 0xFF; if (unsignedStartByte < 0x80) { // normal ASCII // 0xxx_xxxx return unsignedStartByte; } if (unsignedStartByte < 0xc0) { // illegal bytes // 10xx_xxxx throw new InvalidUtf8Exception("Illegal start 0x" + toHexString(unsignedStartByte).toUpperCase() + " of code point"); } if (unsignedStartByte < 0xe0) { // 110x_xxxx 10xx_xxxx if (position + 1 >= utf8.length()) { throw new InvalidUtf8Exception("UTF-8 sequence truncated"); } return ((unsignedStartByte & 0b0001_1111) << 6) | (utf8.getByte(position + 1) & 0b0011_1111); } if (unsignedStartByte < 0xf0) { // 1110_xxxx 10xx_xxxx 10xx_xxxx if (position + 2 >= utf8.length()) { throw new InvalidUtf8Exception("UTF-8 sequence truncated"); } return ((unsignedStartByte & 0b0000_1111) << 12) | ((utf8.getByteUnchecked(position + 1) & 0b0011_1111) << 6) | (utf8.getByteUnchecked(position + 2) & 0b0011_1111); } if (unsignedStartByte < 0xf8) { // 1111_0xxx 10xx_xxxx 10xx_xxxx 10xx_xxxx if (position + 3 >= utf8.length()) { throw new InvalidUtf8Exception("UTF-8 sequence truncated"); } return ((unsignedStartByte & 0b0000_0111) << 18) | ((utf8.getByteUnchecked(position + 1) & 0b0011_1111) << 12) | ((utf8.getByteUnchecked(position + 2) & 0b0011_1111) << 6) | (utf8.getByteUnchecked(position + 3) & 0b0011_1111); } // Per RFC3629, UTF-8 is limited to 4 bytes, so more bytes are illegal throw new InvalidUtf8Exception("Illegal start 0x" + toHexString(unsignedStartByte).toUpperCase() + " of code point"); } /** * Gets the UTF-8 encoded code point before the {@code position}. *

* Note: This method does not explicitly check for valid UTF-8, and may * return incorrect results or throw an exception for invalid UTF-8. */ public static int getCodePointBefore(Slice utf8, int position) { byte unsignedByte = utf8.getByte(position - 1); if (!isContinuationByte(unsignedByte)) { return unsignedByte & 0xFF; } if (!isContinuationByte(utf8.getByte(position - 2))) { return getCodePointAt(utf8, position - 2); } if (!isContinuationByte(utf8.getByte(position - 3))) { return getCodePointAt(utf8, position - 3); } if (!isContinuationByte(utf8.getByte(position - 4))) { return getCodePointAt(utf8, position - 4); } // Per RFC3629, UTF-8 is limited to 4 bytes, so more bytes are illegal throw new InvalidUtf8Exception("UTF-8 is not well formed"); } private static boolean isContinuationByte(byte b) { return (b & 0b1100_0000) == 0b1000_0000; } /** * Convert the code point to UTF-8. *

* * @throws InvalidCodePointException if code point is not within a valid range */ public static Slice codePointToUtf8(int codePoint) { Slice utf8 = Slices.allocate(lengthOfCodePoint(codePoint)); setCodePointAt(codePoint, utf8, 0); return utf8; } /** * Sets the UTF-8 sequence for code point at the {@code position}. * * @throws InvalidCodePointException if code point is not within a valid range */ public static int setCodePointAt(int codePoint, Slice utf8, int position) { if (codePoint < 0) { throw new InvalidCodePointException(codePoint); } if (codePoint < 0x80) { // normal ASCII // 0xxx_xxxx utf8.setByte(position, codePoint); return 1; } if (codePoint < 0x800) { // 110x_xxxx 10xx_xxxx utf8.setByte(position, 0b1100_0000 | (codePoint >>> 6)); utf8.setByte(position + 1, 0b1000_0000 | (codePoint & 0b0011_1111)); return 2; } if (MIN_SURROGATE <= codePoint && codePoint <= MAX_SURROGATE) { throw new InvalidCodePointException(codePoint); } if (codePoint < 0x1_0000) { // 1110_xxxx 10xx_xxxx 10xx_xxxx utf8.setByte(position, 0b1110_0000 | ((codePoint >>> 12) & 0b0000_1111)); utf8.setByte(position + 1, 0b1000_0000 | ((codePoint >>> 6) & 0b0011_1111)); utf8.setByte(position + 2, 0b1000_0000 | (codePoint & 0b0011_1111)); return 3; } if (codePoint < 0x11_0000) { // 1111_0xxx 10xx_xxxx 10xx_xxxx 10xx_xxxx utf8.setByte(position, 0b1111_0000 | ((codePoint >>> 18) & 0b0000_0111)); utf8.setByte(position + 1, 0b1000_0000 | ((codePoint >>> 12) & 0b0011_1111)); utf8.setByte(position + 2, 0b1000_0000 | ((codePoint >>> 6) & 0b0011_1111)); utf8.setByte(position + 3, 0b1000_0000 | (codePoint & 0b0011_1111)); return 4; } // Per RFC3629, UTF-8 is limited to 4 bytes, so more bytes are illegal throw new InvalidCodePointException(codePoint); } private static int countContinuationBytes(byte i8) { // see below int value = i8 & 0xff; return (value >>> 7) & (~value >>> 6); } private static int countContinuationBytes(int i32) { // see below i32 = ((i32 & TOP_MASK32) >>> 1) & (~i32); return Integer.bitCount(i32); } private static int countContinuationBytes(long i64) { // Count the number of bytes that match 0b10xx_xxxx as follows: // 1. Mask off the 8th bit of every byte and shift it into the 7th position. // 2. Then invert the bytes, which turns the 0 in the 7th bit to a one. // 3. And together the restults of step 1 and 2, giving us a one in the 7th // position if the byte matched. // 4. Count the number of bits in the result, which is the number of bytes // that matched. i64 = ((i64 & TOP_MASK64) >>> 1) & (~i64); return Long.bitCount(i64); } } slice-0.16/src/main/java/io/airlift/slice/Slices.java000066400000000000000000000160321261474317300224320ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import sun.nio.ch.DirectBuffer; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import java.nio.channels.FileChannel.MapMode; import java.nio.charset.Charset; import static io.airlift.slice.Preconditions.checkNotNull; import static io.airlift.slice.Preconditions.checkPositionIndexes; import static java.nio.charset.StandardCharsets.UTF_8; import static sun.misc.Unsafe.ARRAY_BYTE_BASE_OFFSET; public final class Slices { /** * A slice with size {@code 0}. */ public static final Slice EMPTY_SLICE = new Slice(); private static final int SLICE_ALLOC_THRESHOLD = 524_288; // 2^19 private static final double SLICE_ALLOW_SKEW = 1.25; // must be > 1! private Slices() {} public static Slice ensureSize(Slice existingSlice, int minWritableBytes) { if (existingSlice == null) { return allocate(minWritableBytes); } if (minWritableBytes <= existingSlice.length()) { return existingSlice; } int newCapacity; if (existingSlice.length() == 0) { newCapacity = 1; } else { newCapacity = existingSlice.length(); } int minNewCapacity = minWritableBytes; while (newCapacity < minNewCapacity) { if (newCapacity < SLICE_ALLOC_THRESHOLD) { newCapacity <<= 1; } else { newCapacity *= SLICE_ALLOW_SKEW; } } Slice newSlice = allocate(newCapacity); newSlice.setBytes(0, existingSlice, 0, existingSlice.length()); return newSlice; } public static Slice allocate(int capacity) { if (capacity == 0) { return EMPTY_SLICE; } return new Slice(new byte[capacity]); } public static Slice allocateDirect(int capacity) { if (capacity == 0) { return EMPTY_SLICE; } return wrappedBuffer(ByteBuffer.allocateDirect(capacity)); } public static Slice copyOf(Slice slice) { return copyOf(slice, 0, slice.length()); } public static Slice copyOf(Slice slice, int offset, int length) { checkPositionIndexes(offset, offset + length, slice.length()); Slice copy = Slices.allocate(length); copy.setBytes(0, slice, offset, length); return copy; } /** * Wrap the visible portion of a {@link java.nio.ByteBuffer}. */ public static Slice wrappedBuffer(ByteBuffer buffer) { if (buffer instanceof DirectBuffer) { DirectBuffer direct = (DirectBuffer) buffer; return new Slice(null, direct.address() + buffer.position(), buffer.limit() - buffer.position(), buffer.capacity(), direct); } if (buffer.hasArray()) { int address = ARRAY_BYTE_BASE_OFFSET + buffer.arrayOffset() + buffer.position(); return new Slice(buffer.array(), address, buffer.limit() - buffer.position(), buffer.array().length, null); } throw new IllegalArgumentException("cannot wrap " + buffer.getClass().getName()); } public static Slice wrappedBuffer(byte... array) { if (array.length == 0) { return EMPTY_SLICE; } return new Slice(array); } public static Slice wrappedBuffer(byte[] array, int offset, int length) { if (length == 0) { return EMPTY_SLICE; } return new Slice(array, offset, length); } public static Slice wrappedBooleanArray(boolean... array) { return wrappedBooleanArray(array, 0, array.length); } public static Slice wrappedBooleanArray(boolean[] array, int offset, int length) { if (length == 0) { return EMPTY_SLICE; } return new Slice(array, offset, length); } public static Slice wrappedShortArray(short... array) { return wrappedShortArray(array, 0, array.length); } public static Slice wrappedShortArray(short[] array, int offset, int length) { if (length == 0) { return EMPTY_SLICE; } return new Slice(array, offset, length); } public static Slice wrappedIntArray(int... array) { return wrappedIntArray(array, 0, array.length); } public static Slice wrappedIntArray(int[] array, int offset, int length) { if (length == 0) { return EMPTY_SLICE; } return new Slice(array, offset, length); } public static Slice wrappedLongArray(long... array) { return wrappedLongArray(array, 0, array.length); } public static Slice wrappedLongArray(long[] array, int offset, int length) { if (length == 0) { return EMPTY_SLICE; } return new Slice(array, offset, length); } public static Slice wrappedFloatArray(float... array) { return wrappedFloatArray(array, 0, array.length); } public static Slice wrappedFloatArray(float[] array, int offset, int length) { if (length == 0) { return EMPTY_SLICE; } return new Slice(array, offset, length); } public static Slice wrappedDoubleArray(double... array) { return wrappedDoubleArray(array, 0, array.length); } public static Slice wrappedDoubleArray(double[] array, int offset, int length) { if (length == 0) { return EMPTY_SLICE; } return new Slice(array, offset, length); } public static Slice copiedBuffer(String string, Charset charset) { checkNotNull(string, "string is null"); checkNotNull(charset, "charset is null"); return wrappedBuffer(string.getBytes(charset)); } public static Slice utf8Slice(String string) { return copiedBuffer(string, UTF_8); } public static Slice mapFileReadOnly(File file) throws IOException { checkNotNull(file, "file is null"); if (!file.exists()) { throw new FileNotFoundException(file.toString()); } try (RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r"); FileChannel channel = randomAccessFile.getChannel()) { MappedByteBuffer byteBuffer = channel.map(MapMode.READ_ONLY, 0, file.length()); return wrappedBuffer(byteBuffer); } } } slice-0.16/src/main/java/io/airlift/slice/StringDecoder.java000066400000000000000000000053521261474317300237470ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.CharacterCodingException; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CoderResult; import java.nio.charset.CodingErrorAction; import java.util.IdentityHashMap; import java.util.Map; import static io.airlift.slice.Preconditions.checkNotNull; final class StringDecoder { private static final ThreadLocal> decoders = new ThreadLocal>() { @Override protected Map initialValue() { return new IdentityHashMap<>(); } }; private StringDecoder() {} @SuppressWarnings("ObjectToString") public static String decodeString(ByteBuffer src, Charset charset) { CharsetDecoder decoder = getDecoder(charset); CharBuffer dst = CharBuffer.allocate((int) ((double) src.remaining() * decoder.maxCharsPerByte())); try { CoderResult cr = decoder.decode(src, dst, true); if (!cr.isUnderflow()) { cr.throwException(); } cr = decoder.flush(dst); if (!cr.isUnderflow()) { cr.throwException(); } } catch (CharacterCodingException x) { throw new IllegalStateException(x); } return dst.flip().toString(); } /** * Returns a cached thread-local {@link java.nio.charset.CharsetDecoder} for the specified charset. */ private static CharsetDecoder getDecoder(Charset charset) { checkNotNull(charset, "charset is null"); Map map = decoders.get(); CharsetDecoder d = map.get(charset); if (d != null) { d.reset(); d.onMalformedInput(CodingErrorAction.REPLACE); d.onUnmappableCharacter(CodingErrorAction.REPLACE); return d; } d = charset.newDecoder(); d.onMalformedInput(CodingErrorAction.REPLACE); d.onUnmappableCharacter(CodingErrorAction.REPLACE); map.put(charset, d); return d; } } slice-0.16/src/main/java/io/airlift/slice/UnsafeSliceFactory.java000066400000000000000000000066151261474317300247470ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import java.lang.reflect.ReflectPermission; import java.security.Permission; /** * A slice factory for creating unsafe slices */ public class UnsafeSliceFactory { /** * The Permission object that is used to check whether a client has * sufficient privilege to defeat Java language access control checks. * This is the same permission used by {@link java.lang.reflect.AccessibleObject}. */ private static final Permission ACCESS_PERMISSION = new ReflectPermission("suppressAccessChecks"); /** * Accessible only to the privileged code. */ private static final UnsafeSliceFactory INSTANCE = new UnsafeSliceFactory(); /** * Get a factory for creating "unsafe" slices that can reference * arbitrary memory addresses. If there is a security manager, its * {@code checkPermission} method is called with a * {@code ReflectPermission("suppressAccessChecks")} permission. * * @return an unsafe slice factory */ @SuppressWarnings("JavaDoc") // IDEA-81310 public static UnsafeSliceFactory getInstance() { // see setAccessible() in AccessibleObject SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(ACCESS_PERMISSION); } return INSTANCE; } private UnsafeSliceFactory() {} /** * Creates a slice for directly a raw memory address. This is * inherently unsafe as it may be used to access arbitrary memory. * * @param address the raw memory address base * @param size the size of the slice * @return the unsafe slice */ public Slice newSlice(long address, int size) { if (address <= 0) { throw new IllegalArgumentException("Invalid address: " + address); } if (size == 0) { return Slices.EMPTY_SLICE; } return new Slice(null, address, size, 0, null); } /** * Creates a slice for directly a raw memory address. This is * inherently unsafe as it may be used to access arbitrary memory. * The slice will hold the specified object reference to prevent the * garbage collector from freeing it while it is in use by the slice. * * @param address the raw memory address base * @param size the size of the slice * @param reference the object reference * @return the unsafe slice */ public Slice newSlice(long address, int size, Object reference) { if (address <= 0) { throw new IllegalArgumentException("Invalid address: " + address); } if (reference == null) { throw new NullPointerException("Object reference is null"); } if (size == 0) { return Slices.EMPTY_SLICE; } return new Slice(null, address, size, size, reference); } } slice-0.16/src/main/java/io/airlift/slice/XxHash64.java000066400000000000000000000112601261474317300225630ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import static io.airlift.slice.JvmUtils.unsafe; import static io.airlift.slice.Preconditions.checkPositionIndexes; import static java.lang.Long.rotateLeft; public class XxHash64 { private final static long PRIME64_1 = 0x9E3779B185EBCA87L; private final static long PRIME64_2 = 0xC2B2AE3D27D4EB4FL; private final static long PRIME64_3 = 0x165667B19E3779F9L; private final static long PRIME64_4 = 0x85EBCA77C2b2AE63L; private final static long PRIME64_5 = 0x27D4EB2F165667C5L; private final static long DEFAULT_SEED = 0; public static long hash(long value) { long hash = DEFAULT_SEED + PRIME64_5 + SizeOf.SIZE_OF_LONG; hash = updateTail(hash, value); hash = finalShuffle(hash); return hash; } public static long hash(Slice data) { return hash(data, 0, data.length()); } public static long hash(long seed, Slice data) { return hash(seed, data, 0, data.length()); } public static long hash(Slice data, int offset, int length) { return hash(DEFAULT_SEED, data, offset, length); } public static long hash(long seed, Slice data, int offset, int length) { checkPositionIndexes(0, offset + length, data.length()); Object base = data.getBase(); final long address = data.getAddress() + offset; long hash; if (length >= 32) { hash = updateBody(seed, base, address, length - 32); } else { hash = seed + PRIME64_5; } hash += length; // round to the closest 32 byte boundary // this is the point up to which {@see #updateBody} processed int index = length & 0xFFFFFF70; while (index <= length - 8) { hash = updateTail(hash, unsafe.getLong(base, address + index)); index += 8; } if (index <= length - 4) { hash = updateTail(hash, unsafe.getInt(base, address + index)); index += 4; } while (index < length) { hash = updateTail(hash, unsafe.getByte(base, address + index)); index++; } hash = finalShuffle(hash); return hash; } private static long updateBody(long seed, Object base, long address, int length) { long v1 = seed + PRIME64_1 + PRIME64_2; long v2 = seed + PRIME64_2; long v3 = seed + 0; long v4 = seed - PRIME64_1; for (int index = 0; index <= length; index += 32) { v1 = mix(v1, unsafe.getLong(base, address)); v2 = mix(v2, unsafe.getLong(base, address + 8)); v3 = mix(v3, unsafe.getLong(base, address + 16)); v4 = mix(v4, unsafe.getLong(base, address + 24)); address += 32; } long hash = rotateLeft(v1, 1) + rotateLeft(v2, 7) + rotateLeft(v3, 12) + rotateLeft(v4, 18); hash = update(hash, v1); hash = update(hash, v2); hash = update(hash, v3); hash = update(hash, v4); return hash; } private static long mix(long current, long value) { return rotateLeft(current + value * PRIME64_2, 31) * PRIME64_1; } private static long update(long hash, long value) { long temp = hash ^ mix(0, value); return temp * PRIME64_1 + PRIME64_4; } private static long updateTail(long hash, long value) { long temp = hash ^ mix(0, value); return rotateLeft(temp, 27) * PRIME64_1 + PRIME64_4; } private static long updateTail(long hash, int value) { long unsigned = value & 0xFFFF_FFFFL; long temp = hash ^ (unsigned * PRIME64_1); return rotateLeft(temp, 23) * PRIME64_2 + PRIME64_3; } private static long updateTail(long hash, byte value) { int unsigned = value & 0xFF; long temp = hash ^ (unsigned * PRIME64_5); return rotateLeft(temp, 11) * PRIME64_1; } private static long finalShuffle(long hash) { hash ^= hash >>> 33; hash *= PRIME64_2; hash ^= hash >>> 29; hash *= PRIME64_3; hash ^= hash >>> 32; return hash; } } slice-0.16/src/main/java/io/airlift/slice/testing/000077500000000000000000000000001261474317300220205ustar00rootroot00000000000000slice-0.16/src/main/java/io/airlift/slice/testing/SliceAssertions.java000066400000000000000000000030311261474317300257720ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice.testing; import io.airlift.slice.Slice; public class SliceAssertions { public static void assertSlicesEqual(Slice actual, Slice expected) { if (actual == null && expected == null) { return; } else if (actual == null) { throw new AssertionError("Actual is null"); } else if (expected == null) { throw new AssertionError("Expected actual to be null"); } if (actual.length() != expected.length()) { throw new AssertionError(String.format("Slices differ in size. Actual: %s, expected: %s", actual.length(), expected.length())); } for (int i = 0; i < actual.length(); i++) { if (actual.getByte(i) != expected.getByte(i)) { throw new AssertionError(String.format("Slices differ at index %s. Actual: 0x%02x, expected: 0x%02x", i, actual.getUnsignedByte(i), expected.getUnsignedByte(i))); } } } } slice-0.16/src/test/000077500000000000000000000000001261474317300143155ustar00rootroot00000000000000slice-0.16/src/test/java/000077500000000000000000000000001261474317300152365ustar00rootroot00000000000000slice-0.16/src/test/java/io/000077500000000000000000000000001261474317300156455ustar00rootroot00000000000000slice-0.16/src/test/java/io/airlift/000077500000000000000000000000001261474317300172775ustar00rootroot00000000000000slice-0.16/src/test/java/io/airlift/slice/000077500000000000000000000000001261474317300203765ustar00rootroot00000000000000slice-0.16/src/test/java/io/airlift/slice/AbstractSliceInputTest.java000066400000000000000000000425051261474317300256520ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import com.google.common.base.Throwables; import com.google.common.collect.ImmutableList; import com.google.common.io.ByteSource; import com.google.common.io.ByteStreams; import org.testng.annotations.Test; import java.io.ByteArrayOutputStream; import java.io.EOFException; import java.io.IOException; import java.util.List; import static com.google.common.collect.Iterables.cycle; import static io.airlift.slice.SizeOf.SIZE_OF_BYTE; import static io.airlift.slice.SizeOf.SIZE_OF_DOUBLE; import static io.airlift.slice.SizeOf.SIZE_OF_FLOAT; import static io.airlift.slice.SizeOf.SIZE_OF_INT; import static io.airlift.slice.SizeOf.SIZE_OF_LONG; import static io.airlift.slice.SizeOf.SIZE_OF_SHORT; import static java.nio.charset.StandardCharsets.UTF_8; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; public abstract class AbstractSliceInputTest { protected static final int BUFFER_SIZE = 129; private static final List VARIABLE_READ_SIZES = ImmutableList.of( 1, 7, 15, BUFFER_SIZE - 1, BUFFER_SIZE, BUFFER_SIZE + 1, BUFFER_SIZE + 13); protected abstract SliceInput createSliceInput(Slice slice); @Test public void testReadBoolean() { testSliceInput(new SliceInputTester(SIZE_OF_BYTE) { @Override public void loadValue(SliceOutput output, int valueIndex) { output.writeBoolean(valueIndex % 2 == 0); } @Override public void verifyValue(SliceInput input, int valueIndex) { assertEquals(input.readBoolean(), valueIndex % 2 == 0); } }); } @Test public void testReadByte() { testSliceInput(new SliceInputTester(SIZE_OF_BYTE) { @Override public void loadValue(SliceOutput output, int valueIndex) { output.appendByte((byte) valueIndex); } @Override public void verifyValue(SliceInput input, int valueIndex) { assertEquals(input.readByte(), (byte) valueIndex); } }); } @Test public void testRead() { testSliceInput(new SliceInputTester(SIZE_OF_BYTE) { @Override public void loadValue(SliceOutput output, int valueIndex) { output.appendByte((byte) valueIndex); } @Override public void verifyValue(SliceInput input, int valueIndex) { assertEquals(input.read(), valueIndex & 0xFF); } @Override public void verifyReadOffEnd(SliceInput input) { assertEquals(input.read(), -1); } }); } @Test public void testReadShort() { testSliceInput(new SliceInputTester(SIZE_OF_SHORT) { @Override public void loadValue(SliceOutput output, int valueIndex) { output.appendShort(valueIndex); } @Override public void verifyValue(SliceInput input, int valueIndex) { assertEquals(input.readShort(), (short) valueIndex); } }); } @Test public void testReadUnsignedShort() { testSliceInput(new SliceInputTester(SIZE_OF_SHORT) { @Override public void loadValue(SliceOutput output, int valueIndex) { output.appendShort(valueIndex); } @Override public void verifyValue(SliceInput input, int valueIndex) { assertEquals(input.readUnsignedShort(), valueIndex & 0xFFF); } }); } @Test public void testReadInt() { testSliceInput(new SliceInputTester(SIZE_OF_INT) { @Override public void loadValue(SliceOutput output, int valueIndex) { output.appendInt(valueIndex); } @Override public void verifyValue(SliceInput input, int valueIndex) { assertEquals(input.readInt(), valueIndex); } }); } @Test public void testUnsignedReadInt() { testSliceInput(new SliceInputTester(SIZE_OF_INT) { @Override public void loadValue(SliceOutput output, int valueIndex) { output.appendInt(valueIndex); } @Override public void verifyValue(SliceInput input, int valueIndex) { assertEquals(input.readUnsignedInt(), valueIndex); } }); } @Test public void testReadLong() { testSliceInput(new SliceInputTester(SIZE_OF_LONG) { @Override public void loadValue(SliceOutput output, int valueIndex) { output.appendLong(valueIndex); } @Override public void verifyValue(SliceInput input, int valueIndex) { assertEquals(input.readLong(), valueIndex); } }); } @Test public void testReadFloat() { testSliceInput(new SliceInputTester(SIZE_OF_FLOAT) { @Override public void loadValue(SliceOutput output, int valueIndex) { output.writeFloat(valueIndex + 0.12f); } @Override public void verifyValue(SliceInput input, int valueIndex) { assertEquals(input.readFloat(), valueIndex + 0.12f); } }); } @Test public void testReadDouble() { testSliceInput(new SliceInputTester(SIZE_OF_DOUBLE) { @Override public void loadValue(SliceOutput output, int valueIndex) { output.appendDouble(valueIndex + 0.12); } @Override public void verifyValue(SliceInput input, int valueIndex) { assertEquals(input.readDouble(), valueIndex + 0.12); } }); } @Test public void testSkip() { for (int readSize : VARIABLE_READ_SIZES) { // skip without any reads testSliceInput(new SkipSliceInputTester(readSize) { @Override public void verifyValue(SliceInput input, int valueIndex) { input.skip(valueSize()); } @Override public void verifyReadOffEnd(SliceInput input) { assertEquals(input.skip(valueSize()), valueSize() - 1); } }); testSliceInput(new SkipSliceInputTester(readSize) { @Override public void verifyValue(SliceInput input, int valueIndex) { input.skipBytes(valueSize()); } @Override public void verifyReadOffEnd(SliceInput input) { assertEquals(input.skip(valueSize()), valueSize() - 1); } }); // read when no data available to force buffering testSliceInput(new SkipSliceInputTester(readSize) { @Override public void verifyValue(SliceInput input, int valueIndex) { int length = valueSize(); while (length > 0) { if (!input.isReadable()) { input.readByte(); length--; } int skipSize = input.skipBytes(length); length -= skipSize; } assertEquals(input.skip(0), 0); } }); testSliceInput(new SkipSliceInputTester(readSize) { @Override public void verifyValue(SliceInput input, int valueIndex) { long length = valueSize(); while (length > 0) { if (!input.isReadable()) { input.readByte(); length--; } long skipSize = input.skip(length); length -= skipSize; } assertEquals(input.skip(0), 0); } }); } } @Test public void testReadSlice() { for (int readSize : VARIABLE_READ_SIZES) { testSliceInput(new StringSliceInputTester(readSize) { @Override public String readActual(SliceInput input) { return input.readSlice(valueSize()).toStringUtf8(); } }); } } @Test public void testReadBytes() { for (int readSize : VARIABLE_READ_SIZES) { testSliceInput(new StringSliceInputTester(readSize) { @Override public String readActual(SliceInput input) { Slice slice = Slices.allocate(valueSize()); input.readBytes(slice); return slice.toStringUtf8(); } }); testSliceInput(new StringSliceInputTester(readSize) { @Override public String readActual(SliceInput input) { Slice slice = Slices.allocate(valueSize() + 5); input.readBytes(slice, valueSize()); return slice.slice(0, valueSize()).toStringUtf8(); } }); testSliceInput(new StringSliceInputTester(readSize) { @Override public String readActual(SliceInput input) { Slice slice = Slices.allocate(valueSize() + 10); input.readBytes(slice, 5, valueSize()); return slice.slice(5, valueSize()).toStringUtf8(); } }); testSliceInput(new StringSliceInputTester(readSize) { @Override public String readActual(SliceInput input) { byte[] bytes = new byte[valueSize()]; input.readBytes(bytes, 0, valueSize()); return new String(bytes, 0, valueSize(), UTF_8); } }); testSliceInput(new StringSliceInputTester(readSize) { @Override public String readActual(SliceInput input) { byte[] bytes = new byte[valueSize() + 10]; input.readBytes(bytes, 5, valueSize()); return new String(bytes, 5, valueSize(), UTF_8); } }); testSliceInput(new StringSliceInputTester(readSize) { @Override public String readActual(SliceInput input) { byte[] bytes = new byte[valueSize()]; int bytesRead = input.read(bytes); if (bytesRead == -1) { throw new IndexOutOfBoundsException(); } assertTrue(bytesRead > 0, "Expected to read at least one byte"); input.readBytes(bytes, bytesRead, bytes.length - bytesRead); return new String(bytes, 0, valueSize(), UTF_8); } }); testSliceInput(new StringSliceInputTester(readSize) { @Override public String readActual(SliceInput input) { try { byte[] bytes = new byte[valueSize() + 10]; ByteStreams.readFully(input, bytes, 5, valueSize()); return new String(bytes, 5, valueSize(), UTF_8); } catch (EOFException e) { throw new IndexOutOfBoundsException(); } catch (IOException e) { throw Throwables.propagate(e); } } }); testSliceInput(new StringSliceInputTester(readSize) { @Override public String readActual(SliceInput input) { try { ByteArrayOutputStream out = new ByteArrayOutputStream(); input.readBytes(out, valueSize()); return new String(out.toByteArray(), UTF_8); } catch (IOException e) { throw Throwables.propagate(e); } } }); } } protected void testSliceInput(SliceInputTester tester) { Slice slice = Slices.allocate((BUFFER_SIZE * 3) + 10); SliceOutput output = slice.getOutput(); for (int i = 0; i < slice.length() / tester.valueSize(); i++) { tester.loadValue(output, i); } testReadForward(tester, slice); testReadReverse(tester, slice); testReadOffEnd(tester, slice); } protected void testReadReverse(SliceInputTester tester, Slice slice) { SliceInput input = createSliceInput(slice); for (int i = slice.length() / tester.valueSize() - 1; i >= 0; i--) { int position = i * tester.valueSize(); input.setPosition(position); assertEquals(input.position(), position); tester.verifyValue(input, i); } } protected void testReadForward(SliceInputTester tester, Slice slice) { SliceInput input = createSliceInput(slice); for (int i = 0; i < slice.length() / tester.valueSize(); i++) { int position = i * tester.valueSize(); assertEquals(input.position(), position); tester.verifyValue(input, i); } } protected void testReadOffEnd(SliceInputTester tester, Slice slice) { SliceInput input = createSliceInput(slice); try { ByteStreams.skipFully(input, slice.length() - tester.valueSize() + 1); } catch (IOException e) { throw Throwables.propagate(e); } tester.verifyReadOffEnd(input); } private static String getExpectedStringValue(int index, int size) { try { return ByteSource.concat(cycle(ByteSource.wrap(String.valueOf(index).getBytes(UTF_8)))).slice(0, size).asCharSource(UTF_8).read(); } catch (IOException e) { throw Throwables.propagate(e); } } protected abstract static class SliceInputTester { private final int size; public SliceInputTester(int size) { this.size = size; } public final int valueSize() { return size; } public abstract void loadValue(SliceOutput slice, int valueIndex); public abstract void verifyValue(SliceInput input, int valueIndex); public void verifyReadOffEnd(SliceInput input) { try { verifyValue(input, 1); fail("expected IndexOutOfBoundsException"); } catch (IndexOutOfBoundsException expected) { } } } private abstract static class SkipSliceInputTester extends SliceInputTester { public SkipSliceInputTester(int size) { super(size); } @Override public void loadValue(SliceOutput output, int valueIndex) { output.writeBytes(new byte[valueSize()]); } } private abstract static class StringSliceInputTester extends SliceInputTester { public StringSliceInputTester(int size) { super(size); } @Override public final void loadValue(SliceOutput output, int valueIndex) { output.writeBytes(getExpectedStringValue(valueIndex, valueSize()).getBytes(UTF_8)); } @Override public final void verifyValue(SliceInput input, int valueIndex) { String actual = readActual(input); String expected = getExpectedStringValue(valueIndex, valueSize()); assertEquals(actual, expected); } protected abstract String readActual(SliceInput input); } } slice-0.16/src/test/java/io/airlift/slice/BenchmarkData.java000066400000000000000000000026011261474317300237240ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import org.openjdk.jmh.annotations.Param; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; import java.util.concurrent.ThreadLocalRandom; @State(Scope.Thread) public class BenchmarkData { @Param({"1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", "2048", "4096", "8192", "16384", "32768", "65536", "131072", "262144", "524288", "1048576"}) public int size; private byte[] bytes; private Slice slice; @Setup public void setup() { bytes = new byte[size]; ThreadLocalRandom.current().nextBytes(bytes); slice = Slices.wrappedBuffer(bytes); } public Slice getSlice() { return slice; } public byte[] getBytes() { return bytes; } } slice-0.16/src/test/java/io/airlift/slice/BenchmarkHashCode.java000066400000000000000000000036451261474317300245420ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import org.openjdk.jmh.annotations.Fork; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.Measurement; import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.Warmup; import org.openjdk.jmh.runner.Runner; import org.openjdk.jmh.runner.RunnerException; import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; import org.openjdk.jmh.runner.options.VerboseMode; import java.util.concurrent.TimeUnit; @State(Scope.Thread) @OutputTimeUnit(TimeUnit.SECONDS) @Fork(5) @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) public class BenchmarkHashCode { @Benchmark public long hash(BenchmarkData data, ByteCounter counter) { counter.add(data.getSlice().length()); return data.getSlice().hashCode(0, data.getSlice().length()); } public static void main(String[] args) throws RunnerException { Options options = new OptionsBuilder() .verbosity(VerboseMode.NORMAL) .include(".*" + BenchmarkHashCode.class.getSimpleName() + ".*") .build(); new Runner(options).run(); } } slice-0.16/src/test/java/io/airlift/slice/BenchmarkMurmur3Hash128.java000066400000000000000000000053531261474317300254730ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import com.google.common.hash.Hashing; import org.openjdk.jmh.annotations.Fork; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.Measurement; import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.Warmup; import org.openjdk.jmh.runner.Runner; import org.openjdk.jmh.runner.RunnerException; import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; import org.openjdk.jmh.runner.options.VerboseMode; import java.util.concurrent.TimeUnit; @State(Scope.Thread) @OutputTimeUnit(TimeUnit.SECONDS) @Fork(5) @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) public class BenchmarkMurmur3Hash128 { @Benchmark public long hash64(BenchmarkData data, ByteCounter counter) { counter.add(data.getSlice().length()); return Murmur3Hash128.hash64(data.getSlice()); } @Benchmark public Slice hash(BenchmarkData data, ByteCounter counter) { counter.add(data.getSlice().length()); return Murmur3Hash128.hash(data.getSlice()); } @Benchmark public long guava(BenchmarkData data, ByteCounter counter) { counter.add(data.getSlice().length()); return Hashing.murmur3_128().hashBytes(data.getBytes()).asLong(); } @Benchmark public long specializedHashLong(SingleLong data, ByteCounter counter) { counter.add(SizeOf.SIZE_OF_LONG); return Murmur3Hash128.hash64(data.getValue()); } @Benchmark public long hashLong(BenchmarkData data, ByteCounter counter) { counter.add(SizeOf.SIZE_OF_LONG); return Murmur3Hash128.hash64(data.getSlice(), 0, 8); } public static void main(String[] args) throws RunnerException { Options options = new OptionsBuilder() .verbosity(VerboseMode.NORMAL) .include(".*" + BenchmarkMurmur3Hash128.class.getSimpleName() + ".*") .build(); new Runner(options).run(); } } slice-0.16/src/test/java/io/airlift/slice/BenchmarkMurmur3Hash32.java000066400000000000000000000056371261474317300254120ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import com.google.common.hash.Hashing; import org.openjdk.jmh.annotations.Fork; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.Measurement; import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.Warmup; import org.openjdk.jmh.runner.Runner; import org.openjdk.jmh.runner.RunnerException; import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; import org.openjdk.jmh.runner.options.VerboseMode; import java.util.concurrent.TimeUnit; @State(Scope.Thread) @OutputTimeUnit(TimeUnit.SECONDS) @Fork(5) @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) public class BenchmarkMurmur3Hash32 { @Benchmark public int hash(BenchmarkData data, ByteCounter counter) { counter.add(data.getSlice().length()); return Murmur3Hash32.hash(data.getSlice()); } @Benchmark public int guava(BenchmarkData data, ByteCounter counter) { counter.add(data.getSlice().length()); return Hashing.murmur3_32().hashBytes(data.getBytes()).asInt(); } @Benchmark public int specializedHashInt(SingleLong data, ByteCounter counter) { counter.add(SizeOf.SIZE_OF_INT); return Murmur3Hash32.hash((int) data.getValue()); } @Benchmark public int hashInt(BenchmarkData data, ByteCounter counter) { counter.add(SizeOf.SIZE_OF_INT); return Murmur3Hash32.hash(data.getSlice(), 0, 4); } @Benchmark public int specializedHashLong(SingleLong data, ByteCounter counter) { counter.add(SizeOf.SIZE_OF_LONG); return Murmur3Hash32.hash(data.getValue()); } @Benchmark public int hashLong(BenchmarkData data, ByteCounter counter) { counter.add(SizeOf.SIZE_OF_LONG); return Murmur3Hash32.hash(data.getSlice(), 0, 8); } public static void main(String[] args) throws RunnerException { Options options = new OptionsBuilder() .verbosity(VerboseMode.NORMAL) .include(".*" + BenchmarkMurmur3Hash32.class.getSimpleName() + ".*") .build(); new Runner(options).run(); } } slice-0.16/src/test/java/io/airlift/slice/BenchmarkXxHash64.java000066400000000000000000000041211261474317300244270ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import org.openjdk.jmh.annotations.Fork; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.Measurement; import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.Warmup; import org.openjdk.jmh.runner.Runner; import org.openjdk.jmh.runner.RunnerException; import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; import org.openjdk.jmh.runner.options.VerboseMode; import java.util.concurrent.TimeUnit; @State(Scope.Thread) @OutputTimeUnit(TimeUnit.SECONDS) @Fork(5) @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) public class BenchmarkXxHash64 { @Benchmark public long xxhash64(BenchmarkData data, ByteCounter counter) { counter.add(data.getSlice().length()); return XxHash64.hash(data.getSlice()); } @Benchmark public long specializedHashLong(SingleLong data, ByteCounter counter) { counter.add(SizeOf.SIZE_OF_LONG); return XxHash64.hash(data.getValue()); } public static void main(String[] args) throws RunnerException { Options options = new OptionsBuilder() .verbosity(VerboseMode.NORMAL) .include(".*" + BenchmarkXxHash64.class.getSimpleName() + ".*") .build(); new Runner(options).run(); } } slice-0.16/src/test/java/io/airlift/slice/ByteCounter.java000066400000000000000000000021501261474317300235020ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import org.openjdk.jmh.annotations.AuxCounters; import org.openjdk.jmh.annotations.Level; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; @AuxCounters @State(Scope.Thread) public class ByteCounter { private long bytes; @Setup(Level.Iteration) public void clean() { bytes = 0; } public long megabytes() { return bytes / 1024 / 1024; } public void add(long bytes) { this.bytes += bytes; } } slice-0.16/src/test/java/io/airlift/slice/MemoryCopyBenchmark.java000066400000000000000000000177551261474317300251760ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Fork; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.Measurement; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.Warmup; import org.openjdk.jmh.runner.Runner; import org.openjdk.jmh.runner.RunnerException; import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; import org.openjdk.jmh.runner.options.VerboseMode; import java.util.concurrent.ThreadLocalRandom; import static io.airlift.slice.JvmUtils.unsafe; @SuppressWarnings("restriction") @BenchmarkMode(Mode.Throughput) @Fork(5) @Warmup(iterations = 10) @Measurement(iterations = 10) public class MemoryCopyBenchmark { static final int PAGE_SIZE = 4 * 1024; static final int N_PAGES = 256 * 1024; static final int ALLOC_SIZE = PAGE_SIZE * N_PAGES; @State(Scope.Thread) public static class Buffers { Slice data; long startOffset; long destOffset; @Setup public void fillWithBogusData() { data = Slices.allocate(ALLOC_SIZE); for (int idx = 0; idx < data.length() / 8; idx++) { data.setLong(idx, ThreadLocalRandom.current().nextLong()); } long startOffsetPages = ThreadLocalRandom.current().nextInt(N_PAGES / 4); long destOffsetPages = ThreadLocalRandom.current().nextInt(N_PAGES / 4) + N_PAGES / 2; startOffset = startOffsetPages * PAGE_SIZE; destOffset = destOffsetPages * PAGE_SIZE; } } @Benchmark public Slice b00sliceZero(Buffers buffers) { return doCopy(buffers, CopyStrategy.SLICE, 0); } @Benchmark public Slice b01customLoopZero(Buffers buffers) { return doCopy(buffers, CopyStrategy.CUSTOM_LOOP, 0); } @Benchmark public Slice b02unsafeZero(Buffers buffers) { return doCopy(buffers, CopyStrategy.UNSAFE, 0); } @Benchmark public Slice b03slice32B(Buffers buffers) { return doCopy(buffers, CopyStrategy.SLICE, 32); } @Benchmark public Slice b04customLoop32B(Buffers buffers) { return doCopy(buffers, CopyStrategy.CUSTOM_LOOP, 32); } @Benchmark public Slice b05unsafe32B(Buffers buffers) { return doCopy(buffers, CopyStrategy.UNSAFE, 32); } @Benchmark public Slice b06slice128B(Buffers buffers) { return doCopy(buffers, CopyStrategy.SLICE, 128); } @Benchmark public Slice b07customLoop128B(Buffers buffers) { return doCopy(buffers, CopyStrategy.CUSTOM_LOOP, 128); } @Benchmark public Slice b08unsafe128B(Buffers buffers) { return doCopy(buffers, CopyStrategy.UNSAFE, 128); } @Benchmark public Slice b09slice512B(Buffers buffers) { return doCopy(buffers, CopyStrategy.SLICE, 512); } @Benchmark public Slice b10customLoop512B(Buffers buffers) { return doCopy(buffers, CopyStrategy.CUSTOM_LOOP, 512); } @Benchmark public Slice b11unsafe512B(Buffers buffers) { return doCopy(buffers, CopyStrategy.UNSAFE, 512); } @Benchmark public Slice b12slice1K(Buffers buffers) { return doCopy(buffers, CopyStrategy.SLICE, 1024); } @Benchmark public Slice b13customLoop1K(Buffers buffers) { return doCopy(buffers, CopyStrategy.CUSTOM_LOOP, 1024); } @Benchmark public Slice b14unsafe1K(Buffers buffers) { return doCopy(buffers, CopyStrategy.UNSAFE, 1024); } @Benchmark public Slice b15slice1M(Buffers buffers) { return doCopy(buffers, CopyStrategy.SLICE, 1024 * 1024); } @Benchmark public Slice b16customLoop1M(Buffers buffers) { return doCopy(buffers, CopyStrategy.CUSTOM_LOOP, 1024 * 1024); } @Benchmark public Slice b17unsafe1M(Buffers buffers) { return doCopy(buffers, CopyStrategy.UNSAFE, 1024 * 1024); } @Benchmark public Slice b18slice128M(Buffers buffers) { return doCopy(buffers, CopyStrategy.SLICE, 128 * 1024 * 1024); } @Benchmark public Slice b19customLoop128M(Buffers buffers) { return doCopy(buffers, CopyStrategy.CUSTOM_LOOP, 128 * 1024 * 1024); } @Benchmark public Slice b20unsafe128M(Buffers buffers) { return doCopy(buffers, CopyStrategy.UNSAFE, 128 * 1024 * 1024); } static Slice doCopy(Buffers buffers, CopyStrategy strategy, int length) { assert buffers.startOffset >= 0 : "startOffset < 0"; assert buffers.destOffset >= 0 : "destOffset < 0"; assert buffers.startOffset + length < ALLOC_SIZE : "startOffset + length >= ALLOC_SIZE"; assert buffers.destOffset + length < ALLOC_SIZE : "destOffset + length >= ALLOC_SIZE"; strategy.doCopy(buffers.data, buffers.startOffset, buffers.destOffset, length); return buffers.data; } private enum CopyStrategy { SLICE { @Override public void doCopy(Slice data, long src, long dest, int length) { data.setBytes((int) dest, data, (int) src, length); } }, CUSTOM_LOOP { @Override public void doCopy(Slice data, long src, long dest, int length) { Object base = data.getBase(); long offset = data.getAddress(); while (length >= SizeOf.SIZE_OF_LONG) { long srcLong = unsafe.getLong(base, src + offset); unsafe.putLong(base, dest + offset, srcLong); offset += SizeOf.SIZE_OF_LONG; length -= SizeOf.SIZE_OF_LONG; } while (length > 0) { byte srcByte = unsafe.getByte(base, src + offset); unsafe.putByte(base, dest + offset, srcByte); offset++; length--; } } }, UNSAFE { @Override public void doCopy(Slice data, long srcOffset, long destOffset, int length) { Object base = data.getBase(); srcOffset += data.getAddress(); destOffset += data.getAddress(); int bytesToCopy = length - (length % 8); unsafe.copyMemory(base, srcOffset, base, destOffset, bytesToCopy); unsafe.copyMemory(base, srcOffset + bytesToCopy, base, destOffset + bytesToCopy, length - bytesToCopy); } }; public abstract void doCopy(Slice data, long src, long dest, int length); } public static void main(String[] args) throws RunnerException { Options options = new OptionsBuilder() .verbosity(VerboseMode.NORMAL) .include(".*" + MemoryCopyBenchmark.class.getSimpleName() + ".*") .build(); new Runner(options).run(); } } slice-0.16/src/test/java/io/airlift/slice/SingleLong.java000066400000000000000000000020101261474317300232730ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; import java.util.concurrent.ThreadLocalRandom; @State(Scope.Thread) public class SingleLong { private long value; @Setup public void setup() throws Exception { value = ThreadLocalRandom.current().nextLong(); } public long getValue() { return value; } } slice-0.16/src/test/java/io/airlift/slice/SliceUtf8Benchmark.java000066400000000000000000000211051261474317300246610ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Fork; import org.openjdk.jmh.annotations.Measurement; import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Param; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.Warmup; import org.openjdk.jmh.runner.Runner; import org.openjdk.jmh.runner.RunnerException; import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; import org.openjdk.jmh.runner.options.VerboseMode; import java.nio.charset.StandardCharsets; import java.util.concurrent.ThreadLocalRandom; import java.util.stream.IntStream; import static io.airlift.slice.SliceUtf8.countCodePoints; import static io.airlift.slice.SliceUtf8.leftTrim; import static io.airlift.slice.SliceUtf8.lengthOfCodePoint; import static io.airlift.slice.SliceUtf8.lengthOfCodePointFromStartByte; import static io.airlift.slice.SliceUtf8.offsetOfCodePoint; import static io.airlift.slice.SliceUtf8.reverse; import static io.airlift.slice.SliceUtf8.rightTrim; import static io.airlift.slice.SliceUtf8.substring; import static io.airlift.slice.SliceUtf8.toLowerCase; import static io.airlift.slice.SliceUtf8.toUpperCase; import static io.airlift.slice.SliceUtf8.trim; import static io.airlift.slice.Slices.utf8Slice; import static java.lang.Character.MAX_CODE_POINT; import static java.lang.Character.SURROGATE; import static java.lang.Character.getType; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.NANOSECONDS; import static org.openjdk.jmh.annotations.Mode.AverageTime; import static org.openjdk.jmh.annotations.Scope.Thread; @SuppressWarnings("MethodMayBeStatic") @State(Thread) @OutputTimeUnit(NANOSECONDS) @BenchmarkMode(AverageTime) @Fork(1) @Warmup(iterations = 4, time = 500, timeUnit = MILLISECONDS) @Measurement(iterations = 5, time = 500, timeUnit = MILLISECONDS) public class SliceUtf8Benchmark { @Benchmark public int benchmarkLengthOfCodePointFromStartByte(BenchmarkData data) { Slice slice = data.getSlice(); int i = 0; int codePoints = 0; while (i < slice.length()) { i += lengthOfCodePointFromStartByte(slice.getByte(i)); codePoints++; } if (codePoints != data.getLength()) { throw new AssertionError(); } return codePoints; } @Benchmark public int benchmarkCountCodePoints(BenchmarkData data) { int codePoints = countCodePoints(data.getSlice()); if (codePoints != data.getLength()) { throw new AssertionError(); } return codePoints; } @Benchmark public int benchmarkOffsetByCodePoints(BenchmarkData data) { Slice slice = data.getSlice(); int offset = offsetOfCodePoint(slice, data.getLength() - 1); if (offset + lengthOfCodePoint(slice, offset) != slice.length()) { throw new AssertionError(); } return offset; } @Benchmark public Slice benchmarkSubstring(BenchmarkData data) { Slice slice = data.getSlice(); int length = data.getLength(); return substring(slice, (length / 2) - 1, length / 2); } @Benchmark public Slice benchmarkReverse(BenchmarkData data) { return reverse(data.getSlice()); } @Benchmark public Slice benchmarkToLowerCase(BenchmarkData data) { return toLowerCase(data.getSlice()); } @Benchmark public Slice benchmarkToUpperCase(BenchmarkData data) { return toUpperCase(data.getSlice()); } @Benchmark public Slice benchmarkLeftTrim(WhitespaceData data) { return leftTrim(data.getLeftWhitespace()); } @Benchmark public Slice benchmarkRightTrim(WhitespaceData data) { return rightTrim(data.getRightWhitespace()); } @Benchmark public Slice benchmarkTrim(WhitespaceData data) { return trim(data.getBothWhitespace()); } @State(Thread) public static class BenchmarkData { private static final int[] ASCII_CODE_POINTS; private static final int[] ALL_CODE_POINTS; static { ASCII_CODE_POINTS = IntStream.rangeClosed(0, 0x7F) .toArray(); ALL_CODE_POINTS = IntStream.rangeClosed(0, MAX_CODE_POINT) .filter(codePoint -> getType(codePoint) != SURROGATE) .toArray(); } @Param({ "2", "5", "10", "100", "1000", "10000" }) private int length; @Param({ "true", "false" }) private boolean ascii; private Slice slice; private int[] codePoints; @Setup public void setup() { int[] codePointSet = ascii ? ASCII_CODE_POINTS : ALL_CODE_POINTS; ThreadLocalRandom random = ThreadLocalRandom.current(); codePoints = new int[length]; DynamicSliceOutput sliceOutput = new DynamicSliceOutput(length * 4); for (int i = 0; i < codePoints.length; i++) { int codePoint = codePointSet[random.nextInt(codePointSet.length)]; codePoints[i] = codePoint; sliceOutput.appendBytes(new String(Character.toChars(codePoint)).getBytes(StandardCharsets.UTF_8)); } slice = sliceOutput.slice(); } public Slice getSlice() { return slice; } public int getLength() { return length; } } @State(Thread) public static class WhitespaceData { private static final int[] ASCII_WHITESPACE; private static final int[] ALL_WHITESPACE; static { ASCII_WHITESPACE = IntStream.rangeClosed(0, 0x7F) .filter(Character::isWhitespace) .toArray(); ALL_WHITESPACE = IntStream.rangeClosed(0, MAX_CODE_POINT) .filter(Character::isWhitespace) .toArray(); } @Param({ "2", "5", "10", "100", "1000", "10000" }) private int length; @Param({ "true", "false" }) private boolean ascii; private Slice leftWhitespace; private Slice rightWhitespace; private Slice bothWhitespace; @Setup public void setup() { Slice whitespace = createRandomUtf8Slice(ascii ? ASCII_WHITESPACE : ALL_WHITESPACE, length + 1); leftWhitespace = Slices.copyOf(whitespace); leftWhitespace.setByte(leftWhitespace.length() - 1, 'X'); rightWhitespace = Slices.copyOf(whitespace); rightWhitespace.setByte(0, 'X'); bothWhitespace = Slices.copyOf(whitespace); bothWhitespace.setByte(length / 2, 'X'); } private static Slice createRandomUtf8Slice(int[] codePointSet, int length) { int[] codePoints = new int[length]; ThreadLocalRandom random = ThreadLocalRandom.current(); for (int i = 0; i < codePoints.length; i++) { int codePoint = codePointSet[random.nextInt(codePointSet.length)]; codePoints[i] = codePoint; } return utf8Slice(new String(codePoints, 0, codePoints.length)); } public int getLength() { return length; } public Slice getLeftWhitespace() { return leftWhitespace; } public Slice getRightWhitespace() { return rightWhitespace; } public Slice getBothWhitespace() { return bothWhitespace; } } public static void main(String[] args) throws RunnerException { Options options = new OptionsBuilder() .verbosity(VerboseMode.NORMAL) .include(".*" + SliceUtf8Benchmark.class.getSimpleName() + ".*") .build(); new Runner(options).run(); } } slice-0.16/src/test/java/io/airlift/slice/TestBasicSliceInput.java000066400000000000000000000014251261474317300251240ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; public class TestBasicSliceInput extends AbstractSliceInputTest { @Override protected SliceInput createSliceInput(Slice slice) { return new BasicSliceInput(slice); } } slice-0.16/src/test/java/io/airlift/slice/TestByteArrays.java000066400000000000000000000072101261474317300241660ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import org.testng.annotations.Test; import java.nio.ByteOrder; import static java.lang.Double.longBitsToDouble; import static java.lang.Float.intBitsToFloat; import static org.testng.Assert.assertEquals; public class TestByteArrays { @Test public void testReading() { assertEquals(ByteOrder.nativeOrder(), ByteOrder.LITTLE_ENDIAN); byte[] bytes = new byte[10]; Slice slice = Slices.wrappedBuffer(bytes); slice.setInt(0, 0xDEADBEEF); slice.setInt(4, 0xCAFEBABE); // little endian memory layout: EF BE AD DE BE BA FE CA 00 00 assertEquals(slice.getBytes(), new byte[] { (byte) 0xEF, (byte) 0xBE, (byte) 0xAD, (byte) 0xDE, (byte) 0xBE, (byte) 0xBA, (byte) 0xFE, (byte) 0xCA, 0x00, 0x00}); assertEquals(ByteArrays.getShort(bytes, 0), (short) 0xBEEF); assertEquals(ByteArrays.getShort(bytes, 1), (short) 0xADBE); assertEquals(ByteArrays.getShort(bytes, 2), (short) 0xDEAD); assertEquals(ByteArrays.getShort(bytes, 3), (short) 0xBEDE); assertEquals(ByteArrays.getInt(bytes, 0), 0xDEADBEEF); assertEquals(ByteArrays.getInt(bytes, 1), 0xBEDEADBE); assertEquals(ByteArrays.getInt(bytes, 2), 0xBABEDEAD); assertEquals(ByteArrays.getInt(bytes, 3), 0xFEBABEDE); assertEquals(ByteArrays.getInt(bytes, 4), 0xCAFEBABE); assertEquals(ByteArrays.getLong(bytes, 0), 0xCAFEBABE_DEADBEEFL); assertEquals(ByteArrays.getLong(bytes, 1), 0x00CAFEBA_BEDEADBEL); assertEquals(ByteArrays.getLong(bytes, 2), 0x0000CAFE_BABEDEADL); assertEquals(ByteArrays.getFloat(bytes, 0), intBitsToFloat(0xDEADBEEF)); assertEquals(ByteArrays.getFloat(bytes, 1), intBitsToFloat(0xBEDEADBE)); assertEquals(ByteArrays.getFloat(bytes, 2), intBitsToFloat(0xBABEDEAD)); assertEquals(ByteArrays.getFloat(bytes, 3), intBitsToFloat(0xFEBABEDE)); assertEquals(ByteArrays.getFloat(bytes, 4), intBitsToFloat(0xCAFEBABE)); assertEquals(ByteArrays.getDouble(bytes, 0), longBitsToDouble(0xCAFEBABE_DEADBEEFL)); assertEquals(ByteArrays.getDouble(bytes, 1), longBitsToDouble(0x00CAFEBA_BEDEADBEL)); assertEquals(ByteArrays.getDouble(bytes, 2), longBitsToDouble(0x0000CAFE_BABEDEADL)); } @Test(expectedExceptions = IndexOutOfBoundsException.class) public void testReadingShortBounds() { ByteArrays.getShort(new byte[3], 2); } @Test(expectedExceptions = IndexOutOfBoundsException.class) public void testReadingIntBounds() { ByteArrays.getInt(new byte[5], 2); } @Test(expectedExceptions = IndexOutOfBoundsException.class) public void testReadingLongBounds() { ByteArrays.getLong(new byte[9], 2); } @Test(expectedExceptions = IndexOutOfBoundsException.class) public void testReadingFloatBounds() { ByteArrays.getFloat(new byte[5], 2); } @Test(expectedExceptions = IndexOutOfBoundsException.class) public void testReadingDoubleBounds() { ByteArrays.getDouble(new byte[9], 2); } } slice-0.16/src/test/java/io/airlift/slice/TestChunkedSliceInput.java000066400000000000000000000037741261474317300254750ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import io.airlift.slice.ChunkedSliceInput.BufferReference; import io.airlift.slice.ChunkedSliceInput.SliceLoader; import static com.google.common.base.Preconditions.checkPositionIndex; public class TestChunkedSliceInput extends AbstractSliceInputTest { @Override protected SliceInput createSliceInput(Slice slice) { return new ChunkedSliceInput(new SliceSliceLoader(slice), BUFFER_SIZE); } private static class SliceSliceLoader implements SliceLoader { private final Slice data; public SliceSliceLoader(Slice data) { this.data = data; } @Override public BufferReference createBuffer(int bufferSize) { final Slice slice = Slices.allocate(bufferSize); return new BufferReference() { @Override public Slice getSlice() { return slice; } }; } @Override public long getSize() { return data.length(); } @Override public void load(long position, BufferReference buffer, int length) { checkPositionIndex((int) (position + length), (int) getSize()); this.data.getBytes((int) position, buffer.getSlice(), 0, length); } @Override public void close() { } } } slice-0.16/src/test/java/io/airlift/slice/TestDirectSlice.java000066400000000000000000000013651261474317300243000ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; public class TestDirectSlice extends TestSlice { @Override protected Slice allocate(int size) { return Slices.allocateDirect(size); } } slice-0.16/src/test/java/io/airlift/slice/TestInputStreamSliceInput.java000066400000000000000000000017201261474317300263540ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import java.io.ByteArrayInputStream; public class TestInputStreamSliceInput extends AbstractSliceInputTest { @Override protected SliceInput createSliceInput(Slice slice) { return new InputStreamSliceInput(new ByteArrayInputStream(slice.getBytes())); } @Override protected void testReadReverse(SliceInputTester tester, Slice slice) { } } slice-0.16/src/test/java/io/airlift/slice/TestMurmur3Hash128.java000066400000000000000000000132201261474317300245100ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import com.google.common.hash.HashCode; import com.google.common.hash.Hashing; import org.testng.annotations.Test; import java.util.concurrent.ThreadLocalRandom; import static org.testng.Assert.assertEquals; public class TestMurmur3Hash128 { @Test(invocationCount = 100) public void testLessThan16Bytes() throws Exception { byte[] data = randomBytes(ThreadLocalRandom.current().nextInt(16)); HashCode expected = Hashing.murmur3_128().hashBytes(data); Slice actual = Murmur3Hash128.hash(Slices.wrappedBuffer(data)); assertEquals(actual.getBytes(), expected.asBytes()); } @Test(invocationCount = 100) public void testMoreThan16Bytes() throws Exception { byte[] data = randomBytes(131); HashCode expected = Hashing.murmur3_128().hashBytes(data); Slice actual = Murmur3Hash128.hash(Slices.wrappedBuffer(data)); assertEquals(actual.getBytes(), expected.asBytes()); } @Test(invocationCount = 100) public void testOffsetAndLength() throws Exception { byte[] data = randomBytes(131); int offset = 13; int length = 55; HashCode expected = Hashing.murmur3_128().hashBytes(data, offset, length); Slice actual = Murmur3Hash128.hash(Slices.wrappedBuffer(data), offset, length); assertEquals(actual.getBytes(), expected.asBytes()); } @Test(invocationCount = 100) public void testNonDefaultSeed() throws Exception { byte[] data = randomBytes(131); int seed = 123456789; HashCode expected = Hashing.murmur3_128(seed).hashBytes(data); Slice actual = Murmur3Hash128.hash(seed, Slices.wrappedBuffer(data), 0, data.length); assertEquals(actual.getBytes(), expected.asBytes()); } @Test public void testTail() throws Exception { for (int i = 0; i < 16; i++) { byte[] data = randomBytes(50 + i); HashCode expected = Hashing.murmur3_128().hashBytes(data); Slice actual = Murmur3Hash128.hash(Slices.wrappedBuffer(data)); assertEquals(actual.getBytes(), expected.asBytes()); } } @Test(invocationCount = 100) public void testLessThan16Bytes64() throws Exception { byte[] data = randomBytes(ThreadLocalRandom.current().nextInt(16)); long expected = Murmur3Hash128.hash(Slices.wrappedBuffer(data)).getLong(0); long actual = Murmur3Hash128.hash64(Slices.wrappedBuffer(data)); assertEquals(actual, expected); } @Test(invocationCount = 100) public void testMoreThan16Bytes64() throws Exception { byte[] data = randomBytes(131); long expected = Murmur3Hash128.hash(Slices.wrappedBuffer(data)).getLong(0); long actual = Murmur3Hash128.hash64(Slices.wrappedBuffer(data)); assertEquals(actual, expected); } @Test(invocationCount = 100) public void testOffsetAndLength64() throws Exception { byte[] data = randomBytes(131); int offset = 13; int length = 55; long expected = Murmur3Hash128.hash(Slices.wrappedBuffer(data), offset, length).getLong(0); long actual = Murmur3Hash128.hash64(Slices.wrappedBuffer(data), offset, length); assertEquals(actual, expected); } @Test(invocationCount = 100) public void testNonDefaultSeed64() throws Exception { byte[] data = randomBytes(131); int seed = 123456789; long expected = Murmur3Hash128.hash(seed, Slices.wrappedBuffer(data), 0, data.length).getLong(0); long actual = Murmur3Hash128.hash64(seed, Slices.wrappedBuffer(data), 0, data.length); assertEquals(actual, expected); } @Test public void testTail64() throws Exception { for (int i = 0; i < 16; i++) { byte[] data = randomBytes(50 + i); long expected = Murmur3Hash128.hash(Slices.wrappedBuffer(data)).getLong(0); long actual = Murmur3Hash128.hash64(Slices.wrappedBuffer(data)); assertEquals(actual, expected); } } @Test(invocationCount = 100) public void test64ReturnsMsb() throws Exception { byte[] data = randomBytes(ThreadLocalRandom.current().nextInt(200)); long expected = Murmur3Hash128.hash(Slices.wrappedBuffer(data)).getLong(0); long actual = Murmur3Hash128.hash64(Slices.wrappedBuffer(data)); assertEquals(actual, expected); } @Test(invocationCount = 100) public void testSingleLong() throws Exception { long value = ThreadLocalRandom.current().nextLong(); Slice slice = Slices.allocate(8); slice.setLong(0, value); long expected = Murmur3Hash128.hash64(slice); long actual = Murmur3Hash128.hash64(value); assertEquals(actual, expected); } private static byte[] randomBytes(int length) { byte[] result = new byte[length]; ThreadLocalRandom.current().nextBytes(result); return result; } } slice-0.16/src/test/java/io/airlift/slice/TestMurmur3Hash32.java000066400000000000000000000070311261474317300244250ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import com.google.common.hash.Hashing; import org.testng.annotations.Test; import java.util.concurrent.ThreadLocalRandom; import static org.testng.Assert.assertEquals; public class TestMurmur3Hash32 { @Test(invocationCount = 100) public void testLessThan4Bytes() throws Exception { byte[] data = randomBytes(ThreadLocalRandom.current().nextInt(4)); int expected = Hashing.murmur3_32().hashBytes(data).asInt(); int actual = Murmur3Hash32.hash(Slices.wrappedBuffer(data)); assertEquals(actual, expected); } @Test(invocationCount = 100) public void testMoreThan4Bytes() throws Exception { byte[] data = randomBytes(131); int expected = Hashing.murmur3_32().hashBytes(data).asInt(); int actual = Murmur3Hash32.hash(Slices.wrappedBuffer(data)); assertEquals(actual, expected); } @Test(invocationCount = 100) public void testOffsetAndLength() throws Exception { byte[] data = randomBytes(131); int offset = 13; int length = 55; int expected = Hashing.murmur3_32().hashBytes(data, offset, length).asInt(); int actual = Murmur3Hash32.hash(Slices.wrappedBuffer(data), offset, length); assertEquals(actual, expected); } @Test(invocationCount = 100) public void testNonDefaultSeed() throws Exception { byte[] data = randomBytes(131); int seed = 123456789; int expected = Hashing.murmur3_32(seed).hashBytes(data).asInt(); int actual = Murmur3Hash32.hash(seed, Slices.wrappedBuffer(data), 0, data.length); assertEquals(actual, expected); } @Test public void testTail() throws Exception { for (int i = 0; i < 4; i++) { byte[] data = randomBytes(50 + i); int expected = Hashing.murmur3_32().hashBytes(data).asInt(); int actual = Murmur3Hash32.hash(Slices.wrappedBuffer(data)); assertEquals(actual, expected); } } @Test(invocationCount = 100) public void testSingleInt() throws Exception { int value = ThreadLocalRandom.current().nextInt(); Slice slice = Slices.allocate(4); slice.setInt(0, value); int expected = Murmur3Hash32.hash(slice); int actual = Murmur3Hash32.hash(value); assertEquals(actual, expected); } @Test(invocationCount = 100) public void testSingleLong() throws Exception { long value = ThreadLocalRandom.current().nextLong(); Slice slice = Slices.allocate(8); slice.setLong(0, value); int expected = Murmur3Hash32.hash(slice); int actual = Murmur3Hash32.hash(value); assertEquals(actual, expected); } private static byte[] randomBytes(int length) { byte[] result = new byte[length]; ThreadLocalRandom.current().nextBytes(result); return result; } } slice-0.16/src/test/java/io/airlift/slice/TestSlice.java000066400000000000000000000623341261474317300231500ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import org.testng.annotations.Test; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Random; import static io.airlift.slice.SizeOf.SIZE_OF_BYTE; import static io.airlift.slice.SizeOf.SIZE_OF_DOUBLE; import static io.airlift.slice.SizeOf.SIZE_OF_FLOAT; import static io.airlift.slice.SizeOf.SIZE_OF_INT; import static io.airlift.slice.SizeOf.SIZE_OF_LONG; import static io.airlift.slice.SizeOf.SIZE_OF_SHORT; import static io.airlift.slice.Slices.EMPTY_SLICE; import static io.airlift.slice.Slices.utf8Slice; import static java.lang.Double.doubleToLongBits; import static java.lang.Double.longBitsToDouble; import static java.lang.Float.floatToIntBits; import static java.lang.Float.intBitsToFloat; import static java.nio.charset.StandardCharsets.UTF_8; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertNotEquals; import static org.testng.Assert.assertSame; import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; public class TestSlice { @Test public void testFillAndClear() { for (byte size = 0; size < 100; size++) { Slice slice = allocate(size); for (int i = 0; i < slice.length(); i++) { assertEquals(slice.getByte(i), (byte) 0); } slice.fill((byte) 0xA5); for (int i = 0; i < slice.length(); i++) { assertEquals(slice.getByte(i), (byte) 0xA5); } slice.clear(); for (int i = 0; i < slice.length(); i++) { assertEquals(slice.getByte(i), (byte) 0); } } } @Test public void testEqualsHashCodeCompare() { for (int size = 0; size < 100; size++) { // self equals Slice slice = allocate(size); assertSlicesEquals(slice, slice); // equals other all zero Slice other = allocate(size); assertSlicesEquals(slice, other); // equals self fill pattern slice = allocate(size); // create a new slice since slices cache the hash code value slice.fill((byte) 0xA5); assertSlicesEquals(slice, slice); // equals other fill pattern other = allocate(size); // create a new slice since slices cache the hash code value other.fill((byte) 0xA5); assertSlicesEquals(slice, other); // different types assertNotEquals(slice, new Object()); //noinspection MisorderedAssertEqualsArgumentsTestNG assertNotEquals(new Object(), slice); // different sizes Slice oneBigger = allocate(size + 1); oneBigger.fill((byte) 0xA5); assertNotEquals(slice, oneBigger); assertNotEquals(oneBigger, slice); assertTrue(slice.compareTo(oneBigger) < 0); assertTrue(oneBigger.compareTo(slice) > 0); assertFalse(slice.equals(0, size, oneBigger, 0, size + 1)); assertFalse(oneBigger.equals(0, size + 1, slice, 0, size)); assertTrue(slice.compareTo(0, size, oneBigger, 0, size + 1) < 0); assertTrue(oneBigger.compareTo(0, size + 1, slice, 0, size) > 0); // different in one byte for (int i = 1; i < slice.length(); i++) { slice.setByte(i - 1, 0xA5); assertTrue(slice.equals(i - 1, size - i, other, i - 1, size - i)); slice.setByte(i, 0xFF); assertNotEquals(slice, other); assertFalse(slice.equals(i, size - i, other, i, size - i)); assertTrue(slice.compareTo(0, size, oneBigger, 0, size + 1) > 0); } // compare with empty slice if (slice.length() > 0) { assertNotEquals(slice, EMPTY_SLICE); //noinspection MisorderedAssertEqualsArgumentsTestNG assertNotEquals(EMPTY_SLICE, slice); assertFalse(slice.equals(0, size, EMPTY_SLICE, 0, 0)); assertFalse(EMPTY_SLICE.equals(0, 0, slice, 0, size)); assertTrue(slice.compareTo(0, size, EMPTY_SLICE, 0, 0) > 0); assertTrue(EMPTY_SLICE.compareTo(0, 0, slice, 0, size) < 0); try { //noinspection ResultOfMethodCallIgnored slice.equals(0, size, EMPTY_SLICE, 0, size); fail("expected IndexOutOfBoundsException"); } catch (IndexOutOfBoundsException expected) { } try { //noinspection ResultOfMethodCallIgnored EMPTY_SLICE.equals(0, size, slice, 0, size); fail("expected IndexOutOfBoundsException"); } catch (IndexOutOfBoundsException expected) { } try { slice.compareTo(0, size, EMPTY_SLICE, 0, size); fail("expected IndexOutOfBoundsException"); } catch (IndexOutOfBoundsException expected) { } try { EMPTY_SLICE.compareTo(0, size, slice, 0, size); fail("expected IndexOutOfBoundsException"); } catch (IndexOutOfBoundsException expected) { } } } } private static void assertSlicesEquals(Slice slice, Slice other) { int size = slice.length(); assertEquals(slice, other); assertTrue(slice.equals(0, size, other, 0, size)); assertEquals(slice.hashCode(), other.hashCode()); assertEquals(slice.hashCode(), other.hashCode(0, size)); assertEquals(slice.compareTo(other), 0); assertEquals(slice.compareTo(0, size, other, 0, size), 0); for (int i = 0; i < slice.length(); i++) { assertTrue(slice.equals(i, size - i, other, i, size - i)); assertEquals(slice.hashCode(i, size - i), other.hashCode(i, size - i)); assertEquals(slice.compareTo(i, size - i, other, i, size - i), 0); } for (int i = 0; i < slice.length(); i++) { assertTrue(slice.equals(0, size - i, other, 0, size - i)); assertEquals(slice.hashCode(0, size - i), other.hashCode(0, size - i)); assertEquals(slice.compareTo(0, size - i, other, 0, size - i), 0); } } @Test public void testToString() { assertEquals(Slices.copiedBuffer("apple", UTF_8).toString(UTF_8), "apple"); for (int size = 0; size < 100; size++) { for (int index = 0; index < size; index++) { assertToStrings(allocate(size), index); } } } @Test public void testUtf8Conversion() { String s = "apple \u2603 snowman"; Slice slice = Slices.copiedBuffer(s, UTF_8); assertEquals(utf8Slice(s), slice); assertEquals(slice.toStringUtf8(), s); assertEquals(utf8Slice(s).toStringUtf8(), s); } @SuppressWarnings("CharUsedInArithmeticContext") private static void assertToStrings(Slice slice, int index) { // fill slice with FF slice.fill((byte) 0xFF); // set and get the value char[] chars = new char[(slice.length() - index) / 2]; for (int i = 0; i < chars.length; i++) { chars[i] = (char) ('a' + (i % 26)); } String string = new String(chars); Slice value = Slices.copiedBuffer(string, UTF_8); slice.setBytes(index, value); assertEquals(slice.toString(index, value.length(), UTF_8), string); for (int length = 0; length < value.length(); length++) { slice.fill((byte) 0xFF); slice.setBytes(index, value, 0, length); assertEquals(slice.toString(index, length, UTF_8), string.substring(0, length)); } } @Test public void testByte() { for (byte size = 0; size < 100; size++) { for (byte index = 0; index < (size - SIZE_OF_BYTE); index++) { assertByte(allocate(size), index); } } } private static void assertByte(Slice slice, byte index) { // fill slice with FF slice.fill((byte) 0xFF); // set and get unsigned value slice.setByte(index, 0xA5); assertEquals(slice.getUnsignedByte(index), 0x0000_00A5); // set and get the value slice.setByte(index, 0xA5); assertEquals(slice.getByte(index), (byte) 0xA5); try { slice.getByte(-1); fail("expected IndexOutOfBoundsException"); } catch (IndexOutOfBoundsException e) { } try { slice.getByte((slice.length() - SIZE_OF_BYTE) + 1); fail("expected IndexOutOfBoundsException"); } catch (IndexOutOfBoundsException e) { } try { slice.getByte(slice.length()); fail("expected IndexOutOfBoundsException"); } catch (IndexOutOfBoundsException e) { } try { slice.getByte(slice.length() + 1); fail("expected IndexOutOfBoundsException"); } catch (IndexOutOfBoundsException e) { } } @Test public void testShort() { for (short size = 0; size < 100; size++) { for (short index = 0; index < (size - SIZE_OF_SHORT); index++) { assertShort(allocate(size), index); } } } private static void assertShort(Slice slice, short index) { // fill slice with FF slice.fill((byte) 0xFF); // set and get the value slice.setShort(index, 0xAA55); assertEquals(slice.getShort(index), (short) 0xAA55); try { slice.getShort(-1); fail("expected IndexOutOfBoundsException"); } catch (IndexOutOfBoundsException e) { } try { slice.getShort((slice.length() - SIZE_OF_SHORT) + 1); fail("expected IndexOutOfBoundsException"); } catch (IndexOutOfBoundsException e) { } try { slice.getShort(slice.length()); fail("expected IndexOutOfBoundsException"); } catch (IndexOutOfBoundsException e) { } try { slice.getShort(slice.length() + 1); fail("expected IndexOutOfBoundsException"); } catch (IndexOutOfBoundsException e) { } } @Test public void testInt() { for (int size = 0; size < 100; size++) { for (int index = 0; index < (size - SIZE_OF_INT); index++) { assertInt(allocate(size), index); } } } private static void assertInt(Slice slice, int index) { // fill slice with FF slice.fill((byte) 0xFF); // set and get the value slice.setInt(index, 0xAAAA_5555); assertEquals(slice.getInt(index), 0xAAAA_5555); try { slice.getInt(-1); fail("expected IndexOutOfBoundsException"); } catch (IndexOutOfBoundsException e) { } try { slice.getInt((slice.length() - SIZE_OF_INT) + 1); fail("expected IndexOutOfBoundsException"); } catch (IndexOutOfBoundsException e) { } try { slice.getInt(slice.length()); fail("expected IndexOutOfBoundsException"); } catch (IndexOutOfBoundsException e) { } try { slice.getInt(slice.length() + 1); fail("expected IndexOutOfBoundsException"); } catch (IndexOutOfBoundsException e) { } } @Test public void testLong() { for (int size = 0; size < 100; size++) { for (int index = 0; index < (size - SIZE_OF_LONG); index++) { assertLong(allocate(size), index); } } } private static void assertLong(Slice slice, int index) { // fill slice with FF slice.fill((byte) 0xFF); // set and get the value slice.setLong(index, 0xAAAA_AAAA_5555_5555L); assertEquals(slice.getLong(index), 0xAAAA_AAAA_5555_5555L); try { slice.getLong(-1); fail("expected IndexOutOfBoundsException"); } catch (IndexOutOfBoundsException e) { } try { slice.getLong((slice.length() - SIZE_OF_LONG) + 1); fail("expected IndexOutOfBoundsException"); } catch (IndexOutOfBoundsException e) { } try { slice.getLong(slice.length()); fail("expected IndexOutOfBoundsException"); } catch (IndexOutOfBoundsException e) { } try { slice.getLong(slice.length() + 1); fail("expected IndexOutOfBoundsException"); } catch (IndexOutOfBoundsException e) { } } @Test public void testFloat() { for (int size = 0; size < 100; size++) { for (int index = 0; index < (size - SIZE_OF_FLOAT); index++) { assertFloat(allocate(size), index); } } } private static void assertFloat(Slice slice, int index) { // fill slice with FF slice.fill((byte) 0xFF); // set and get the value slice.setFloat(index, intBitsToFloat(0xAAAA_5555)); assertEquals(floatToIntBits(slice.getFloat(index)), 0xAAAA_5555); try { slice.getFloat(-1); fail("expected IndexOutOfBoundsException"); } catch (IndexOutOfBoundsException e) { } try { slice.getFloat((slice.length() - SIZE_OF_FLOAT) + 1); fail("expected IndexOutOfBoundsException"); } catch (IndexOutOfBoundsException e) { } try { slice.getFloat(slice.length()); fail("expected IndexOutOfBoundsException"); } catch (IndexOutOfBoundsException e) { } try { slice.getFloat(slice.length() + 1); fail("expected IndexOutOfBoundsException"); } catch (IndexOutOfBoundsException e) { } } @Test public void testDouble() { for (int size = 0; size < 100; size++) { for (int index = 0; index < (size - SIZE_OF_DOUBLE); index++) { assertDouble(allocate(size), index); } } } private static void assertDouble(Slice slice, int index) { // fill slice with FF slice.fill((byte) 0xFF); // set and get the value slice.setDouble(index, longBitsToDouble(0xAAAA_AAAA_5555_5555L)); assertEquals(doubleToLongBits(slice.getDouble(index)), 0xAAAA_AAAA_5555_5555L); try { slice.getDouble(-1); fail("expected IndexOutOfBoundsException"); } catch (IndexOutOfBoundsException e) { } try { slice.getDouble((slice.length() - SIZE_OF_DOUBLE) + 1); fail("expected IndexOutOfBoundsException"); } catch (IndexOutOfBoundsException e) { } try { slice.getDouble(slice.length()); fail("expected IndexOutOfBoundsException"); } catch (IndexOutOfBoundsException e) { } try { slice.getDouble(slice.length() + 1); fail("expected IndexOutOfBoundsException"); } catch (IndexOutOfBoundsException e) { } } @Test public void testBytesArray() { for (int size = 0; size < 100; size++) { for (int index = 0; index < size; index++) { assertBytesArray(allocate(size), index); } } } private static void assertBytesArray(Slice slice, int index) { // fill slice with FF slice.fill((byte) 0xFF); byte[] value = new byte[slice.length()]; Arrays.fill(value, (byte) 0xFF); assertEquals(slice.getBytes(), value); // set and get the value value = new byte[(slice.length() - index) / 2]; for (int i = 0; i < value.length; i++) { value[i] = (byte) i; } slice.setBytes(index, value); assertEquals(slice.getBytes(index, value.length), value); for (int length = 0; length < value.length; length++) { slice.fill((byte) 0xFF); slice.setBytes(index, value, 0, length); assertEquals(slice.getBytes(index, length), Arrays.copyOf(value, length)); } } @Test public void testBytesSlice() { for (int size = 0; size < 100; size++) { for (int index = 0; index < size; index++) { assertBytesSlice(allocate(size), index); } } } private void assertBytesSlice(Slice slice, int index) { // fill slice with FF slice.fill((byte) 0xFF); // compare to self slice assertEquals(slice.slice(0, slice.length()), slice); Slice value = allocate(slice.length()); slice.getBytes(0, value, 0, slice.length()); assertEquals(value, slice); // set and get the value value = allocate((slice.length() - index) / 2); for (int i = 0; i < value.length(); i++) { value.setByte(i, i); } // check by slicing out the region slice.setBytes(index, value); assertEquals(value, slice.slice(index, value.length())); // check by getting out the region Slice tempValue = allocate(value.length()); slice.getBytes(index, tempValue, 0, tempValue.length()); assertEquals(tempValue, slice.slice(index, tempValue.length())); assertTrue(tempValue.equals(0, tempValue.length(), slice, index, tempValue.length())); for (int length = 0; length < value.length(); length++) { slice.fill((byte) 0xFF); slice.setBytes(index, value, 0, length); // check by slicing out the region assertEquals(value.slice(0, length), slice.slice(index, length)); assertTrue(value.equals(0, length, slice, index, length)); // check by getting out the region tempValue = allocate(length); slice.getBytes(index, tempValue); assertEquals(tempValue, slice.slice(index, length)); assertTrue(tempValue.equals(0, length, slice, index, length)); } } @Test public void testBytesStreams() throws Exception { for (int size = 0; size < 100; size++) { for (int index = 0; index < size; index++) { assertBytesStreams(allocate(size), index); } } assertBytesStreams(allocate(16 * 1024), 3); } private static void assertBytesStreams(Slice slice, int index) throws Exception { // fill slice with FF slice.fill((byte) 0xFF); byte[] value = new byte[slice.length()]; Arrays.fill(value, (byte) 0xFF); assertEquals(slice.getBytes(), value); // set and get the value value = new byte[(slice.length() - index) / 2]; for (int i = 0; i < value.length; i++) { value[i] = (byte) i; } slice.setBytes(index, new ByteArrayInputStream(value), value.length); assertEquals(slice.getBytes(index, value.length), value); ByteArrayOutputStream out = new ByteArrayOutputStream(); slice.getBytes(index, out, value.length); assertEquals(slice.getBytes(index, value.length), out.toByteArray()); for (int length = 0; length < value.length; length++) { slice.fill((byte) 0xFF); slice.setBytes(index, new ByteArrayInputStream(value), length); assertEquals(slice.getBytes(index, length), Arrays.copyOf(value, length)); out = new ByteArrayOutputStream(); slice.getBytes(index, out, length); assertEquals(slice.getBytes(index, length), out.toByteArray()); } } @Test public void testMemoryMappedReads() throws IOException { Path path = Files.createTempFile("longs", null); List values = createRandomLongs(20000); Slice output = allocate(values.size() * (int) SIZE_OF_LONG); for (int i = 0; i < values.size(); i++) { output.setLong(i * SIZE_OF_LONG, values.get(i)); } Files.write(path, output.getBytes()); Slice slice = Slices.mapFileReadOnly(path.toFile()); for (int i = 0; i < values.size(); i++) { long actual = slice.getLong(i * SIZE_OF_LONG); long expected = values.get(i); assertEquals(actual, expected); } assertEquals(slice.getBytes(), output.getBytes()); } @Test public void testRetainedSize() throws Exception { Slice slice = Slices.allocate(10); assertEquals(slice.getRetainedSize(), 10); assertEquals(slice.length(), 10); Slice subSlice = slice.slice(0, 1); assertEquals(subSlice.getRetainedSize(), 10); assertEquals(subSlice.length(), 1); } @Test public void testCopyOf() throws Exception { // slightly stronger guarantees for empty slice assertSame(Slices.copyOf(EMPTY_SLICE), EMPTY_SLICE); assertSame(Slices.copyOf(utf8Slice("hello world"), 1, 0), EMPTY_SLICE); Slice slice = utf8Slice("hello world"); assertEquals(Slices.copyOf(slice), slice); assertEquals(Slices.copyOf(slice, 1, 3), slice.slice(1, 3)); // verify it's an actual copy Slice original = utf8Slice("hello world"); Slice copy = Slices.copyOf(original); original.fill((byte) 0); assertEquals(copy, utf8Slice("hello world")); // read before beginning try { Slices.copyOf(slice, -1, slice.length()); fail(); } catch (IndexOutOfBoundsException ignored) { } // read after end try { Slices.copyOf(slice, slice.length() + 1, 1); fail(); } catch (IndexOutOfBoundsException ignored) { } // start before but extend past end try { Slices.copyOf(slice, 1, slice.length()); fail(); } catch (IndexOutOfBoundsException ignored) { } } @Test public void testIndexOf() throws Exception { assertIndexOf(utf8Slice("no-match-bigger"), utf8Slice("test")); assertIndexOf(utf8Slice("no"), utf8Slice("test")); assertIndexOf(utf8Slice("test"), utf8Slice("test")); assertIndexOf(utf8Slice("test-start"), utf8Slice("test")); assertIndexOf(utf8Slice("end-test"), utf8Slice("test")); assertIndexOf(utf8Slice("a-test-middle"), utf8Slice("test")); assertIndexOf(utf8Slice("this-test-is-a-test"), utf8Slice("test")); assertIndexOf(utf8Slice("test"), EMPTY_SLICE, 0, 0); assertIndexOf(EMPTY_SLICE, utf8Slice("test"), 0, -1); assertIndexOf(utf8Slice("test"), utf8Slice("no"), 4, -1); assertIndexOf(utf8Slice("test"), utf8Slice("no"), 5, -1); assertIndexOf(utf8Slice("test"), utf8Slice("no"), -1, -1); } public static void assertIndexOf(Slice data, Slice pattern, int offset, int expected) { assertEquals(data.indexOf(pattern, offset), expected); assertEquals(data.indexOfBruteForce(pattern, offset), expected); } public static void assertIndexOf(Slice data, Slice pattern) { int index; List bruteForce = new ArrayList<>(); index = 0; while (index >= 0 && index < data.length()) { index = data.indexOfBruteForce(pattern, index); if (index >= 0) { bruteForce.add(index); index++; } } List indexOf = new ArrayList<>(); index = 0; while (index >= 0 && index < data.length()) { index = data.indexOf(pattern, index); if (index >= 0) { indexOf.add(index); index++; } } assertEquals(bruteForce, indexOf); } private static List createRandomLongs(int count) { Random random = new Random(); List list = new ArrayList<>(count); for (int i = 0; i < count; i++) { list.add(random.nextLong()); } return Collections.unmodifiableList(list); } protected Slice allocate(int size) { return Slices.allocate(size); } } slice-0.16/src/test/java/io/airlift/slice/TestSliceOutput.java000066400000000000000000000044021261474317300243610ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; public class TestSliceOutput { @Test public void testAppendByte() throws Exception { for (int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) { Slice actual = new DynamicSliceOutput(1) .appendByte(i) .slice(); Slice expected = Slices.wrappedBuffer(new byte[] {(byte) i}); assertEquals(actual, expected); } } @Test public void testAppendUnsignedByte() throws Exception { for (int i = 0; i < 256; i++) { Slice actual = new DynamicSliceOutput(1) .appendByte(i) .slice(); Slice expected = Slices.wrappedBuffer(new byte[] {(byte) i}); assertEquals(actual, expected); } } @Test public void testAppendByteTruncation() throws Exception { for (int i = 256; i < 512; i++) { Slice actual = new DynamicSliceOutput(1) .appendByte(i) .slice(); Slice expected = Slices.wrappedBuffer(new byte[] {(byte) i}); assertEquals(actual, expected); } } @Test public void testAppendMultiple() throws Exception { Slice actual = new DynamicSliceOutput(1) .appendByte(0) .appendByte(1) .appendByte(2) .appendByte(3) .appendByte(4) .slice(); Slice expected = Slices.wrappedBuffer(new byte[] { 0, 1, 2, 3, 4 }); assertEquals(actual, expected); } } slice-0.16/src/test/java/io/airlift/slice/TestSliceUtf8.java000066400000000000000000001056701261474317300237200ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import com.google.common.primitives.Ints; import org.testng.annotations.Test; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.stream.IntStream; import static com.google.common.primitives.Bytes.concat; import static io.airlift.slice.SliceUtf8.codePointToUtf8; import static io.airlift.slice.SliceUtf8.countCodePoints; import static io.airlift.slice.SliceUtf8.fixInvalidUtf8; import static io.airlift.slice.SliceUtf8.getCodePointAt; import static io.airlift.slice.SliceUtf8.getCodePointBefore; import static io.airlift.slice.SliceUtf8.isAscii; import static io.airlift.slice.SliceUtf8.leftTrim; import static io.airlift.slice.SliceUtf8.lengthOfCodePoint; import static io.airlift.slice.SliceUtf8.lengthOfCodePointFromStartByte; import static io.airlift.slice.SliceUtf8.lengthOfCodePointSafe; import static io.airlift.slice.SliceUtf8.offsetOfCodePoint; import static io.airlift.slice.SliceUtf8.reverse; import static io.airlift.slice.SliceUtf8.rightTrim; import static io.airlift.slice.SliceUtf8.setCodePointAt; import static io.airlift.slice.SliceUtf8.substring; import static io.airlift.slice.SliceUtf8.toLowerCase; import static io.airlift.slice.SliceUtf8.toUpperCase; import static io.airlift.slice.SliceUtf8.trim; import static io.airlift.slice.Slices.EMPTY_SLICE; import static io.airlift.slice.Slices.utf8Slice; import static io.airlift.slice.Slices.wrappedBuffer; import static java.lang.Character.MAX_CODE_POINT; import static java.lang.Character.MIN_SURROGATE; import static java.lang.Character.SURROGATE; import static java.lang.Character.getType; import static java.nio.charset.StandardCharsets.UTF_8; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertTrue; public class TestSliceUtf8 { private static final int[] ASCII_CODE_POINTS; private static final String STRING_ASCII_CODE_POINTS; private static final int[] ALL_CODE_POINTS; private static final String STRING_ALL_CODE_POINTS; private static final int[] ALL_CODE_POINTS_RANDOM; private static final String STRING_ALL_CODE_POINTS_RANDOM; private static final byte START_1_BYTE = (byte) 0b0111_1111; private static final byte CONTINUATION_BYTE = (byte) 0b1011_1111; private static final byte START_2_BYTE = (byte) 0b1101_1111; private static final byte START_3_BYTE = (byte) 0b1110_1111; private static final byte START_4_BYTE = (byte) 0b1111_0111; private static final byte START_5_BYTE = (byte) 0b1111_1011; private static final byte START_6_BYTE = (byte) 0b1111_1101; private static final byte INVALID_FE_BYTE = (byte) 0b11111110; private static final byte INVALID_FF_BYTE = (byte) 0b11111111; private static final byte X_CHAR = (byte) 'X'; private static final List INVALID_SEQUENCES; static { ASCII_CODE_POINTS = IntStream.rangeClosed(0, 0x7F) .toArray(); STRING_ASCII_CODE_POINTS = new String(ASCII_CODE_POINTS, 0, ASCII_CODE_POINTS.length); ALL_CODE_POINTS = IntStream.rangeClosed(0, MAX_CODE_POINT) .filter(codePoint -> getType(codePoint) != SURROGATE) .toArray(); STRING_ALL_CODE_POINTS = new String(ALL_CODE_POINTS, 0, ALL_CODE_POINTS.length); ALL_CODE_POINTS_RANDOM = Arrays.copyOf(ALL_CODE_POINTS, ALL_CODE_POINTS.length); Collections.shuffle(Arrays.asList(ALL_CODE_POINTS_RANDOM)); STRING_ALL_CODE_POINTS_RANDOM = new String(ALL_CODE_POINTS_RANDOM, 0, ALL_CODE_POINTS_RANDOM.length); ImmutableList.Builder invalidSequences = ImmutableList.builder(); invalidSequences.add(new byte[] {CONTINUATION_BYTE}); invalidSequences.add(new byte[] {START_2_BYTE}); invalidSequences.add(new byte[] {START_3_BYTE}); invalidSequences.add(new byte[] {START_3_BYTE, CONTINUATION_BYTE}); invalidSequences.add(new byte[] {START_4_BYTE}); invalidSequences.add(new byte[] {START_4_BYTE, CONTINUATION_BYTE}); invalidSequences.add(new byte[] {START_4_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE}); // 4 byte sequence is limited to 10FFFF invalidSequences.add(new byte[] {START_4_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE}); invalidSequences.add(new byte[] {START_5_BYTE}); invalidSequences.add(new byte[] {START_5_BYTE, CONTINUATION_BYTE}); invalidSequences.add(new byte[] {START_5_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE}); invalidSequences.add(new byte[] {START_5_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE}); invalidSequences.add(new byte[] {START_5_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE}); invalidSequences.add(new byte[] {START_6_BYTE}); invalidSequences.add(new byte[] {START_6_BYTE, CONTINUATION_BYTE}); invalidSequences.add(new byte[] {START_6_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE}); invalidSequences.add(new byte[] {START_6_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE}); invalidSequences.add(new byte[] {START_6_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE}); invalidSequences.add(new byte[] {START_6_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE}); invalidSequences.add(new byte[] {INVALID_FF_BYTE}); // min and max surrogate characters invalidSequences.add(new byte[] {(byte) 0b11101101, (byte) 0xA0, (byte) 0x80}); invalidSequences.add(new byte[] {(byte) 0b11101101, (byte) 0xBF, (byte) 0xBF}); INVALID_SEQUENCES = invalidSequences.build(); } private static final String STRING_EMPTY = ""; private static final String STRING_HELLO = "hello"; private static final String STRING_QUADRATICALLY = "Quadratically"; private static final String STRING_OESTERREICH = "\u00D6sterreich"; private static final String STRING_DULIOE_DULIOE = "Duli\u00F6 duli\u00F6"; private static final String STRING_FAITH_HOPE_LOVE = "\u4FE1\u5FF5,\u7231,\u5E0C\u671B"; private static final String STRING_NAIVE = "na\u00EFve"; private static final String STRING_OO = "\uD801\uDC2Dend"; // length increase when cast to lower case, and ends with invalid character private static final byte[] INVALID_SEQUENCE_TO_LOWER_EXPANDS = new byte[] {(byte) 0xC8, (byte) 0xBA, (byte) 0xFF}; private static final byte[] INVALID_UTF8_1 = new byte[] {-127}; private static final byte[] INVALID_UTF8_2 = new byte[] {50, -127, 52, 50}; @Test public void testCodePointCount() { assertCodePointCount(STRING_EMPTY); assertCodePointCount(STRING_HELLO); assertCodePointCount(STRING_QUADRATICALLY); assertCodePointCount(STRING_OESTERREICH); assertCodePointCount(STRING_DULIOE_DULIOE); assertCodePointCount(STRING_FAITH_HOPE_LOVE); assertCodePointCount(STRING_NAIVE); assertCodePointCount(STRING_OO); assertCodePointCount(STRING_ASCII_CODE_POINTS); assertCodePointCount(STRING_ALL_CODE_POINTS); assertCodePointCount(STRING_ALL_CODE_POINTS_RANDOM); assertEquals(countCodePoints(wrappedBuffer(START_1_BYTE)), 1); assertEquals(countCodePoints(wrappedBuffer(START_2_BYTE)), 1); assertEquals(countCodePoints(wrappedBuffer(START_3_BYTE)), 1); assertEquals(countCodePoints(wrappedBuffer(START_4_BYTE)), 1); assertEquals(countCodePoints(wrappedBuffer(START_5_BYTE)), 1); assertEquals(countCodePoints(wrappedBuffer(START_6_BYTE)), 1); assertEquals(countCodePoints(wrappedBuffer(INVALID_FE_BYTE)), 1); assertEquals(countCodePoints(wrappedBuffer(INVALID_FF_BYTE)), 1); assertEquals(countCodePoints(wrappedBuffer(CONTINUATION_BYTE)), 0); } private static void assertCodePointCount(String string) { assertEquals(countCodePoints(utf8Slice(string)), string.codePoints().count()); } @Test public void testOffsetByCodePoints() { assertEquals(offsetOfCodePoint(EMPTY_SLICE, 0), -1); assertOffsetByCodePoints(STRING_HELLO); assertOffsetByCodePoints(STRING_QUADRATICALLY); assertOffsetByCodePoints(STRING_OESTERREICH); assertOffsetByCodePoints(STRING_DULIOE_DULIOE); assertOffsetByCodePoints(STRING_FAITH_HOPE_LOVE); assertOffsetByCodePoints(STRING_NAIVE); assertOffsetByCodePoints(STRING_OO); assertOffsetByCodePoints(STRING_ASCII_CODE_POINTS); assertOffsetByCodePoints(STRING_ALL_CODE_POINTS); assertOffsetByCodePoints(STRING_ALL_CODE_POINTS_RANDOM); } private static void assertOffsetByCodePoints(String string) { Slice utf8 = utf8Slice(string); int codePoints = (int) string.codePoints().count(); int lastIndex = 0; int characterIndex = 0; for (int codePointIndex = 0; codePointIndex < codePoints; codePointIndex++) { int expectedIndex = 0; // calculate the expected index by searching forward from the last index if (codePointIndex > 0) { expectedIndex = lastIndex + lengthOfCodePoint(string.codePointAt(characterIndex)); characterIndex = string.offsetByCodePoints(characterIndex, 1); } // avoid n^2 performance for large test string if (codePointIndex < 10000) { assertEquals(offsetOfCodePoint(utf8, codePointIndex), expectedIndex); } if (codePointIndex > 0) { assertEquals(offsetOfCodePoint(utf8, lastIndex, 1), expectedIndex); } lastIndex = expectedIndex; } assertEquals(offsetOfCodePoint(utf8Slice(string), codePoints), -1); } @Test public void testSubstring() { assertSubstring(STRING_HELLO); assertSubstring(STRING_QUADRATICALLY); assertSubstring(STRING_OESTERREICH); assertSubstring(STRING_DULIOE_DULIOE); assertSubstring(STRING_FAITH_HOPE_LOVE); assertSubstring(STRING_NAIVE); assertSubstring(STRING_OO); assertSubstring(STRING_ASCII_CODE_POINTS); // substring test over all code points takes too long, so only run it on the tail // that has the largest code points assertSubstring(new String(ALL_CODE_POINTS, ALL_CODE_POINTS.length - 500, 500)); } private static void assertSubstring(String string) { Slice utf8 = utf8Slice(string); int[] codePoints = string.codePoints().toArray(); for (int start = 0; start < codePoints.length / 2; start++) { int count = Math.min(20, codePoints.length - start - start - 1); Slice actual = substring(utf8, start, count); Slice expected = wrappedBuffer(new String(codePoints, start, count).getBytes(UTF_8)); assertEquals(actual, expected); } assertEquals(substring(utf8, 0, codePoints.length), utf8); assertEquals(substring(utf8, 0, 0), EMPTY_SLICE); } @Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "UTF-8 does not contain 10 code points") public void testSubstringInvalidStart() { substring(utf8Slice(STRING_HELLO), 10, 2); } @Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "UTF-8 does not contain 7 code points") public void testSubstringInvalidLength() { substring(utf8Slice(STRING_HELLO), 0, 7); } @Test(expectedExceptions = InvalidUtf8Exception.class, expectedExceptionsMessageRegExp = "UTF-8 is not well formed") public void testSubstringInvalidUtf8() { substring(wrappedBuffer((byte) 'f', (byte) 'o', (byte) 'o', START_3_BYTE, CONTINUATION_BYTE), 0, 4); } @Test public void testReverse() { assertReverse(STRING_HELLO); assertReverse(STRING_QUADRATICALLY); assertReverse(STRING_OESTERREICH); assertReverse(STRING_DULIOE_DULIOE); assertReverse(STRING_FAITH_HOPE_LOVE); assertReverse(STRING_NAIVE); assertReverse(STRING_OO); assertReverse(STRING_ASCII_CODE_POINTS); assertReverse(STRING_ALL_CODE_POINTS); INVALID_SEQUENCES.forEach(TestSliceUtf8::assertReverseWithInvalidSequence); } private static void assertReverse(String string) { Slice actualReverse = reverse(utf8Slice(string)); int[] codePoints = string.codePoints().toArray(); codePoints = Ints.toArray(Lists.reverse(Ints.asList(codePoints))); Slice expectedReverse = wrappedBuffer(new String(codePoints, 0, codePoints.length).getBytes(UTF_8)); assertEquals(actualReverse, expectedReverse); } private static void assertReverseWithInvalidSequence(byte[] invalidSequence) { assertEquals( reverse(wrappedBuffer(invalidSequence)), wrappedBuffer(invalidSequence)); assertEquals( reverse(wrappedBuffer(concat(new byte[] {'a', 'b', 'c'}, invalidSequence))), wrappedBuffer(concat(invalidSequence, new byte[] {'c', 'b', 'a'}))); assertEquals( reverse(wrappedBuffer(concat(invalidSequence, new byte[] {'x', 'y', 'z'}))), wrappedBuffer(concat(new byte[] {'z', 'y', 'x'}, invalidSequence))); assertEquals( reverse(wrappedBuffer(concat(new byte[] {'a', 'b', 'c'}, invalidSequence, new byte[] {'x', 'y', 'z'}))), wrappedBuffer(concat(new byte[] {'z', 'y', 'x'}, invalidSequence, new byte[] {'c', 'b', 'a'}))); } @Test public void testIsAscii() { assertTrue(isAscii(utf8Slice(STRING_HELLO))); assertTrue(isAscii(utf8Slice(STRING_QUADRATICALLY))); assertFalse(isAscii(utf8Slice(STRING_OESTERREICH))); assertFalse(isAscii(utf8Slice(STRING_DULIOE_DULIOE))); assertFalse(isAscii(utf8Slice(STRING_FAITH_HOPE_LOVE))); assertFalse(isAscii(utf8Slice(STRING_NAIVE))); assertFalse(isAscii(utf8Slice(STRING_OO))); assertTrue(isAscii(utf8Slice(STRING_ASCII_CODE_POINTS))); assertFalse(isAscii(utf8Slice(STRING_ALL_CODE_POINTS))); } @Test public void testFixInvalidUtf8() { assertFixInvalidUtf8(utf8Slice(STRING_OESTERREICH), utf8Slice(STRING_OESTERREICH)); assertFixInvalidUtf8(utf8Slice(STRING_HELLO), utf8Slice(STRING_HELLO)); assertFixInvalidUtf8(utf8Slice(STRING_QUADRATICALLY), utf8Slice(STRING_QUADRATICALLY)); assertFixInvalidUtf8(utf8Slice(STRING_OESTERREICH), utf8Slice(STRING_OESTERREICH)); assertFixInvalidUtf8(utf8Slice(STRING_DULIOE_DULIOE), utf8Slice(STRING_DULIOE_DULIOE)); assertFixInvalidUtf8(utf8Slice(STRING_FAITH_HOPE_LOVE), utf8Slice(STRING_FAITH_HOPE_LOVE)); assertFixInvalidUtf8(utf8Slice(STRING_NAIVE), utf8Slice(STRING_NAIVE)); assertFixInvalidUtf8(utf8Slice(STRING_OO), utf8Slice(STRING_OO)); assertFixInvalidUtf8(utf8Slice(STRING_ASCII_CODE_POINTS), utf8Slice(STRING_ASCII_CODE_POINTS)); assertFixInvalidUtf8(utf8Slice(STRING_ALL_CODE_POINTS), utf8Slice(STRING_ALL_CODE_POINTS)); // max valid value for 2, 3, and 4 byte sequences assertFixInvalidUtf8(wrappedBuffer(X_CHAR, START_2_BYTE, CONTINUATION_BYTE), utf8Slice("X\u07FF")); assertFixInvalidUtf8(wrappedBuffer(X_CHAR, START_3_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE), utf8Slice("X\uFFFF")); // 4 byte sequence is limited to U+10FFFF by RFC 3629 assertFixInvalidUtf8( wrappedBuffer(X_CHAR, (byte) 0xF4, (byte) 0x8F, CONTINUATION_BYTE, CONTINUATION_BYTE), wrappedBuffer(X_CHAR, (byte) 0xF4, (byte) 0x8F, CONTINUATION_BYTE, CONTINUATION_BYTE)); // 4 byte sequence is limited to 10FFFF assertFixInvalidUtf8(wrappedBuffer(X_CHAR, START_4_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE), utf8Slice("X\uFFFD")); // 5 and 6 byte sequences are always invalid assertFixInvalidUtf8(wrappedBuffer(X_CHAR, START_5_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE), utf8Slice("X\uFFFD")); assertFixInvalidUtf8(wrappedBuffer(X_CHAR, START_6_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE), utf8Slice("X\uFFFD")); // continuation byte alone is invalid assertFixInvalidUtf8(wrappedBuffer(X_CHAR, CONTINUATION_BYTE), utf8Slice("X\uFFFD")); assertFixInvalidUtf8(wrappedBuffer(X_CHAR, INVALID_FE_BYTE), utf8Slice("X\uFFFD")); assertFixInvalidUtf8(wrappedBuffer(X_CHAR, INVALID_FF_BYTE), utf8Slice("X\uFFFD")); // sequences with not enough continuation bytes, but enough bytes assertFixInvalidUtf8(wrappedBuffer(X_CHAR, START_2_BYTE, X_CHAR), utf8Slice("X\uFFFDX")); assertFixInvalidUtf8(wrappedBuffer(X_CHAR, START_3_BYTE, X_CHAR, X_CHAR), utf8Slice("X\uFFFDXX")); assertFixInvalidUtf8(wrappedBuffer(X_CHAR, START_3_BYTE, CONTINUATION_BYTE, X_CHAR), utf8Slice("X\uFFFDX")); assertFixInvalidUtf8(wrappedBuffer(X_CHAR, START_4_BYTE, X_CHAR, X_CHAR, X_CHAR), utf8Slice("X\uFFFDXXX")); assertFixInvalidUtf8(wrappedBuffer(X_CHAR, START_4_BYTE, CONTINUATION_BYTE, X_CHAR, X_CHAR), utf8Slice("X\uFFFDXX")); assertFixInvalidUtf8(wrappedBuffer(X_CHAR, START_4_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE, X_CHAR), utf8Slice("X\uFFFDX")); assertFixInvalidUtf8(wrappedBuffer(X_CHAR, START_5_BYTE, X_CHAR, X_CHAR, X_CHAR, X_CHAR), utf8Slice("X\uFFFDXXXX")); assertFixInvalidUtf8(wrappedBuffer(X_CHAR, START_5_BYTE, CONTINUATION_BYTE, X_CHAR, X_CHAR, X_CHAR), utf8Slice("X\uFFFDXXX")); assertFixInvalidUtf8(wrappedBuffer(X_CHAR, START_5_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE, X_CHAR, X_CHAR), utf8Slice("X\uFFFDXX")); assertFixInvalidUtf8(wrappedBuffer(X_CHAR, START_5_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE, X_CHAR), utf8Slice("X\uFFFDX")); assertFixInvalidUtf8(wrappedBuffer(X_CHAR, START_6_BYTE, X_CHAR, X_CHAR, X_CHAR, X_CHAR, X_CHAR), utf8Slice("X\uFFFDXXXXX")); assertFixInvalidUtf8(wrappedBuffer(X_CHAR, START_6_BYTE, CONTINUATION_BYTE, X_CHAR, X_CHAR, X_CHAR, X_CHAR), utf8Slice("X\uFFFDXXXX")); assertFixInvalidUtf8(wrappedBuffer(X_CHAR, START_6_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE, X_CHAR, X_CHAR, X_CHAR), utf8Slice("X\uFFFDXXX")); assertFixInvalidUtf8(wrappedBuffer(X_CHAR, START_6_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE, X_CHAR, X_CHAR), utf8Slice("X\uFFFDXX")); assertFixInvalidUtf8(wrappedBuffer(X_CHAR, START_6_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE, X_CHAR), utf8Slice("X\uFFFDX")); assertFixInvalidUtf8(wrappedBuffer(X_CHAR, INVALID_FE_BYTE), utf8Slice("X\uFFFD")); assertFixInvalidUtf8(wrappedBuffer(X_CHAR, INVALID_FF_BYTE), utf8Slice("X\uFFFD")); // truncated sequences assertFixInvalidUtf8(wrappedBuffer(X_CHAR, CONTINUATION_BYTE), utf8Slice("X\uFFFD")); assertFixInvalidUtf8(wrappedBuffer(X_CHAR, START_2_BYTE), utf8Slice("X\uFFFD")); assertFixInvalidUtf8(wrappedBuffer(X_CHAR, START_3_BYTE), utf8Slice("X\uFFFD")); assertFixInvalidUtf8(wrappedBuffer(X_CHAR, START_3_BYTE, CONTINUATION_BYTE), utf8Slice("X\uFFFD")); assertFixInvalidUtf8(wrappedBuffer(X_CHAR, START_4_BYTE), utf8Slice("X\uFFFD")); assertFixInvalidUtf8(wrappedBuffer(X_CHAR, START_4_BYTE, CONTINUATION_BYTE), utf8Slice("X\uFFFD")); assertFixInvalidUtf8(wrappedBuffer(X_CHAR, START_4_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE), utf8Slice("X\uFFFD")); assertFixInvalidUtf8(wrappedBuffer(X_CHAR, START_5_BYTE), utf8Slice("X\uFFFD")); assertFixInvalidUtf8(wrappedBuffer(X_CHAR, START_5_BYTE, CONTINUATION_BYTE), utf8Slice("X\uFFFD")); assertFixInvalidUtf8(wrappedBuffer(X_CHAR, START_5_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE), utf8Slice("X\uFFFD")); assertFixInvalidUtf8(wrappedBuffer(X_CHAR, START_5_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE), utf8Slice("X\uFFFD")); assertFixInvalidUtf8(wrappedBuffer(X_CHAR, START_6_BYTE), utf8Slice("X\uFFFD")); assertFixInvalidUtf8(wrappedBuffer(X_CHAR, START_6_BYTE, CONTINUATION_BYTE), utf8Slice("X\uFFFD")); assertFixInvalidUtf8(wrappedBuffer(X_CHAR, START_6_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE), utf8Slice("X\uFFFD")); assertFixInvalidUtf8(wrappedBuffer(X_CHAR, START_6_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE), utf8Slice("X\uFFFD")); assertFixInvalidUtf8(wrappedBuffer(X_CHAR, START_6_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE), utf8Slice("X\uFFFD")); assertFixInvalidUtf8(wrappedBuffer(X_CHAR, START_6_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE), utf8Slice("X\uFFFD")); assertFixInvalidUtf8(wrappedBuffer(X_CHAR, INVALID_FE_BYTE), utf8Slice("X\uFFFD")); assertFixInvalidUtf8(wrappedBuffer(X_CHAR, INVALID_FF_BYTE), utf8Slice("X\uFFFD")); // min and max surrogate characters assertFixInvalidUtf8(wrappedBuffer(X_CHAR, (byte) 0b11101101, (byte) 0xA0, (byte) 0x80), utf8Slice("X\uFFFD")); assertFixInvalidUtf8(wrappedBuffer(X_CHAR, (byte) 0b11101101, (byte) 0xBF, (byte) 0xBF), utf8Slice("X\uFFFD")); } private static void assertFixInvalidUtf8(Slice testSlice, Slice expectedSlice) { assertEquals(fixInvalidUtf8(testSlice), expectedSlice); } @Test public void testCaseChange() { assertCaseChange(STRING_ALL_CODE_POINTS); assertCaseChange(STRING_FAITH_HOPE_LOVE); assertCaseChange(STRING_HELLO); assertCaseChange(STRING_QUADRATICALLY); assertCaseChange(STRING_OESTERREICH); assertCaseChange(STRING_DULIOE_DULIOE); assertCaseChange(STRING_FAITH_HOPE_LOVE); assertCaseChange(STRING_NAIVE); assertCaseChange(STRING_OO); assertCaseChange(STRING_ASCII_CODE_POINTS); assertCaseChange(STRING_ALL_CODE_POINTS); assertCaseChange(STRING_ALL_CODE_POINTS_RANDOM); toLowerCase(Slices.wrappedBuffer(INVALID_SEQUENCE_TO_LOWER_EXPANDS)); INVALID_SEQUENCES.forEach(TestSliceUtf8::assertCaseChangeWithInvalidSequence); } private static void assertCaseChangeWithInvalidSequence(byte[] invalidSequence) { assertEquals( toLowerCase(wrappedBuffer(invalidSequence)), wrappedBuffer(invalidSequence)); assertEquals( toUpperCase(wrappedBuffer(invalidSequence)), wrappedBuffer(invalidSequence)); assertEquals( toLowerCase(wrappedBuffer(concat(new byte[] {'F', 'O', 'O'}, invalidSequence))), wrappedBuffer(concat(new byte[] {'f', 'o', 'o'}, invalidSequence))); assertEquals( toUpperCase(wrappedBuffer(concat(new byte[] {'f', 'o', 'o'}, invalidSequence))), wrappedBuffer(concat(new byte[] {'F', 'O', 'O'}, invalidSequence))); assertEquals( toLowerCase(wrappedBuffer(concat(invalidSequence, new byte[] {'F', 'O', 'O'}))), wrappedBuffer(concat(invalidSequence, new byte[] {'f', 'o', 'o'}))); assertEquals( toUpperCase(wrappedBuffer(concat(invalidSequence, new byte[] {'f', 'o', 'o'}))), wrappedBuffer(concat(invalidSequence, new byte[] {'F', 'O', 'O'}))); assertEquals( toLowerCase(wrappedBuffer(concat(new byte[] {'F', 'O', 'O'}, invalidSequence, new byte[] {'B', 'A', 'R'}))), wrappedBuffer(concat(new byte[] {'f', 'o', 'o'}, invalidSequence, new byte[] {'b', 'a', 'r'}))); assertEquals( toUpperCase(wrappedBuffer(concat(new byte[] {'f', 'o', 'o'}, invalidSequence, new byte[] {'b', 'a', 'r'}))), wrappedBuffer(concat(new byte[] {'F', 'O', 'O'}, invalidSequence, new byte[] {'B', 'A', 'R'}))); } private static void assertCaseChange(String string) { String expectedLower = lowerByCodePoint(string); Slice actualLower = toLowerCase(utf8Slice(string)); assertEquals(actualLower, wrappedBuffer(expectedLower.getBytes(UTF_8))); String expectedUpper = upperByCodePoint(string); Slice actualUpper = toUpperCase(utf8Slice(string)); assertEquals(actualUpper, wrappedBuffer(expectedUpper.getBytes(UTF_8))); // lower the upper and upper the lower // NOTE: not all code points roundtrip, so calculate the expected assertEquals(toLowerCase(actualUpper), wrappedBuffer(lowerByCodePoint(expectedUpper).getBytes(UTF_8))); assertEquals(toUpperCase(actualLower), wrappedBuffer(upperByCodePoint(expectedLower).getBytes(UTF_8))); } private static String lowerByCodePoint(String string) { int[] upperCodePoints = string.codePoints().map(Character::toLowerCase).toArray(); return new String(upperCodePoints, 0, upperCodePoints.length); } private static String upperByCodePoint(String string) { int[] upperCodePoints = string.codePoints().map(Character::toUpperCase).toArray(); return new String(upperCodePoints, 0, upperCodePoints.length); } @Test public void testLeftTrim() { assertLeftTrim(""); assertLeftTrim("hello"); assertLeftTrim("hello world"); assertLeftTrim("hello world "); INVALID_SEQUENCES.forEach(TestSliceUtf8::assertLeftTrim); } private static void assertLeftTrim(String string) { assertLeftTrim(string.getBytes(UTF_8)); } private static void assertLeftTrim(byte[] sequence) { assertEquals(leftTrim(wrappedBuffer(sequence)), wrappedBuffer(sequence)); for (int codePoint : ALL_CODE_POINTS) { if (Character.isWhitespace(codePoint)) { byte[] whitespace = new String(new int[] {codePoint}, 0, 1).getBytes(UTF_8); assertEquals(leftTrim(wrappedBuffer(concat(whitespace, sequence))), wrappedBuffer(sequence)); assertEquals(leftTrim(wrappedBuffer(concat(whitespace, new byte[] {'\r', '\n', '\t', ' '}, whitespace, sequence))), wrappedBuffer(sequence)); } } } @Test public void testRightTrim() { assertRightTrim(""); assertRightTrim("hello"); assertRightTrim("hello world"); assertRightTrim(" hello world"); INVALID_SEQUENCES.forEach(TestSliceUtf8::assertRightTrim); } private static void assertRightTrim(String string) { assertRightTrim(string.getBytes(UTF_8)); } private static void assertRightTrim(byte[] sequence) { assertEquals(rightTrim(wrappedBuffer(sequence)), wrappedBuffer(sequence)); for (int codePoint : ALL_CODE_POINTS) { if (Character.isWhitespace(codePoint)) { byte[] whitespace = new String(new int[] {codePoint}, 0, 1).getBytes(UTF_8); assertEquals(rightTrim(wrappedBuffer(concat(sequence, whitespace))), wrappedBuffer(sequence)); assertEquals(rightTrim(wrappedBuffer(concat(sequence, whitespace, new byte[] {'\r', '\n', '\t', ' '}, whitespace))), wrappedBuffer(sequence)); } } } @Test public void testTrim() { assertTrim(""); assertTrim("hello"); assertTrim("hello world"); INVALID_SEQUENCES.forEach(TestSliceUtf8::assertTrim); } private static void assertTrim(String string) { assertTrim(string.getBytes(UTF_8)); } private static void assertTrim(byte[] sequence) { assertEquals(trim(wrappedBuffer(sequence)), wrappedBuffer(sequence)); for (int codePoint : ALL_CODE_POINTS) { if (Character.isWhitespace(codePoint)) { byte[] whitespace = new String(new int[] {codePoint}, 0, 1).getBytes(UTF_8); assertEquals(trim(wrappedBuffer(concat(whitespace, sequence, whitespace))), wrappedBuffer(sequence)); assertEquals( trim(wrappedBuffer(concat(whitespace, new byte[] {'\r', '\n', '\t', ' '}, whitespace, sequence, whitespace, new byte[] {'\r', '\n', '\t', ' '}, whitespace))), wrappedBuffer(sequence)); } } } /** * Test invalid UTF8 encodings. We do not expect a 'correct' but none harmful result. */ @Test public void testInvalidUtf8() { assertEquals(countCodePoints(wrappedBuffer(INVALID_UTF8_1)), 0); assertEquals(countCodePoints(wrappedBuffer(INVALID_UTF8_2)), 3); assertEquals(offsetOfCodePoint(wrappedBuffer(INVALID_UTF8_1), 0), 0); assertEquals(offsetOfCodePoint(wrappedBuffer(INVALID_UTF8_1), 1), -1); assertEquals(offsetOfCodePoint(wrappedBuffer(INVALID_UTF8_2), 0), 0); assertEquals(offsetOfCodePoint(wrappedBuffer(INVALID_UTF8_2), 1), 2); assertEquals(offsetOfCodePoint(wrappedBuffer(INVALID_UTF8_2), 2), 3); assertEquals(offsetOfCodePoint(wrappedBuffer(INVALID_UTF8_2), 3), -1); } @Test public void testLengthOfCodePoint() { assertEquals(lengthOfCodePointFromStartByte(START_1_BYTE), 1); assertEquals(lengthOfCodePointFromStartByte(START_2_BYTE), 2); assertEquals(lengthOfCodePointFromStartByte(START_3_BYTE), 3); assertEquals(lengthOfCodePointFromStartByte(START_4_BYTE), 4); for (int codePoint : ALL_CODE_POINTS) { String string = new String(new int[] {codePoint}, 0, 1); assertEquals(string.codePoints().count(), 1); Slice utf8 = wrappedBuffer(string.getBytes(UTF_8)); assertEquals(lengthOfCodePoint(codePoint), utf8.length()); assertEquals(lengthOfCodePoint(utf8, 0), utf8.length()); assertEquals(lengthOfCodePointSafe(utf8, 0), utf8.length()); assertEquals(lengthOfCodePointFromStartByte(utf8.getByte(0)), utf8.length()); assertEquals(getCodePointAt(utf8, 0), codePoint); assertEquals(getCodePointBefore(utf8, utf8.length()), codePoint); assertEquals(codePointToUtf8(codePoint), utf8); } for (byte[] sequence : INVALID_SEQUENCES) { assertEquals(lengthOfCodePointSafe(wrappedBuffer(sequence), 0), sequence.length); assertEquals(lengthOfCodePointSafe(wrappedBuffer(concat(new byte[] {'x'}, sequence)), 1), sequence.length); assertEquals(lengthOfCodePointSafe(wrappedBuffer(concat(sequence, new byte[] {'x'})), 0), sequence.length); } } @Test(expectedExceptions = InvalidCodePointException.class, expectedExceptionsMessageRegExp = "Invalid code point 0xFFFFFFFF") public void testLengthOfNegativeCodePoint() { lengthOfCodePoint(-1); } @Test(expectedExceptions = InvalidCodePointException.class, expectedExceptionsMessageRegExp = "Invalid code point 0x110000") public void testLengthOfOutOfRangeCodePoint() { lengthOfCodePoint(MAX_CODE_POINT + 1); } @Test(expectedExceptions = InvalidUtf8Exception.class, expectedExceptionsMessageRegExp = "Illegal start 0xBF of code point") public void testLengthOfCodePointContinuationByte() { lengthOfCodePointFromStartByte(CONTINUATION_BYTE); } @Test(expectedExceptions = InvalidUtf8Exception.class, expectedExceptionsMessageRegExp = "Illegal start 0xFB of code point") public void testLengthOfCodePoint5ByteSequence() { lengthOfCodePointFromStartByte(START_5_BYTE); } @Test(expectedExceptions = InvalidUtf8Exception.class, expectedExceptionsMessageRegExp = "Illegal start 0xFD of code point") public void testLengthOfCodePoint6ByteByte() { lengthOfCodePointFromStartByte(START_6_BYTE); } @Test(expectedExceptions = InvalidUtf8Exception.class, expectedExceptionsMessageRegExp = "Illegal start 0xFE of code point") public void testLengthOfCodePointFEByte() { lengthOfCodePointFromStartByte(INVALID_FE_BYTE); } @Test(expectedExceptions = InvalidUtf8Exception.class, expectedExceptionsMessageRegExp = "Illegal start 0xFF of code point") public void testLengthOfCodePointFFByte() { lengthOfCodePointFromStartByte(INVALID_FF_BYTE); } @Test(expectedExceptions = InvalidUtf8Exception.class, expectedExceptionsMessageRegExp = "UTF-8 sequence truncated") public void testCodePointAtTruncated2() { getCodePointAt(wrappedBuffer((byte) 'x', START_2_BYTE), 1); } @Test(expectedExceptions = InvalidUtf8Exception.class, expectedExceptionsMessageRegExp = "UTF-8 sequence truncated") public void testCodePointAtTruncated3() { getCodePointAt(wrappedBuffer((byte) 'x', START_3_BYTE, CONTINUATION_BYTE), 1); } @Test(expectedExceptions = InvalidUtf8Exception.class, expectedExceptionsMessageRegExp = "UTF-8 sequence truncated") public void testCodePointAtTruncated4() { getCodePointAt(wrappedBuffer((byte) 'x', START_4_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE), 1); } @Test(expectedExceptions = InvalidUtf8Exception.class, expectedExceptionsMessageRegExp = "Illegal start 0xFB of code point") public void testCodePointAt5ByteSequence() { getCodePointAt(wrappedBuffer((byte) 'x', START_5_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE), 1); } @Test(expectedExceptions = InvalidUtf8Exception.class, expectedExceptionsMessageRegExp = "UTF-8 is not well formed") public void testCodePointBefore5ByteSequence() { getCodePointBefore(wrappedBuffer((byte) 'x', START_5_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE, CONTINUATION_BYTE), 6); } @Test(expectedExceptions = InvalidCodePointException.class, expectedExceptionsMessageRegExp = "Invalid code point 0xFFFFFFFF") public void testSetNegativeCodePoint() { setCodePointAt(-1, Slices.allocate(8), 0); } @Test(expectedExceptions = InvalidCodePointException.class, expectedExceptionsMessageRegExp = "Invalid code point 0xD800") public void testSetSurrogateCodePoint() { setCodePointAt(MIN_SURROGATE, Slices.allocate(8), 0); } @Test(expectedExceptions = InvalidCodePointException.class, expectedExceptionsMessageRegExp = "Invalid code point 0x110000") public void testSetOutOfRangeCodePoint() { setCodePointAt(MAX_CODE_POINT + 1, Slices.allocate(8), 0); } @Test(expectedExceptions = InvalidCodePointException.class, expectedExceptionsMessageRegExp = "Invalid code point 0xFFFFFFBF") public void testSetCodePointContinuationByte() { setCodePointAt(CONTINUATION_BYTE, Slices.allocate(8), 0); } } slice-0.16/src/test/java/io/airlift/slice/TestSlices.java000066400000000000000000000036521261474317300233310ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import org.testng.annotations.Test; import java.nio.ByteBuffer; import static org.testng.Assert.assertEquals; public class TestSlices { @Test public void testWrapDirectBuffer() throws Exception { testWrapping(ByteBuffer.allocateDirect(50)); } @Test public void testWrapHeapBuffer() throws Exception { testWrapping(ByteBuffer.allocate(50)); } private static void testWrapping(ByteBuffer buffer) { // initialize buffer for (int i = 0; i < 50; i++) { buffer.put((byte) i); } // test full buffer buffer.rewind(); Slice slice = Slices.wrappedBuffer(buffer); assertEquals(slice.length(), 50); for (int i = 0; i < 50; i++) { assertEquals(slice.getByte(i), i); } // test limited buffer buffer.position(10).limit(30); slice = Slices.wrappedBuffer(buffer); assertEquals(slice.length(), 20); for (int i = 0; i < 20; i++) { assertEquals(slice.getByte(i), i + 10); } // test limited buffer after slicing buffer = buffer.slice(); slice = Slices.wrappedBuffer(buffer); assertEquals(slice.length(), 20); for (int i = 0; i < 20; i++) { assertEquals(slice.getByte(i), i + 10); } } } slice-0.16/src/test/java/io/airlift/slice/TestUnsafeSliceFactory.java000066400000000000000000000053641261474317300256420ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import com.google.common.primitives.Ints; import org.testng.annotations.Test; import sun.nio.ch.DirectBuffer; import java.nio.ByteBuffer; import java.security.Permission; import static io.airlift.slice.JvmUtils.unsafe; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; public class TestUnsafeSliceFactory { @Test public void testRawAddress() throws Exception { UnsafeSliceFactory factory = UnsafeSliceFactory.getInstance(); int size = 100; long address = unsafe.allocateMemory(size); try { Slice slice = factory.newSlice(address, size); for (int i = 0; i < size; i += Ints.BYTES) { slice.setInt(i, i); } for (int i = 0; i < size; i += Ints.BYTES) { assertEquals(slice.getInt(i), i); } } finally { unsafe.freeMemory(address); } } @Test public void testRawAddressWithReference() throws Exception { ByteBuffer buffer = ByteBuffer.allocateDirect(100); assertTrue(buffer instanceof DirectBuffer); long address = ((DirectBuffer) buffer).address(); UnsafeSliceFactory factory = UnsafeSliceFactory.getInstance(); Slice slice = factory.newSlice(address, buffer.capacity(), buffer); slice.setInt(32, 0xDEADBEEF); assertEquals(slice.getInt(32), 0xDEADBEEF); } @Test(expectedExceptions = SecurityException.class) public void testSecurity() throws Exception { SecurityManager saved = System.getSecurityManager(); System.setSecurityManager(new SecurityManager() { @Override public void checkPermission(Permission perm) { if (perm.getName().equals("suppressAccessChecks")) { throw new SecurityException(); } } }); try { UnsafeSliceFactory.getInstance(); fail("expected SecurityException"); } finally { System.setSecurityManager(saved); } } } slice-0.16/src/test/java/io/airlift/slice/TestXxHash64.java000066400000000000000000000043701261474317300234620ustar00rootroot00000000000000/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.airlift.slice; import org.testng.annotations.Test; import static io.airlift.slice.XxHash64.hash; import static org.testng.Assert.assertEquals; public class TestXxHash64 { private static final long PRIME = 2654435761L; private final Slice buffer; public TestXxHash64() { buffer = Slices.allocate(101); long value = PRIME; for (int i = 0; i < buffer.length(); i++) { buffer.setByte(i, (byte) (value >> 24)); value *= value; } } @Test public void testSanity() throws Exception { assertEquals(hash(0, buffer, 0, 1), 0x4FCE394CC88952D8L); assertEquals(hash(PRIME, buffer, 0, 1), 0x739840CB819FA723L); assertEquals(hash(0, buffer, 0, 4), 0x9256E58AA397AEF1L); assertEquals(hash(PRIME, buffer, 0, 4), 0x9D5FFDFB928AB4BL); assertEquals(hash(0, buffer, 0, 8), 0xF74CB1451B32B8CFL); assertEquals(hash(PRIME, buffer, 0, 8), 0x9C44B77FBCC302C5L); assertEquals(hash(0, buffer, 0, 14), 0xCFFA8DB881BC3A3DL); assertEquals(hash(PRIME, buffer, 0, 14), 0x5B9611585EFCC9CBL); assertEquals(hash(0, buffer, 0, 32), 0xAF5753D39159EDEEL); assertEquals(hash(PRIME, buffer, 0, 32), 0xDCAB9233B8CA7B0FL); assertEquals(hash(0, buffer), 0x0EAB543384F878ADL); assertEquals(hash(PRIME, buffer), 0xCAA65939306F1E21L); } @Test public void testEmpty() throws Exception { assertEquals(hash(0, Slices.EMPTY_SLICE), 0xEF46DB3751D8E999L); } @Test public void testHashLong() throws Exception { assertEquals(hash(buffer.getLong(0)), hash(buffer, 0, SizeOf.SIZE_OF_LONG)); } }