| /* |
| * 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. |
| */ |
| |
| using System; |
| using System.Collections.Generic; |
| using System.IO; |
| using System.Text; |
| |
| namespace Apache.IoTDB.DataStructure |
| { |
| public interface ColumnDecoder |
| { |
| Column ReadColumn(ByteBuffer reader, TSDataType dataType, int positionCount); |
| } |
| |
| public class BaseColumnDecoder |
| { |
| |
| private static Dictionary<ColumnEncoding, ColumnDecoder> decoders = new Dictionary<ColumnEncoding, ColumnDecoder> |
| { |
| { ColumnEncoding.Int32Array, new Int32ArrayColumnDecoder() }, |
| { ColumnEncoding.Int64Array, new Int64ArrayColumnDecoder() }, |
| { ColumnEncoding.ByteArray, new ByteArrayColumnDecoder() }, |
| { ColumnEncoding.BinaryArray, new BinaryArrayColumnDecoder() }, |
| { ColumnEncoding.Rle, new RunLengthColumnDecoder() } |
| }; |
| |
| public static ColumnDecoder GetDecoder(ColumnEncoding encoding) |
| { |
| if (decoders.TryGetValue(encoding, out var decoder)) |
| return decoder; |
| throw new ArgumentException($"Unsupported encoding: {encoding}"); |
| } |
| |
| public static ColumnEncoding DeserializeColumnEncoding(ByteBuffer reader) |
| { |
| return (ColumnEncoding)reader.GetByte(); |
| } |
| } |
| |
| public static class ColumnDeserializer |
| { |
| public static bool[] DeserializeNullIndicators(ByteBuffer reader, int positionCount) |
| { |
| byte b = reader.GetByte(); |
| bool mayHaveNull = b != 0; |
| if (!mayHaveNull) |
| return null; |
| return DeserializeBooleanArray(reader, positionCount); |
| } |
| |
| public static bool[] DeserializeBooleanArray(ByteBuffer reader, int size) |
| { |
| int packedSize = (size + 7) / 8; |
| byte[] packedBytes = reader.GetBytesByLength(packedSize); |
| if (packedBytes.Length < packedSize) |
| throw new InvalidDataException( |
| $"Boolean array decoding failed: expected {packedSize} bytes for {size} bits, but only received {packedBytes.Length} bytes from buffer." |
| ); |
| bool[] output = new bool[size]; |
| int currentByte = 0; |
| int fullGroups = size & ~0b111; |
| |
| for (int pos = 0; pos < fullGroups; pos += 8) |
| { |
| byte b = packedBytes[currentByte++]; |
| output[pos + 0] = (b & 0b10000000) != 0; |
| output[pos + 1] = (b & 0b01000000) != 0; |
| output[pos + 2] = (b & 0b00100000) != 0; |
| output[pos + 3] = (b & 0b00010000) != 0; |
| output[pos + 4] = (b & 0b00001000) != 0; |
| output[pos + 5] = (b & 0b00000100) != 0; |
| output[pos + 6] = (b & 0b00000010) != 0; |
| output[pos + 7] = (b & 0b00000001) != 0; |
| } |
| |
| if (size % 8 != 0) |
| { |
| byte b = packedBytes[packedSize - 1]; |
| byte mask = 0b10000000; |
| for (int pos = fullGroups; pos < size; pos++) |
| { |
| output[pos] = (b & mask) != 0; |
| mask >>= 1; |
| } |
| } |
| |
| return output; |
| } |
| } |
| |
| public class Int32ArrayColumnDecoder : ColumnDecoder |
| { |
| public Column ReadColumn(ByteBuffer reader, TSDataType dataType, int positionCount) |
| { |
| bool[] nullIndicators = ColumnDeserializer.DeserializeNullIndicators(reader, positionCount); |
| |
| switch (dataType) |
| { |
| case TSDataType.INT32: |
| case TSDataType.DATE: |
| int[] intValues = new int[positionCount]; |
| for (int i = 0; i < positionCount; i++) |
| { |
| if (nullIndicators != null && nullIndicators[i]) |
| continue; |
| intValues[i] = reader.GetInt(); |
| } |
| return new IntColumn(0, positionCount, nullIndicators, intValues); |
| case TSDataType.FLOAT: |
| float[] floatValues = new float[positionCount]; |
| for (int i = 0; i < positionCount; i++) |
| { |
| if (nullIndicators != null && nullIndicators[i]) |
| continue; |
| floatValues[i] = reader.GetFloat(); |
| } |
| return new FloatColumn(0, positionCount, nullIndicators, floatValues); |
| default: |
| throw new ArgumentException($"Invalid data type: {dataType}"); |
| } |
| } |
| } |
| |
| public class Int64ArrayColumnDecoder : ColumnDecoder |
| { |
| public Column ReadColumn(ByteBuffer reader, TSDataType dataType, int positionCount) |
| { |
| bool[] nullIndicators = ColumnDeserializer.DeserializeNullIndicators(reader, positionCount); |
| |
| switch (dataType) |
| { |
| case TSDataType.INT64: |
| case TSDataType.TIMESTAMP: |
| long[] longValues = new long[positionCount]; |
| for (int i = 0; i < positionCount; i++) |
| { |
| if (nullIndicators != null && nullIndicators[i]) |
| continue; |
| longValues[i] = reader.GetLong(); |
| } |
| return new LongColumn(0, positionCount, nullIndicators, longValues); |
| case TSDataType.DOUBLE: |
| double[] doubleValues = new double[positionCount]; |
| for (int i = 0; i < positionCount; i++) |
| { |
| if (nullIndicators != null && nullIndicators[i]) |
| continue; |
| doubleValues[i] = reader.GetDouble(); |
| } |
| return new DoubleColumn(0, positionCount, nullIndicators, doubleValues); |
| default: |
| throw new ArgumentException($"Invalid data type: {dataType}"); |
| } |
| } |
| } |
| |
| public class ByteArrayColumnDecoder : ColumnDecoder |
| { |
| public Column ReadColumn(ByteBuffer reader, TSDataType dataType, int positionCount) |
| { |
| if (dataType != TSDataType.BOOLEAN) |
| throw new ArgumentException($"Invalid data type: {dataType}"); |
| |
| bool[] nullIndicators = ColumnDeserializer.DeserializeNullIndicators(reader, positionCount); |
| bool[] values = ColumnDeserializer.DeserializeBooleanArray(reader, positionCount); |
| return new BooleanColumn(0, positionCount, nullIndicators, values); |
| } |
| } |
| |
| public class BinaryArrayColumnDecoder : ColumnDecoder |
| { |
| public Column ReadColumn(ByteBuffer reader, TSDataType dataType, int positionCount) |
| { |
| if (dataType != TSDataType.TEXT) |
| throw new ArgumentException($"Invalid data type: {dataType}"); |
| |
| bool[] nullIndicators = ColumnDeserializer.DeserializeNullIndicators(reader, positionCount); |
| Binary[] values = new Binary[positionCount]; |
| |
| for (int i = 0; i < positionCount; i++) |
| { |
| if (nullIndicators != null && nullIndicators[i]) |
| continue; |
| int length = reader.GetInt(); |
| byte[] value = reader.GetBytesByLength(length); |
| values[i] = new Binary(value); |
| } |
| |
| return new BinaryColumn(0, positionCount, nullIndicators, values); |
| } |
| } |
| |
| public class RunLengthColumnDecoder : ColumnDecoder |
| { |
| public Column ReadColumn(ByteBuffer reader, TSDataType dataType, int positionCount) |
| { |
| ColumnEncoding encoding = BaseColumnDecoder.DeserializeColumnEncoding(reader); |
| ColumnDecoder decoder = BaseColumnDecoder.GetDecoder(encoding); |
| Column column = decoder.ReadColumn(reader, dataType, 1); |
| return new RunLengthEncodedColumn(column, positionCount); |
| } |
| } |
| } |