| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| #pragma once |
|
|
| #include <atomic> |
| #include <cassert> |
| #include <cstdint> |
| #include <memory> |
| #include <utility> |
| #include <vector> |
|
|
| #include "arrow/array/statistics.h" |
| #include "arrow/buffer.h" |
| #include "arrow/result.h" |
| #include "arrow/type.h" |
| #include "arrow/type_fwd.h" |
| #include "arrow/util/bit_util.h" |
| #include "arrow/util/macros.h" |
| #include "arrow/util/span.h" |
| #include "arrow/util/visibility.h" |
|
|
| namespace arrow { |
|
|
| namespace internal { |
| |
| |
|
|
| ARROW_EXPORT bool IsNullSparseUnion(const ArrayData& data, int64_t i); |
| ARROW_EXPORT bool IsNullDenseUnion(const ArrayData& data, int64_t i); |
| ARROW_EXPORT bool IsNullRunEndEncoded(const ArrayData& data, int64_t i); |
|
|
| ARROW_EXPORT bool UnionMayHaveLogicalNulls(const ArrayData& data); |
| ARROW_EXPORT bool RunEndEncodedMayHaveLogicalNulls(const ArrayData& data); |
| ARROW_EXPORT bool DictionaryMayHaveLogicalNulls(const ArrayData& data); |
|
|
| } |
|
|
| |
| |
| |
| |
| constexpr int64_t kUnknownNullCount = -1; |
|
|
| |
| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| struct ARROW_EXPORT ArrayData { |
| ArrayData() = default; |
|
|
| ArrayData(std::shared_ptr<DataType> type, int64_t length, |
| int64_t null_count = kUnknownNullCount, int64_t offset = 0) |
| : type(std::move(type)), length(length), null_count(null_count), offset(offset) {} |
|
|
| ArrayData(std::shared_ptr<DataType> type, int64_t length, |
| std::vector<std::shared_ptr<Buffer>> buffers, |
| int64_t null_count = kUnknownNullCount, int64_t offset = 0) |
| : ArrayData(std::move(type), length, null_count, offset) { |
| this->buffers = std::move(buffers); |
| #ifndef NDEBUG |
| |
| |
| ARROW_UNUSED(this->device_type()); |
| #endif |
| } |
|
|
| ArrayData(std::shared_ptr<DataType> type, int64_t length, |
| std::vector<std::shared_ptr<Buffer>> buffers, |
| std::vector<std::shared_ptr<ArrayData>> child_data, |
| int64_t null_count = kUnknownNullCount, int64_t offset = 0) |
| : ArrayData(std::move(type), length, null_count, offset) { |
| this->buffers = std::move(buffers); |
| this->child_data = std::move(child_data); |
| #ifndef NDEBUG |
| |
| |
| |
| ARROW_UNUSED(this->device_type()); |
| #endif |
| } |
|
|
| static std::shared_ptr<ArrayData> Make(std::shared_ptr<DataType> type, int64_t length, |
| std::vector<std::shared_ptr<Buffer>> buffers, |
| int64_t null_count = kUnknownNullCount, |
| int64_t offset = 0); |
|
|
| static std::shared_ptr<ArrayData> Make( |
| std::shared_ptr<DataType> type, int64_t length, |
| std::vector<std::shared_ptr<Buffer>> buffers, |
| std::vector<std::shared_ptr<ArrayData>> child_data, |
| int64_t null_count = kUnknownNullCount, int64_t offset = 0); |
|
|
| static std::shared_ptr<ArrayData> Make( |
| std::shared_ptr<DataType> type, int64_t length, |
| std::vector<std::shared_ptr<Buffer>> buffers, |
| std::vector<std::shared_ptr<ArrayData>> child_data, |
| std::shared_ptr<ArrayData> dictionary, int64_t null_count = kUnknownNullCount, |
| int64_t offset = 0); |
|
|
| static std::shared_ptr<ArrayData> Make(std::shared_ptr<DataType> type, int64_t length, |
| int64_t null_count = kUnknownNullCount, |
| int64_t offset = 0); |
|
|
| |
| ArrayData(ArrayData&& other) noexcept |
| : type(std::move(other.type)), |
| length(other.length), |
| null_count(other.null_count.load()), |
| offset(other.offset), |
| buffers(std::move(other.buffers)), |
| child_data(std::move(other.child_data)), |
| dictionary(std::move(other.dictionary)), |
| statistics(std::move(other.statistics)) {} |
|
|
| |
| ArrayData(const ArrayData& other) noexcept |
| : type(other.type), |
| length(other.length), |
| null_count(other.null_count.load()), |
| offset(other.offset), |
| buffers(other.buffers), |
| child_data(other.child_data), |
| dictionary(other.dictionary), |
| statistics(other.statistics) {} |
|
|
| |
| ArrayData& operator=(ArrayData&& other) { |
| type = std::move(other.type); |
| length = other.length; |
| SetNullCount(other.null_count); |
| offset = other.offset; |
| buffers = std::move(other.buffers); |
| child_data = std::move(other.child_data); |
| dictionary = std::move(other.dictionary); |
| statistics = std::move(other.statistics); |
| return *this; |
| } |
|
|
| |
| ArrayData& operator=(const ArrayData& other) { |
| type = other.type; |
| length = other.length; |
| SetNullCount(other.null_count); |
| offset = other.offset; |
| buffers = other.buffers; |
| child_data = other.child_data; |
| dictionary = other.dictionary; |
| statistics = other.statistics; |
| return *this; |
| } |
|
|
| std::shared_ptr<ArrayData> Copy() const { return std::make_shared<ArrayData>(*this); } |
|
|
| |
| |
| |
| |
| |
| Result<std::shared_ptr<ArrayData>> CopyTo( |
| const std::shared_ptr<MemoryManager>& to) const; |
| |
| |
| |
| |
| |
| Result<std::shared_ptr<ArrayData>> ViewOrCopyTo( |
| const std::shared_ptr<MemoryManager>& to) const; |
|
|
| bool IsNull(int64_t i) const { return !IsValid(i); } |
|
|
| bool IsValid(int64_t i) const { |
| if (buffers[0] != NULLPTR) { |
| return bit_util::GetBit(buffers[0]->data(), i + offset); |
| } |
| const auto type = this->type->id(); |
| if (type == Type::SPARSE_UNION) { |
| return !internal::IsNullSparseUnion(*this, i); |
| } |
| if (type == Type::DENSE_UNION) { |
| return !internal::IsNullDenseUnion(*this, i); |
| } |
| if (type == Type::RUN_END_ENCODED) { |
| return !internal::IsNullRunEndEncoded(*this, i); |
| } |
| return null_count.load() != length; |
| } |
|
|
| |
| template <typename T> |
| inline const T* GetValues(int i, int64_t absolute_offset) const { |
| if (buffers[i]) { |
| return reinterpret_cast<const T*>(buffers[i]->data()) + absolute_offset; |
| } else { |
| return NULLPTR; |
| } |
| } |
|
|
| template <typename T> |
| inline const T* GetValues(int i) const { |
| return GetValues<T>(i, offset); |
| } |
|
|
| |
| |
| template <typename T> |
| inline const T* GetValuesSafe(int i, int64_t absolute_offset) const { |
| if (buffers[i] && buffers[i]->is_cpu()) { |
| return reinterpret_cast<const T*>(buffers[i]->data()) + absolute_offset; |
| } else { |
| return NULLPTR; |
| } |
| } |
|
|
| template <typename T> |
| inline const T* GetValuesSafe(int i) const { |
| return GetValuesSafe<T>(i, offset); |
| } |
|
|
| |
| template <typename T> |
| inline T* GetMutableValues(int i, int64_t absolute_offset) { |
| if (buffers[i]) { |
| return reinterpret_cast<T*>(buffers[i]->mutable_data()) + absolute_offset; |
| } else { |
| return NULLPTR; |
| } |
| } |
|
|
| template <typename T> |
| inline T* GetMutableValues(int i) { |
| return GetMutableValues<T>(i, offset); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| std::shared_ptr<ArrayData> Slice(int64_t offset, int64_t length) const; |
|
|
| |
| |
| |
| |
| Result<std::shared_ptr<ArrayData>> SliceSafe(int64_t offset, int64_t length) const; |
|
|
| void SetNullCount(int64_t v) { null_count.store(v); } |
|
|
| |
| int64_t GetNullCount() const; |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| bool MayHaveNulls() const { |
| |
| |
| return null_count.load() != 0 && buffers[0] != NULLPTR; |
| } |
|
|
| |
| bool HasValidityBitmap() const { return buffers[0] != NULLPTR; } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| bool MayHaveLogicalNulls() const { |
| if (buffers[0] != NULLPTR) { |
| return null_count.load() != 0; |
| } |
| const auto t = type->id(); |
| if (t == Type::SPARSE_UNION || t == Type::DENSE_UNION) { |
| return internal::UnionMayHaveLogicalNulls(*this); |
| } |
| if (t == Type::RUN_END_ENCODED) { |
| return internal::RunEndEncodedMayHaveLogicalNulls(*this); |
| } |
| if (t == Type::DICTIONARY) { |
| return internal::DictionaryMayHaveLogicalNulls(*this); |
| } |
| return null_count.load() != 0; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| int64_t ComputeLogicalNullCount() const; |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| DeviceAllocationType device_type() const; |
|
|
| std::shared_ptr<DataType> type; |
| int64_t length = 0; |
| mutable std::atomic<int64_t> null_count{0}; |
| |
| |
| int64_t offset = 0; |
| std::vector<std::shared_ptr<Buffer>> buffers; |
| std::vector<std::shared_ptr<ArrayData>> child_data; |
|
|
| |
| std::shared_ptr<ArrayData> dictionary; |
|
|
| |
| std::shared_ptr<ArrayStatistics> statistics; |
| }; |
|
|
| |
| struct ARROW_EXPORT BufferSpan { |
| |
| |
| |
| uint8_t* data = NULLPTR; |
| int64_t size = 0; |
| |
| const std::shared_ptr<Buffer>* owner = NULLPTR; |
|
|
| template <typename T> |
| const T* data_as() const { |
| return reinterpret_cast<const T*>(data); |
| } |
| template <typename T> |
| T* mutable_data_as() { |
| return reinterpret_cast<T*>(data); |
| } |
| }; |
|
|
| |
| |
| |
| struct ARROW_EXPORT ArraySpan { |
| const DataType* type = NULLPTR; |
| int64_t length = 0; |
| mutable int64_t null_count = kUnknownNullCount; |
| int64_t offset = 0; |
| BufferSpan buffers[3]; |
|
|
| ArraySpan() = default; |
|
|
| explicit ArraySpan(const DataType* type, int64_t length) : type(type), length(length) {} |
|
|
| ArraySpan(const ArrayData& data) { |
| SetMembers(data); |
| } |
| explicit ArraySpan(const Scalar& data) { FillFromScalar(data); } |
|
|
| |
| std::vector<ArraySpan> child_data; |
|
|
| |
| |
| void FillFromScalar(const Scalar& value); |
|
|
| void SetMembers(const ArrayData& data); |
|
|
| void SetBuffer(int index, const std::shared_ptr<Buffer>& buffer) { |
| this->buffers[index].data = const_cast<uint8_t*>(buffer->data()); |
| this->buffers[index].size = buffer->size(); |
| this->buffers[index].owner = &buffer; |
| } |
|
|
| const ArraySpan& dictionary() const { return child_data[0]; } |
|
|
| |
| |
| int num_buffers() const; |
|
|
| |
| template <typename T> |
| inline T* GetValues(int i, int64_t absolute_offset) { |
| return reinterpret_cast<T*>(buffers[i].data) + absolute_offset; |
| } |
|
|
| template <typename T> |
| inline T* GetValues(int i) { |
| return GetValues<T>(i, this->offset); |
| } |
|
|
| |
| template <typename T> |
| inline const T* GetValues(int i, int64_t absolute_offset) const { |
| return reinterpret_cast<const T*>(buffers[i].data) + absolute_offset; |
| } |
|
|
| template <typename T> |
| inline const T* GetValues(int i) const { |
| return GetValues<T>(i, this->offset); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| template <typename T> |
| util::span<const T> GetSpan(int i, int64_t length) const { |
| const int64_t buffer_length = buffers[i].size / static_cast<int64_t>(sizeof(T)); |
| assert(i > 0 && length + offset <= buffer_length); |
| ARROW_UNUSED(buffer_length); |
| return util::span<const T>(buffers[i].data_as<T>() + this->offset, length); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| template <typename T> |
| util::span<T> GetSpan(int i, int64_t length) { |
| const int64_t buffer_length = buffers[i].size / static_cast<int64_t>(sizeof(T)); |
| assert(i > 0 && length + offset <= buffer_length); |
| ARROW_UNUSED(buffer_length); |
| return util::span<T>(buffers[i].mutable_data_as<T>() + this->offset, length); |
| } |
|
|
| inline bool IsNull(int64_t i) const { return !IsValid(i); } |
|
|
| inline bool IsValid(int64_t i) const { |
| if (this->buffers[0].data != NULLPTR) { |
| return bit_util::GetBit(this->buffers[0].data, i + this->offset); |
| } else { |
| const auto type = this->type->id(); |
| if (type == Type::SPARSE_UNION) { |
| return !IsNullSparseUnion(i); |
| } |
| if (type == Type::DENSE_UNION) { |
| return !IsNullDenseUnion(i); |
| } |
| if (type == Type::RUN_END_ENCODED) { |
| return !IsNullRunEndEncoded(i); |
| } |
| return this->null_count != this->length; |
| } |
| } |
|
|
| std::shared_ptr<ArrayData> ToArrayData() const; |
|
|
| std::shared_ptr<Array> ToArray() const; |
|
|
| std::shared_ptr<Buffer> GetBuffer(int index) const { |
| const BufferSpan& buf = this->buffers[index]; |
| if (buf.owner) { |
| return *buf.owner; |
| } else if (buf.data != NULLPTR) { |
| |
| return std::make_shared<Buffer>(buf.data, buf.size); |
| } else { |
| return NULLPTR; |
| } |
| } |
|
|
| void SetSlice(int64_t offset, int64_t length) { |
| this->offset = offset; |
| this->length = length; |
| if (this->type->id() == Type::NA) { |
| this->null_count = this->length; |
| } else if (this->MayHaveNulls()) { |
| this->null_count = kUnknownNullCount; |
| } else { |
| this->null_count = 0; |
| } |
| } |
|
|
| |
| int64_t GetNullCount() const; |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| bool MayHaveNulls() const { |
| |
| |
| return null_count != 0 && buffers[0].data != NULLPTR; |
| } |
|
|
| |
| bool HasValidityBitmap() const { return buffers[0].data != NULLPTR; } |
|
|
| |
| |
| |
| |
| |
| bool MayHaveLogicalNulls() const { |
| if (buffers[0].data != NULLPTR) { |
| return null_count != 0; |
| } |
| const auto t = type->id(); |
| if (t == Type::SPARSE_UNION || t == Type::DENSE_UNION) { |
| return UnionMayHaveLogicalNulls(); |
| } |
| if (t == Type::RUN_END_ENCODED) { |
| return RunEndEncodedMayHaveLogicalNulls(); |
| } |
| if (t == Type::DICTIONARY) { |
| return DictionaryMayHaveLogicalNulls(); |
| } |
| return null_count != 0; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| int64_t ComputeLogicalNullCount() const; |
|
|
| |
| |
| |
| |
| |
| |
| |
| util::span<const std::shared_ptr<Buffer>> GetVariadicBuffers() const; |
| bool HasVariadicBuffers() const; |
|
|
| private: |
| ARROW_FRIEND_EXPORT friend bool internal::IsNullRunEndEncoded(const ArrayData& data, |
| int64_t i); |
|
|
| bool IsNullSparseUnion(int64_t i) const; |
| bool IsNullDenseUnion(int64_t i) const; |
|
|
| |
| |
| |
| |
| |
| |
| bool IsNullRunEndEncoded(int64_t i) const; |
|
|
| bool UnionMayHaveLogicalNulls() const; |
| bool RunEndEncodedMayHaveLogicalNulls() const; |
| bool DictionaryMayHaveLogicalNulls() const; |
| }; |
|
|
| namespace internal { |
|
|
| void FillZeroLengthArray(const DataType* type, ArraySpan* span); |
|
|
| |
| |
| |
| |
| |
| |
| ARROW_EXPORT |
| Result<std::shared_ptr<ArrayData>> GetArrayView(const std::shared_ptr<ArrayData>& data, |
| const std::shared_ptr<DataType>& type); |
|
|
| } |
| } |
|
|