| /* | |
| * 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. | |
| */ | |
| #include "paimon/common/data/binary_array.h" | |
| #include <cassert> | |
| #include <cstddef> | |
| #include <utility> | |
| #include "paimon/common/data/binary_array_writer.h" | |
| #include "paimon/common/data/binary_data_read_utils.h" | |
| #include "paimon/memory/memory_pool.h" | |
| #include "paimon/memory/memory_segment.h" | |
| namespace paimon { | |
| int32_t BinaryArray::CalculateHeaderInBytes(int32_t num_fields) { | |
| return 4 + ((num_fields + 31) / 32) * 4; | |
| } | |
| void BinaryArray::AssertIndexIsValid(int32_t ordinal) const { | |
| assert(ordinal >= 0); | |
| assert(ordinal < size_); | |
| } | |
| int32_t BinaryArray::GetElementOffset(int32_t ordinal, int32_t element_size) const { | |
| return element_offset_ + ordinal * element_size; | |
| } | |
| void BinaryArray::PointTo(const MemorySegment& segment, int32_t offset, int32_t size_in_bytes) { | |
| auto size = MemorySegmentUtils::GetValue<int32_t>({segment}, offset); | |
| assert(size >= 0); | |
| size_ = size; | |
| segment_ = segment; | |
| offset_ = offset; | |
| size_in_bytes_ = size_in_bytes; | |
| element_offset_ = offset_ + CalculateHeaderInBytes(size_); | |
| } | |
| bool BinaryArray::IsNullAt(int32_t pos) const { | |
| AssertIndexIsValid(pos); | |
| return MemorySegmentUtils::BitGet({segment_}, offset_ + 4, pos); | |
| } | |
| int64_t BinaryArray::GetLong(int32_t pos) const { | |
| AssertIndexIsValid(pos); | |
| return MemorySegmentUtils::GetValue<int64_t>({segment_}, GetElementOffset(pos, 8)); | |
| } | |
| int32_t BinaryArray::GetInt(int32_t pos) const { | |
| AssertIndexIsValid(pos); | |
| return MemorySegmentUtils::GetValue<int32_t>({segment_}, GetElementOffset(pos, 4)); | |
| } | |
| int32_t BinaryArray::GetDate(int32_t pos) const { | |
| return GetInt(pos); | |
| } | |
| BinaryString BinaryArray::GetString(int32_t pos) const { | |
| AssertIndexIsValid(pos); | |
| int32_t field_offset = GetElementOffset(pos, 8); | |
| const auto offset_and_size = MemorySegmentUtils::GetValue<int64_t>({segment_}, field_offset); | |
| return BinaryDataReadUtils::ReadBinaryString(segment_, offset_, field_offset, offset_and_size); | |
| } | |
| std::string_view BinaryArray::GetStringView(int32_t pos) const { | |
| BinaryString binary_string = GetString(pos); | |
| return binary_string.GetStringView(); | |
| } | |
| Decimal BinaryArray::GetDecimal(int32_t pos, int32_t precision, int32_t scale) const { | |
| AssertIndexIsValid(pos); | |
| if (Decimal::IsCompact(precision)) { | |
| return Decimal::FromUnscaledLong( | |
| MemorySegmentUtils::GetValue<int64_t>({segment_}, GetElementOffset(pos, 8)), precision, | |
| scale); | |
| } | |
| int32_t field_offset = GetElementOffset(pos, 8); | |
| const auto offset_and_size = MemorySegmentUtils::GetValue<int64_t>({segment_}, field_offset); | |
| return BinaryDataReadUtils::ReadDecimal(segment_, offset_, offset_and_size, precision, scale); | |
| } | |
| Timestamp BinaryArray::GetTimestamp(int32_t pos, int32_t precision) const { | |
| AssertIndexIsValid(pos); | |
| if (Timestamp::IsCompact(precision)) { | |
| return Timestamp::FromEpochMillis( | |
| MemorySegmentUtils::GetValue<int64_t>({segment_}, GetElementOffset(pos, 8))); | |
| } | |
| int32_t field_offset = GetElementOffset(pos, 8); | |
| const auto offset_and_nano_of_milli = | |
| MemorySegmentUtils::GetValue<int64_t>({segment_}, field_offset); | |
| return BinaryDataReadUtils::ReadTimestampData(segment_, offset_, offset_and_nano_of_milli); | |
| } | |
| std::shared_ptr<Bytes> BinaryArray::GetBinary(int32_t pos) const { | |
| AssertIndexIsValid(pos); | |
| int32_t field_offset = GetElementOffset(pos, 8); | |
| const auto offset_and_size = MemorySegmentUtils::GetValue<int64_t>({segment_}, field_offset); | |
| return BinarySection::ReadBinary(segment_, offset_, field_offset, offset_and_size, | |
| GetDefaultPool().get()); | |
| } | |
| std::shared_ptr<InternalArray> BinaryArray::GetArray(int32_t pos) const { | |
| AssertIndexIsValid(pos); | |
| return BinaryDataReadUtils::ReadArrayData(segment_, offset_, GetLong(pos)); | |
| } | |
| std::shared_ptr<InternalMap> BinaryArray::GetMap(int32_t pos) const { | |
| AssertIndexIsValid(pos); | |
| return BinaryDataReadUtils::ReadMapData(segment_, offset_, GetLong(pos)); | |
| } | |
| std::shared_ptr<InternalRow> BinaryArray::GetRow(int32_t pos, int32_t num_fields) const { | |
| AssertIndexIsValid(pos); | |
| int32_t field_offset = GetElementOffset(pos, 8); | |
| const auto offset_and_size = MemorySegmentUtils::GetValue<int64_t>({segment_}, field_offset); | |
| return BinaryDataReadUtils::ReadRowData(segment_, num_fields, offset_, offset_and_size); | |
| } | |
| bool BinaryArray::GetBoolean(int32_t pos) const { | |
| AssertIndexIsValid(pos); | |
| return MemorySegmentUtils::GetValue<bool>({segment_}, GetElementOffset(pos, 1)); | |
| } | |
| char BinaryArray::GetByte(int32_t pos) const { | |
| AssertIndexIsValid(pos); | |
| return MemorySegmentUtils::GetValue<char>({segment_}, GetElementOffset(pos, 1)); | |
| } | |
| int16_t BinaryArray::GetShort(int32_t pos) const { | |
| AssertIndexIsValid(pos); | |
| return MemorySegmentUtils::GetValue<int16_t>({segment_}, | |
| GetElementOffset(pos, sizeof(int16_t))); | |
| } | |
| float BinaryArray::GetFloat(int32_t pos) const { | |
| AssertIndexIsValid(pos); | |
| return MemorySegmentUtils::GetValue<float>({segment_}, GetElementOffset(pos, sizeof(float))); | |
| } | |
| double BinaryArray::GetDouble(int32_t pos) const { | |
| AssertIndexIsValid(pos); | |
| return MemorySegmentUtils::GetValue<double>({segment_}, GetElementOffset(pos, sizeof(double))); | |
| } | |
| bool BinaryArray::AnyNull() const { | |
| for (int32_t i = offset_ + 4; i < element_offset_; i += 4) { | |
| if (MemorySegmentUtils::GetValue<int32_t>({segment_}, i) != 0) { | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| Result<std::vector<char>> BinaryArray::ToBooleanArray() const { | |
| PAIMON_RETURN_NOT_OK(CheckNoNull()); | |
| std::vector<char> values; | |
| values.resize(size_); | |
| MemorySegmentUtils::CopyToUnsafe({segment_}, element_offset_, | |
| const_cast<void*>(static_cast<const void*>(values.data())), | |
| size_); | |
| return values; | |
| } | |
| Result<std::vector<char>> BinaryArray::ToByteArray() const { | |
| PAIMON_RETURN_NOT_OK(CheckNoNull()); | |
| std::vector<char> values; | |
| values.resize(size_); | |
| MemorySegmentUtils::CopyToUnsafe({segment_}, element_offset_, | |
| const_cast<void*>(static_cast<const void*>(values.data())), | |
| size_); | |
| return values; | |
| } | |
| Result<std::vector<int16_t>> BinaryArray::ToShortArray() const { | |
| PAIMON_RETURN_NOT_OK(CheckNoNull()); | |
| std::vector<int16_t> values; | |
| values.resize(size_); | |
| MemorySegmentUtils::CopyToUnsafe({segment_}, element_offset_, | |
| const_cast<void*>(static_cast<const void*>(values.data())), | |
| size_ * sizeof(int16_t)); | |
| return values; | |
| } | |
| Result<std::vector<int32_t>> BinaryArray::ToIntArray() const { | |
| PAIMON_RETURN_NOT_OK(CheckNoNull()); | |
| std::vector<int32_t> values; | |
| values.resize(size_); | |
| MemorySegmentUtils::CopyToUnsafe({segment_}, element_offset_, | |
| const_cast<void*>(static_cast<const void*>(values.data())), | |
| size_ * sizeof(int32_t)); | |
| return values; | |
| } | |
| Result<std::vector<int64_t>> BinaryArray::ToLongArray() const { | |
| PAIMON_RETURN_NOT_OK(CheckNoNull()); | |
| std::vector<int64_t> values; | |
| values.resize(size_); | |
| MemorySegmentUtils::CopyToUnsafe({segment_}, element_offset_, | |
| const_cast<void*>(static_cast<const void*>(values.data())), | |
| size_ * sizeof(int64_t)); | |
| return values; | |
| } | |
| Result<std::vector<float>> BinaryArray::ToFloatArray() const { | |
| PAIMON_RETURN_NOT_OK(CheckNoNull()); | |
| std::vector<float> values; | |
| values.resize(size_); | |
| MemorySegmentUtils::CopyToUnsafe({segment_}, element_offset_, | |
| const_cast<void*>(static_cast<const void*>(values.data())), | |
| size_ * sizeof(float)); | |
| return values; | |
| } | |
| Result<std::vector<double>> BinaryArray::ToDoubleArray() const { | |
| PAIMON_RETURN_NOT_OK(CheckNoNull()); | |
| std::vector<double> values; | |
| values.resize(size_); | |
| MemorySegmentUtils::CopyToUnsafe({segment_}, element_offset_, | |
| const_cast<void*>(static_cast<const void*>(values.data())), | |
| size_ * sizeof(double)); | |
| return values; | |
| } | |
| BinaryArray BinaryArray::Copy(MemoryPool* pool) const { | |
| BinaryArray array; | |
| Copy(&array, pool); | |
| return array; | |
| } | |
| void BinaryArray::Copy(BinaryArray* reuse, MemoryPool* pool) const { | |
| std::shared_ptr<Bytes> bytes = | |
| MemorySegmentUtils::CopyToBytes({segment_}, offset_, size_in_bytes_, pool); | |
| reuse->PointTo(MemorySegment::Wrap(bytes), 0, size_in_bytes_); | |
| } | |
| BinaryArray BinaryArray::FromIntArray(const std::vector<int32_t>& arr, MemoryPool* pool) { | |
| BinaryArray array; | |
| BinaryArrayWriter writer = BinaryArrayWriter(&array, arr.size(), sizeof(int32_t), pool); | |
| for (size_t i = 0; i < arr.size(); i++) { | |
| int32_t v = arr[i]; | |
| writer.WriteInt(i, v); | |
| } | |
| writer.Complete(); | |
| return array; | |
| } | |
| BinaryArray BinaryArray::FromLongArray(const std::vector<int64_t>& arr, MemoryPool* pool) { | |
| BinaryArray array; | |
| BinaryArrayWriter writer = BinaryArrayWriter(&array, arr.size(), sizeof(int64_t), pool); | |
| for (size_t i = 0; i < arr.size(); i++) { | |
| int64_t v = arr[i]; | |
| writer.WriteLong(i, v); | |
| } | |
| writer.Complete(); | |
| return array; | |
| } | |
| BinaryArray BinaryArray::FromLongArray(const InternalArray* arr, MemoryPool* pool) { | |
| assert(arr); | |
| auto cast_array = dynamic_cast<const BinaryArray*>(arr); | |
| if (cast_array) { | |
| return *cast_array; | |
| } | |
| BinaryArray array; | |
| BinaryArrayWriter writer = BinaryArrayWriter(&array, arr->Size(), 8, pool); | |
| std::vector<bool> is_null(arr->Size(), false); | |
| // accessing the null bit first makes memory access more concentrated | |
| for (int32_t i = 0; i < arr->Size(); i++) { | |
| is_null[i] = arr->IsNullAt(i); | |
| } | |
| for (int32_t i = 0; i < arr->Size(); i++) { | |
| if (is_null[i]) { | |
| writer.SetNullValue<int64_t>(i); | |
| } else { | |
| writer.WriteLong(i, arr->GetLong(i)); | |
| } | |
| } | |
| writer.Complete(); | |
| return array; | |
| } | |
| } // namespace paimon |