| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.iotdb.tsfile.utils; |
| |
| import java.io.ByteArrayOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.nio.ByteBuffer; |
| import java.util.List; |
| |
| /** Utils to read/write stream. */ |
| public class ReadWriteForEncodingUtils { |
| private static final String TOO_LONG_BYTE_FORMAT = |
| "tsfile-common BytesUtils: encountered value (%d) that requires more than 4 bytes"; |
| |
| private ReadWriteForEncodingUtils() {} |
| |
| /** |
| * check all number in a int list and find max bit width. |
| * |
| * @param list input list |
| * @return max bit width |
| */ |
| public static int getIntMaxBitWidth(List<Integer> list) { |
| int max = 1; |
| for (int num : list) { |
| int bitWidth = 32 - Integer.numberOfLeadingZeros(num); |
| max = Math.max(bitWidth, max); |
| } |
| return max; |
| } |
| |
| /** |
| * check all number in a long list and find max bit width. |
| * |
| * @param list input list |
| * @return max bit width |
| */ |
| public static int getLongMaxBitWidth(List<Long> list) { |
| int max = 1; |
| for (long num : list) { |
| int bitWidth = 64 - Long.numberOfLeadingZeros(num); |
| max = Math.max(bitWidth, max); |
| } |
| return max; |
| } |
| |
| /** transform an int var to byte[] format. */ |
| public static byte[] getUnsignedVarInt(int value) { |
| int preValue = value; |
| int length = 0; |
| while ((value & 0xFFFFFF80) != 0L) { |
| length++; |
| value >>>= 7; |
| } |
| length++; |
| |
| byte[] res = new byte[length]; |
| value = preValue; |
| int i = 0; |
| while ((value & 0xFFFFFF80) != 0L) { |
| res[i] = (byte) ((value & 0x7F) | 0x80); |
| value >>>= 7; |
| i++; |
| } |
| res[i] = (byte) (value & 0x7F); |
| return res; |
| } |
| |
| /** |
| * read an unsigned var int in stream and transform it to int format. |
| * |
| * @param in stream to read an unsigned var int |
| * @return integer value |
| * @throws IOException exception in IO |
| */ |
| public static int readUnsignedVarInt(InputStream in) throws IOException { |
| int value = 0; |
| int i = 0; |
| int b = in.read(); |
| while (b != -1 && (b & 0x80) != 0) { |
| value |= (b & 0x7F) << i; |
| i += 7; |
| b = in.read(); |
| } |
| return value | (b << i); |
| } |
| |
| public static int readVarInt(InputStream in) throws IOException { |
| int value = readUnsignedVarInt(in); |
| int x = value >>> 1; |
| if ((value & 1) != 0) { |
| x = ~x; |
| } |
| return x; |
| } |
| |
| /** |
| * read an unsigned var int in stream and transform it to int format. |
| * |
| * @param buffer stream to read an unsigned var int |
| * @return integer value |
| */ |
| public static int readUnsignedVarInt(ByteBuffer buffer) { |
| int value = 0; |
| int i = 0; |
| int b = 0; |
| while (buffer.hasRemaining() && ((b = buffer.get()) & 0x80) != 0) { |
| value |= (b & 0x7F) << i; |
| i += 7; |
| } |
| return value | (b << i); |
| } |
| |
| public static int readVarInt(ByteBuffer buffer) { |
| int value = readUnsignedVarInt(buffer); |
| int x = value >>> 1; |
| if ((value & 1) != 0) { |
| x = ~x; |
| } |
| return x; |
| } |
| |
| /** |
| * write a value to stream using unsigned var int format. for example, int 123456789 has its |
| * binary format 00000111-01011011-11001101-00010101 (if we omit the first 5 0, then it is |
| * 111010-1101111-0011010-0010101), function writeUnsignedVarInt will split every seven bits and |
| * write them to stream from low bit to high bit like: 1-0010101 1-0011010 1-1101111 0-0111010 1 |
| * represents has next byte to write, 0 represents number end. |
| * |
| * @param value value to write into stream |
| * @param out output stream |
| * @return the number of bytes that the value consume. |
| */ |
| public static int writeUnsignedVarInt(int value, ByteArrayOutputStream out) { |
| int position = 1; |
| while ((value & 0xFFFFFF80) != 0L) { |
| out.write((value & 0x7F) | 0x80); |
| value >>>= 7; |
| position++; |
| } |
| out.write(value & 0x7F); |
| return position; |
| } |
| |
| public static int writeVarInt(int value, ByteArrayOutputStream out) { |
| int uValue = value << 1; |
| if (value < 0) { |
| uValue = ~uValue; |
| } |
| return writeUnsignedVarInt(uValue, out); |
| } |
| |
| public static int writeUnsignedVarInt(int value, OutputStream out) throws IOException { |
| int position = 1; |
| while ((value & 0xFFFFFF80) != 0L) { |
| out.write((value & 0x7F) | 0x80); |
| value >>>= 7; |
| position++; |
| } |
| out.write(value & 0x7F); |
| return position; |
| } |
| |
| public static int writeVarInt(int value, OutputStream out) throws IOException { |
| int uValue = value << 1; |
| if (value < 0) { |
| uValue = ~uValue; |
| } |
| return writeUnsignedVarInt(uValue, out); |
| } |
| |
| /** |
| * write a value to stream using unsigned var int format. for example, int 123456789 has its |
| * binary format 111010-1101111-0011010-0010101, function writeUnsignedVarInt will split every |
| * seven bits and write them to stream from low bit to high bit like: 1-0010101 1-0011010 |
| * 1-1101111 0-0111010 1 represents has next byte to write, 0 represents number end. |
| * |
| * @param value value to write into stream |
| * @param buffer where to store the result. buffer.remaining() needs to >= 32. Notice: (1) this |
| * function does not check buffer's remaining(). (2) the position will be updated. |
| * @return the number of bytes that the value consume. |
| * @throws IOException exception in IO |
| */ |
| public static int writeUnsignedVarInt(int value, ByteBuffer buffer) { |
| int position = 1; |
| while ((value & 0xFFFFFF80) != 0L) { |
| buffer.put((byte) ((value & 0x7F) | 0x80)); |
| value >>>= 7; |
| position++; |
| } |
| buffer.put((byte) (value & 0x7F)); |
| return position; |
| } |
| |
| public static int writeVarInt(int value, ByteBuffer buffer) { |
| int uValue = value << 1; |
| if (value < 0) { |
| uValue = ~uValue; |
| } |
| return writeUnsignedVarInt(uValue, buffer); |
| } |
| |
| /** |
| * Returns the encoding size in bytes of its input value. |
| * |
| * @param value the integer to be measured |
| * @return the encoding size in bytes of its input value |
| */ |
| public static int varIntSize(int value) { |
| int uValue = value << 1; |
| if (value < 0) { |
| uValue = ~uValue; |
| } |
| int position = 1; |
| while ((uValue & 0xFFFFFF80) != 0L) { |
| uValue >>>= 7; |
| position++; |
| } |
| return position; |
| } |
| |
| /** |
| * Returns the encoding size in bytes of its input value. |
| * |
| * @param value the unsigned integer to be measured |
| * @return the encoding size in bytes of its input value |
| */ |
| public static int uVarIntSize(int value) { |
| int position = 1; |
| while ((value & 0xFFFFFF80) != 0L) { |
| value >>>= 7; |
| position++; |
| } |
| return position; |
| } |
| |
| /** |
| * write integer value using special bit to output stream. |
| * |
| * @param value value to write to stream |
| * @param out output stream |
| * @param bitWidth bit length |
| * @throws IOException exception in IO |
| */ |
| public static void writeIntLittleEndianPaddedOnBitWidth(int value, OutputStream out, int bitWidth) |
| throws IOException { |
| int paddedByteNum = (bitWidth + 7) / 8; |
| if (paddedByteNum > 4) { |
| throw new IOException(String.format(TOO_LONG_BYTE_FORMAT, paddedByteNum)); |
| } |
| int offset = 0; |
| while (paddedByteNum > 0) { |
| out.write((value >>> offset) & 0xFF); |
| offset += 8; |
| paddedByteNum--; |
| } |
| } |
| |
| /** |
| * write long value using special bit to output stream. |
| * |
| * @param value value to write to stream |
| * @param out output stream |
| * @param bitWidth bit length |
| * @throws IOException exception in IO |
| */ |
| public static void writeLongLittleEndianPaddedOnBitWidth( |
| long value, OutputStream out, int bitWidth) throws IOException { |
| int paddedByteNum = (bitWidth + 7) / 8; |
| if (paddedByteNum > 8) { |
| throw new IOException(String.format(TOO_LONG_BYTE_FORMAT, paddedByteNum)); |
| } |
| out.write(BytesUtils.longToBytes(value, paddedByteNum)); |
| } |
| |
| /** |
| * read integer value using special bit from input stream. |
| * |
| * @param buffer byte buffer |
| * @param bitWidth bit length |
| * @return integer value |
| * @throws IOException exception in IO |
| */ |
| public static int readIntLittleEndianPaddedOnBitWidth(ByteBuffer buffer, int bitWidth) |
| throws IOException { |
| int paddedByteNum = (bitWidth + 7) / 8; |
| if (paddedByteNum > 4) { |
| throw new IOException(String.format(TOO_LONG_BYTE_FORMAT, paddedByteNum)); |
| } |
| int result = 0; |
| int offset = 0; |
| while (paddedByteNum > 0) { |
| int ch = ReadWriteIOUtils.read(buffer); |
| result += ch << offset; |
| offset += 8; |
| paddedByteNum--; |
| } |
| return result; |
| } |
| |
| /** |
| * read long value using special bit from input stream. |
| * |
| * @param buffer byte buffer |
| * @param bitWidth bit length |
| * @return long long value |
| * @throws IOException exception in IO |
| */ |
| public static long readLongLittleEndianPaddedOnBitWidth(ByteBuffer buffer, int bitWidth) |
| throws IOException { |
| int paddedByteNum = (bitWidth + 7) / 8; |
| if (paddedByteNum > 8) { |
| throw new IOException(String.format(TOO_LONG_BYTE_FORMAT, paddedByteNum)); |
| } |
| long result = 0; |
| for (int i = 0; i < paddedByteNum; i++) { |
| int ch = ReadWriteIOUtils.read(buffer); |
| result <<= 8; |
| result |= (ch & 0xff); |
| } |
| return result; |
| } |
| } |