blob: f1267b548e14e3ed360b39d5d46fb7ff77e1c66b [file] [log] [blame]
/*
* 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);
}
}
}