Consolidate Array and Builder classes in array.h, builder.h. Remove arrow/types subdirectory

Change-Id: I1d84f714b02a2e1abc0171663ca183b682be5907
This commit is contained in:
Wes McKinney committed 2016-12-12 13:01:22 -05:00
1 parent 73fe55683c
commit 8cdf059d5d
43 files changed
+1506 -2035

No files matched your search

-9
View File
@@ -750,14 +750,6 @@ set(ARROW_SRCS
src/arrow/table.cc
src/arrow/type.cc
src/arrow/types/construct.cc
src/arrow/types/decimal.cc
src/arrow/types/list.cc
src/arrow/types/primitive.cc
src/arrow/types/string.cc
src/arrow/types/struct.cc
src/arrow/types/union.cc
src/arrow/util/bit-util.cc
src/arrow/util/buffer.cc
src/arrow/util/memory-pool.cc
@@ -823,7 +815,6 @@ endif()
add_subdirectory(src/arrow)
add_subdirectory(src/arrow/io)
add_subdirectory(src/arrow/util)
add_subdirectory(src/arrow/types)
#----------------------------------------------------------------------
# IPC library
+6
View File
@@ -37,6 +37,12 @@ install(FILES
set(ARROW_TEST_LINK_LIBS ${ARROW_MIN_TEST_LIBS})
ADD_ARROW_TEST(array-test)
ADD_ARROW_TEST(array-decimal-test)
ADD_ARROW_TEST(array-list-test)
ADD_ARROW_TEST(array-primitive-test)
ADD_ARROW_TEST(array-string-test)
ADD_ARROW_TEST(array-struct-test)
ADD_ARROW_TEST(column-test)
ADD_ARROW_TEST(pretty_print-test)
ADD_ARROW_TEST(schema-test)
-6
View File
@@ -27,12 +27,6 @@
#include "arrow/table.h"
#include "arrow/type.h"
#include "arrow/types/construct.h"
#include "arrow/types/list.h"
#include "arrow/types/primitive.h"
#include "arrow/types/string.h"
#include "arrow/types/struct.h"
#include "arrow/util/buffer.h"
#include "arrow/util/memory-pool.h"
#include "arrow/util/status.h"
@@ -17,7 +17,7 @@
#include "gtest/gtest.h"
#include "arrow/types/decimal.h"
#include "arrow/type.h"
namespace arrow {
@@ -27,10 +27,6 @@
#include "arrow/builder.h"
#include "arrow/test-util.h"
#include "arrow/type.h"
#include "arrow/types/construct.h"
#include "arrow/types/list.h"
#include "arrow/types/primitive.h"
#include "arrow/types/test-common.h"
#include "arrow/util/status.h"
using std::shared_ptr;
@@ -22,13 +22,11 @@
#include "gtest/gtest.h"
#include "arrow/array.h"
#include "arrow/builder.h"
#include "arrow/test-util.h"
#include "arrow/type.h"
#include "arrow/type_traits.h"
#include "arrow/types/construct.h"
#include "arrow/types/primitive.h"
#include "arrow/types/test-common.h"
#include "arrow/util/bit-util.h"
#include "arrow/util/buffer.h"
#include "arrow/util/status.h"
@@ -24,11 +24,9 @@
#include "gtest/gtest.h"
#include "arrow/array.h"
#include "arrow/builder.h"
#include "arrow/test-util.h"
#include "arrow/type.h"
#include "arrow/types/primitive.h"
#include "arrow/types/string.h"
#include "arrow/types/test-common.h"
namespace arrow {
@@ -25,11 +25,6 @@
#include "arrow/builder.h"
#include "arrow/test-util.h"
#include "arrow/type.h"
#include "arrow/types/construct.h"
#include "arrow/types/list.h"
#include "arrow/types/primitive.h"
#include "arrow/types/struct.h"
#include "arrow/types/test-common.h"
#include "arrow/util/status.h"
using std::shared_ptr;
-1
View File
@@ -26,7 +26,6 @@
#include "arrow/array.h"
#include "arrow/test-util.h"
#include "arrow/type.h"
#include "arrow/types/primitive.h"
#include "arrow/util/buffer.h"
#include "arrow/util/memory-pool.h"
+439
View File
@@ -19,9 +19,12 @@
#include <cstdint>
#include <cstring>
#include <sstream>
#include "arrow/type_traits.h"
#include "arrow/util/bit-util.h"
#include "arrow/util/buffer.h"
#include "arrow/util/logging.h"
#include "arrow/util/status.h"
namespace arrow {
@@ -85,4 +88,440 @@ Status NullArray::Accept(ArrayVisitor* visitor) const {
return visitor->Visit(*this);
}
// ----------------------------------------------------------------------
// Primitive array base
PrimitiveArray::PrimitiveArray(const TypePtr& type, int32_t length,
const std::shared_ptr<Buffer>& data, int32_t null_count,
const std::shared_ptr<Buffer>& null_bitmap)
: Array(type, length, null_count, null_bitmap) {
data_ = data;
raw_data_ = data == nullptr ? nullptr : data_->data();
}
bool PrimitiveArray::EqualsExact(const PrimitiveArray& other) const {
if (this == &other) { return true; }
if (null_count_ != other.null_count_) { return false; }
if (null_count_ > 0) {
bool equal_bitmap =
null_bitmap_->Equals(*other.null_bitmap_, BitUtil::CeilByte(length_) / 8);
if (!equal_bitmap) { return false; }
const uint8_t* this_data = raw_data_;
const uint8_t* other_data = other.raw_data_;
auto size_meta = dynamic_cast<const FixedWidthType*>(type_.get());
int value_byte_size = size_meta->bit_width() / 8;
DCHECK_GT(value_byte_size, 0);
for (int i = 0; i < length_; ++i) {
if (!IsNull(i) && memcmp(this_data, other_data, value_byte_size)) { return false; }
this_data += value_byte_size;
other_data += value_byte_size;
}
return true;
} else {
if (length_ == 0 && other.length_ == 0) { return true; }
return data_->Equals(*other.data_, length_);
}
}
bool PrimitiveArray::Equals(const std::shared_ptr<Array>& arr) const {
if (this == arr.get()) { return true; }
if (!arr) { return false; }
if (this->type_enum() != arr->type_enum()) { return false; }
return EqualsExact(*static_cast<const PrimitiveArray*>(arr.get()));
}
template <typename T>
Status NumericArray<T>::Accept(ArrayVisitor* visitor) const {
return visitor->Visit(*this);
}
template class NumericArray<UInt8Type>;
template class NumericArray<UInt16Type>;
template class NumericArray<UInt32Type>;
template class NumericArray<UInt64Type>;
template class NumericArray<Int8Type>;
template class NumericArray<Int16Type>;
template class NumericArray<Int32Type>;
template class NumericArray<Int64Type>;
template class NumericArray<TimestampType>;
template class NumericArray<HalfFloatType>;
template class NumericArray<FloatType>;
template class NumericArray<DoubleType>;
// ----------------------------------------------------------------------
// BooleanArray
BooleanArray::BooleanArray(int32_t length, const std::shared_ptr<Buffer>& data,
int32_t null_count, const std::shared_ptr<Buffer>& null_bitmap)
: PrimitiveArray(
std::make_shared<BooleanType>(), length, data, null_count, null_bitmap) {}
BooleanArray::BooleanArray(const TypePtr& type, int32_t length,
const std::shared_ptr<Buffer>& data, int32_t null_count,
const std::shared_ptr<Buffer>& null_bitmap)
: PrimitiveArray(type, length, data, null_count, null_bitmap) {}
bool BooleanArray::EqualsExact(const BooleanArray& other) const {
if (this == &other) return true;
if (null_count_ != other.null_count_) { return false; }
if (null_count_ > 0) {
bool equal_bitmap =
null_bitmap_->Equals(*other.null_bitmap_, BitUtil::BytesForBits(length_));
if (!equal_bitmap) { return false; }
const uint8_t* this_data = raw_data_;
const uint8_t* other_data = other.raw_data_;
for (int i = 0; i < length_; ++i) {
if (!IsNull(i) && BitUtil::GetBit(this_data, i) != BitUtil::GetBit(other_data, i)) {
return false;
}
}
return true;
} else {
return data_->Equals(*other.data_, BitUtil::BytesForBits(length_));
}
}
bool BooleanArray::Equals(const ArrayPtr& arr) const {
if (this == arr.get()) return true;
if (Type::BOOL != arr->type_enum()) { return false; }
return EqualsExact(*static_cast<const BooleanArray*>(arr.get()));
}
bool BooleanArray::RangeEquals(int32_t start_idx, int32_t end_idx,
int32_t other_start_idx, const ArrayPtr& arr) const {
if (this == arr.get()) { return true; }
if (!arr) { return false; }
if (this->type_enum() != arr->type_enum()) { return false; }
const auto other = static_cast<BooleanArray*>(arr.get());
for (int32_t i = start_idx, o_i = other_start_idx; i < end_idx; ++i, ++o_i) {
const bool is_null = IsNull(i);
if (is_null != arr->IsNull(o_i) || (!is_null && Value(i) != other->Value(o_i))) {
return false;
}
}
return true;
}
Status BooleanArray::Accept(ArrayVisitor* visitor) const {
return visitor->Visit(*this);
}
// ----------------------------------------------------------------------
// ListArray
bool ListArray::EqualsExact(const ListArray& other) const {
if (this == &other) { return true; }
if (null_count_ != other.null_count_) { return false; }
bool equal_offsets =
offset_buffer_->Equals(*other.offset_buffer_, (length_ + 1) * sizeof(int32_t));
if (!equal_offsets) { return false; }
bool equal_null_bitmap = true;
if (null_count_ > 0) {
equal_null_bitmap =
null_bitmap_->Equals(*other.null_bitmap_, BitUtil::BytesForBits(length_));
}
if (!equal_null_bitmap) { return false; }
return values()->Equals(other.values());
}
bool ListArray::Equals(const std::shared_ptr<Array>& arr) const {
if (this == arr.get()) { return true; }
if (this->type_enum() != arr->type_enum()) { return false; }
return EqualsExact(*static_cast<const ListArray*>(arr.get()));
}
bool ListArray::RangeEquals(int32_t start_idx, int32_t end_idx, int32_t other_start_idx,
const std::shared_ptr<Array>& arr) const {
if (this == arr.get()) { return true; }
if (!arr) { return false; }
if (this->type_enum() != arr->type_enum()) { return false; }
const auto other = static_cast<ListArray*>(arr.get());
for (int32_t i = start_idx, o_i = other_start_idx; i < end_idx; ++i, ++o_i) {
const bool is_null = IsNull(i);
if (is_null != arr->IsNull(o_i)) { return false; }
if (is_null) continue;
const int32_t begin_offset = offset(i);
const int32_t end_offset = offset(i + 1);
const int32_t other_begin_offset = other->offset(o_i);
const int32_t other_end_offset = other->offset(o_i + 1);
// Underlying can't be equal if the size isn't equal
if (end_offset - begin_offset != other_end_offset - other_begin_offset) {
return false;
}
if (!values_->RangeEquals(
begin_offset, end_offset, other_begin_offset, other->values())) {
return false;
}
}
return true;
}
Status ListArray::Validate() const {
if (length_ < 0) { return Status::Invalid("Length was negative"); }
if (!offset_buffer_) { return Status::Invalid("offset_buffer_ was null"); }
if (offset_buffer_->size() / static_cast<int>(sizeof(int32_t)) < length_) {
std::stringstream ss;
ss << "offset buffer size (bytes): " << offset_buffer_->size()
<< " isn't large enough for length: " << length_;
return Status::Invalid(ss.str());
}
const int32_t last_offset = offset(length_);
if (last_offset > 0) {
if (!values_) {
return Status::Invalid("last offset was non-zero and values was null");
}
if (values_->length() != last_offset) {
std::stringstream ss;
ss << "Final offset invariant not equal to values length: " << last_offset
<< "!=" << values_->length();
return Status::Invalid(ss.str());
}
const Status child_valid = values_->Validate();
if (!child_valid.ok()) {
std::stringstream ss;
ss << "Child array invalid: " << child_valid.ToString();
return Status::Invalid(ss.str());
}
}
int32_t prev_offset = offset(0);
if (prev_offset != 0) { return Status::Invalid("The first offset wasn't zero"); }
for (int32_t i = 1; i <= length_; ++i) {
int32_t current_offset = offset(i);
if (IsNull(i - 1) && current_offset != prev_offset) {
std::stringstream ss;
ss << "Offset invariant failure at: " << i << " inconsistent offsets for null slot"
<< current_offset << "!=" << prev_offset;
return Status::Invalid(ss.str());
}
if (current_offset < prev_offset) {
std::stringstream ss;
ss << "Offset invariant failure: " << i
<< " inconsistent offset for non-null slot: " << current_offset << "<"
<< prev_offset;
return Status::Invalid(ss.str());
}
prev_offset = current_offset;
}
return Status::OK();
}
Status ListArray::Accept(ArrayVisitor* visitor) const {
return visitor->Visit(*this);
}
// ----------------------------------------------------------------------
// String and binary
static std::shared_ptr<DataType> kBinary = std::make_shared<BinaryType>();
static std::shared_ptr<DataType> kString = std::make_shared<StringType>();
BinaryArray::BinaryArray(int32_t length, const std::shared_ptr<Buffer>& offsets,
const std::shared_ptr<Buffer>& data, int32_t null_count,
const std::shared_ptr<Buffer>& null_bitmap)
: BinaryArray(kBinary, length, offsets, data, null_count, null_bitmap) {}
BinaryArray::BinaryArray(const TypePtr& type, int32_t length,
const std::shared_ptr<Buffer>& offsets, const std::shared_ptr<Buffer>& data,
int32_t null_count, const std::shared_ptr<Buffer>& null_bitmap)
: Array(type, length, null_count, null_bitmap),
offset_buffer_(offsets),
offsets_(reinterpret_cast<const int32_t*>(offset_buffer_->data())),
data_buffer_(data),
data_(nullptr) {
if (data_buffer_ != nullptr) { data_ = data_buffer_->data(); }
}
Status BinaryArray::Validate() const {
// TODO(wesm): what to do here?
return Status::OK();
}
bool BinaryArray::EqualsExact(const BinaryArray& other) const {
if (!Array::EqualsExact(other)) { return false; }
bool equal_offsets =
offset_buffer_->Equals(*other.offset_buffer_, (length_ + 1) * sizeof(int32_t));
if (!equal_offsets) { return false; }
if (!data_buffer_ && !(other.data_buffer_)) { return true; }
return data_buffer_->Equals(*other.data_buffer_, data_buffer_->size());
}
bool BinaryArray::Equals(const std::shared_ptr<Array>& arr) const {
if (this == arr.get()) { return true; }
if (this->type_enum() != arr->type_enum()) { return false; }
return EqualsExact(*static_cast<const BinaryArray*>(arr.get()));
}
bool BinaryArray::RangeEquals(int32_t start_idx, int32_t end_idx, int32_t other_start_idx,
const std::shared_ptr<Array>& arr) const {
if (this == arr.get()) { return true; }
if (!arr) { return false; }
if (this->type_enum() != arr->type_enum()) { return false; }
const auto other = static_cast<const BinaryArray*>(arr.get());
for (int32_t i = start_idx, o_i = other_start_idx; i < end_idx; ++i, ++o_i) {
const bool is_null = IsNull(i);
if (is_null != arr->IsNull(o_i)) { return false; }
if (is_null) continue;
const int32_t begin_offset = offset(i);
const int32_t end_offset = offset(i + 1);
const int32_t other_begin_offset = other->offset(o_i);
const int32_t other_end_offset = other->offset(o_i + 1);
// Underlying can't be equal if the size isn't equal
if (end_offset - begin_offset != other_end_offset - other_begin_offset) {
return false;
}
if (std::memcmp(data_ + begin_offset, other->data_ + other_begin_offset,
end_offset - begin_offset)) {
return false;
}
}
return true;
}
Status BinaryArray::Accept(ArrayVisitor* visitor) const {
return visitor->Visit(*this);
}
StringArray::StringArray(int32_t length, const std::shared_ptr<Buffer>& offsets,
const std::shared_ptr<Buffer>& data, int32_t null_count,
const std::shared_ptr<Buffer>& null_bitmap)
: BinaryArray(kString, length, offsets, data, null_count, null_bitmap) {}
Status StringArray::Validate() const {
// TODO(emkornfield) Validate proper UTF8 code points?
return BinaryArray::Validate();
}
Status StringArray::Accept(ArrayVisitor* visitor) const {
return visitor->Visit(*this);
}
// ----------------------------------------------------------------------
// Struct
std::shared_ptr<Array> StructArray::field(int32_t pos) const {
DCHECK_GT(field_arrays_.size(), 0);
return field_arrays_[pos];
}
bool StructArray::Equals(const std::shared_ptr<Array>& arr) const {
if (this == arr.get()) { return true; }
if (!arr) { return false; }
if (this->type_enum() != arr->type_enum()) { return false; }
if (null_count_ != arr->null_count()) { return false; }
return RangeEquals(0, length_, 0, arr);
}
bool StructArray::RangeEquals(int32_t start_idx, int32_t end_idx, int32_t other_start_idx,
const std::shared_ptr<Array>& arr) const {
if (this == arr.get()) { return true; }
if (!arr) { return false; }
if (Type::STRUCT != arr->type_enum()) { return false; }
const auto other = static_cast<StructArray*>(arr.get());
bool equal_fields = true;
for (int32_t i = start_idx, o_i = other_start_idx; i < end_idx; ++i, ++o_i) {
if (IsNull(i) != arr->IsNull(o_i)) { return false; }
if (IsNull(i)) continue;
for (size_t j = 0; j < field_arrays_.size(); ++j) {
// TODO: really we should be comparing stretches of non-null data rather
// than looking at one value at a time.
equal_fields = field(j)->RangeEquals(i, i + 1, o_i, other->field(j));
if (!equal_fields) { return false; }
}
}
return true;
}
Status StructArray::Validate() const {
if (length_ < 0) { return Status::Invalid("Length was negative"); }
if (null_count() > length_) {
return Status::Invalid("Null count exceeds the length of this struct");
}
if (field_arrays_.size() > 0) {
// Validate fields
int32_t array_length = field_arrays_[0]->length();
size_t idx = 0;
for (auto it : field_arrays_) {
if (it->length() != array_length) {
std::stringstream ss;
ss << "Length is not equal from field " << it->type()->ToString()
<< " at position {" << idx << "}";
return Status::Invalid(ss.str());
}
const Status child_valid = it->Validate();
if (!child_valid.ok()) {
std::stringstream ss;
ss << "Child array invalid: " << child_valid.ToString() << " at position {" << idx
<< "}";
return Status::Invalid(ss.str());
}
++idx;
}
if (array_length > 0 && array_length != length_) {
return Status::Invalid("Struct's length is not equal to its child arrays");
}
}
return Status::OK();
}
Status StructArray::Accept(ArrayVisitor* visitor) const {
return visitor->Visit(*this);
}
// ----------------------------------------------------------------------
#define MAKE_PRIMITIVE_ARRAY_CASE(ENUM, ArrayType) \
case Type::ENUM: \
out->reset(new ArrayType(type, length, data, null_count, null_bitmap)); \
break;
Status MakePrimitiveArray(const TypePtr& type, int32_t length,
const std::shared_ptr<Buffer>& data, int32_t null_count,
const std::shared_ptr<Buffer>& null_bitmap, ArrayPtr* out) {
switch (type->type) {
MAKE_PRIMITIVE_ARRAY_CASE(BOOL, BooleanArray);
MAKE_PRIMITIVE_ARRAY_CASE(UINT8, UInt8Array);
MAKE_PRIMITIVE_ARRAY_CASE(INT8, Int8Array);
MAKE_PRIMITIVE_ARRAY_CASE(UINT16, UInt16Array);
MAKE_PRIMITIVE_ARRAY_CASE(INT16, Int16Array);
MAKE_PRIMITIVE_ARRAY_CASE(UINT32, UInt32Array);
MAKE_PRIMITIVE_ARRAY_CASE(INT32, Int32Array);
MAKE_PRIMITIVE_ARRAY_CASE(UINT64, UInt64Array);
MAKE_PRIMITIVE_ARRAY_CASE(INT64, Int64Array);
MAKE_PRIMITIVE_ARRAY_CASE(FLOAT, FloatArray);
MAKE_PRIMITIVE_ARRAY_CASE(DOUBLE, DoubleArray);
MAKE_PRIMITIVE_ARRAY_CASE(TIME, Int64Array);
MAKE_PRIMITIVE_ARRAY_CASE(TIMESTAMP, TimestampArray);
MAKE_PRIMITIVE_ARRAY_CASE(TIMESTAMP_DOUBLE, DoubleArray);
default:
return Status::NotImplemented(type->ToString());
}
#ifdef NDEBUG
return Status::OK();
#else
return (*out)->Validate();
#endif
}
} // namespace arrow
+370 -1
View File
@@ -23,12 +23,12 @@
#include "arrow/type.h"
#include "arrow/util/bit-util.h"
#include "arrow/util/buffer.h"
#include "arrow/util/macros.h"
#include "arrow/util/visibility.h"
namespace arrow {
class Buffer;
class MemoryPool;
class MutableBuffer;
class Status;
@@ -110,6 +110,375 @@ typedef std::shared_ptr<Array> ArrayPtr;
Status ARROW_EXPORT GetEmptyBitmap(
MemoryPool* pool, int32_t length, std::shared_ptr<MutableBuffer>* result);
// Base class for fixed-size logical types. See MakePrimitiveArray
// (types/construct.h) for constructing a specific subclass.
class ARROW_EXPORT PrimitiveArray : public Array {
public:
virtual ~PrimitiveArray() {}
std::shared_ptr<Buffer> data() const { return data_; }
bool EqualsExact(const PrimitiveArray& other) const;
bool Equals(const std::shared_ptr<Array>& arr) const override;
protected:
PrimitiveArray(const TypePtr& type, int32_t length, const std::shared_ptr<Buffer>& data,
int32_t null_count = 0, const std::shared_ptr<Buffer>& null_bitmap = nullptr);
std::shared_ptr<Buffer> data_;
const uint8_t* raw_data_;
};
template <typename TYPE>
class ARROW_EXPORT NumericArray : public PrimitiveArray {
public:
using TypeClass = TYPE;
using value_type = typename TypeClass::c_type;
NumericArray(int32_t length, const std::shared_ptr<Buffer>& data,
int32_t null_count = 0, const std::shared_ptr<Buffer>& null_bitmap = nullptr)
: PrimitiveArray(
std::make_shared<TypeClass>(), length, data, null_count, null_bitmap) {}
NumericArray(const TypePtr& type, int32_t length, const std::shared_ptr<Buffer>& data,
int32_t null_count = 0, const std::shared_ptr<Buffer>& null_bitmap = nullptr)
: PrimitiveArray(type, length, data, null_count, null_bitmap) {}
bool EqualsExact(const NumericArray<TypeClass>& other) const {
return PrimitiveArray::EqualsExact(static_cast<const PrimitiveArray&>(other));
}
bool ApproxEquals(const std::shared_ptr<Array>& arr) const { return Equals(arr); }
bool RangeEquals(int32_t start_idx, int32_t end_idx, int32_t other_start_idx,
const ArrayPtr& arr) const override {
if (this == arr.get()) { return true; }
if (!arr) { return false; }
if (this->type_enum() != arr->type_enum()) { return false; }
const auto other = static_cast<NumericArray<TypeClass>*>(arr.get());
for (int32_t i = start_idx, o_i = other_start_idx; i < end_idx; ++i, ++o_i) {
const bool is_null = IsNull(i);
if (is_null != arr->IsNull(o_i) || (!is_null && Value(i) != other->Value(o_i))) {
return false;
}
}
return true;
}
const value_type* raw_data() const {
return reinterpret_cast<const value_type*>(raw_data_);
}
Status Accept(ArrayVisitor* visitor) const override;
value_type Value(int i) const { return raw_data()[i]; }
};
template <>
inline bool NumericArray<FloatType>::ApproxEquals(
const std::shared_ptr<Array>& arr) const {
if (this == arr.get()) { return true; }
if (!arr) { return false; }
if (this->type_enum() != arr->type_enum()) { return false; }
const auto& other = *static_cast<NumericArray<FloatType>*>(arr.get());
if (this == &other) { return true; }
if (null_count_ != other.null_count_) { return false; }
auto this_data = reinterpret_cast<const float*>(raw_data_);
auto other_data = reinterpret_cast<const float*>(other.raw_data_);
static constexpr float EPSILON = 1E-5;
if (length_ == 0 && other.length_ == 0) { return true; }
if (null_count_ > 0) {
bool equal_bitmap =
null_bitmap_->Equals(*other.null_bitmap_, BitUtil::CeilByte(length_) / 8);
if (!equal_bitmap) { return false; }
for (int i = 0; i < length_; ++i) {
if (IsNull(i)) continue;
if (fabs(this_data[i] - other_data[i]) > EPSILON) { return false; }
}
} else {
for (int i = 0; i < length_; ++i) {
if (fabs(this_data[i] - other_data[i]) > EPSILON) { return false; }
}
}
return true;
}
template <>
inline bool NumericArray<DoubleType>::ApproxEquals(
const std::shared_ptr<Array>& arr) const {
if (this == arr.get()) { return true; }
if (!arr) { return false; }
if (this->type_enum() != arr->type_enum()) { return false; }
const auto& other = *static_cast<NumericArray<DoubleType>*>(arr.get());
if (this == &other) { return true; }
if (null_count_ != other.null_count_) { return false; }
auto this_data = reinterpret_cast<const double*>(raw_data_);
auto other_data = reinterpret_cast<const double*>(other.raw_data_);
if (length_ == 0 && other.length_ == 0) { return true; }
static constexpr double EPSILON = 1E-5;
if (null_count_ > 0) {
bool equal_bitmap =
null_bitmap_->Equals(*other.null_bitmap_, BitUtil::CeilByte(length_) / 8);
if (!equal_bitmap) { return false; }
for (int i = 0; i < length_; ++i) {
if (IsNull(i)) continue;
if (fabs(this_data[i] - other_data[i]) > EPSILON) { return false; }
}
} else {
for (int i = 0; i < length_; ++i) {
if (fabs(this_data[i] - other_data[i]) > EPSILON) { return false; }
}
}
return true;
}
class ARROW_EXPORT BooleanArray : public PrimitiveArray {
public:
using TypeClass = BooleanType;
BooleanArray(int32_t length, const std::shared_ptr<Buffer>& data,
int32_t null_count = 0, const std::shared_ptr<Buffer>& null_bitmap = nullptr);
BooleanArray(const TypePtr& type, int32_t length, const std::shared_ptr<Buffer>& data,
int32_t null_count = 0, const std::shared_ptr<Buffer>& null_bitmap = nullptr);
bool EqualsExact(const BooleanArray& other) const;
bool Equals(const ArrayPtr& arr) const override;
bool RangeEquals(int32_t start_idx, int32_t end_idx, int32_t other_start_idx,
const ArrayPtr& arr) const override;
Status Accept(ArrayVisitor* visitor) const override;
const uint8_t* raw_data() const { return reinterpret_cast<const uint8_t*>(raw_data_); }
bool Value(int i) const { return BitUtil::GetBit(raw_data(), i); }
};
// ----------------------------------------------------------------------
// ListArray
class ARROW_EXPORT ListArray : public Array {
public:
using TypeClass = ListType;
ListArray(const TypePtr& type, int32_t length, std::shared_ptr<Buffer> offsets,
const ArrayPtr& values, int32_t null_count = 0,
std::shared_ptr<Buffer> null_bitmap = nullptr)
: Array(type, length, null_count, null_bitmap) {
offset_buffer_ = offsets;
offsets_ = offsets == nullptr ? nullptr : reinterpret_cast<const int32_t*>(
offset_buffer_->data());
values_ = values;
}
Status Validate() const override;
virtual ~ListArray() = default;
// Return a shared pointer in case the requestor desires to share ownership
// with this array.
std::shared_ptr<Array> values() const { return values_; }
std::shared_ptr<Buffer> offsets() const {
return std::static_pointer_cast<Buffer>(offset_buffer_);
}
std::shared_ptr<DataType> value_type() const { return values_->type(); }
const int32_t* raw_offsets() const { return offsets_; }
int32_t offset(int i) const { return offsets_[i]; }
// Neither of these functions will perform boundschecking
int32_t value_offset(int i) const { return offsets_[i]; }
int32_t value_length(int i) const { return offsets_[i + 1] - offsets_[i]; }
bool EqualsExact(const ListArray& other) const;
bool Equals(const std::shared_ptr<Array>& arr) const override;
bool RangeEquals(int32_t start_idx, int32_t end_idx, int32_t other_start_idx,
const ArrayPtr& arr) const override;
Status Accept(ArrayVisitor* visitor) const override;
protected:
std::shared_ptr<Buffer> offset_buffer_;
const int32_t* offsets_;
ArrayPtr values_;
};
// ----------------------------------------------------------------------
// Binary and String
class ARROW_EXPORT BinaryArray : public Array {
public:
using TypeClass = BinaryType;
BinaryArray(int32_t length, const std::shared_ptr<Buffer>& offsets,
const std::shared_ptr<Buffer>& data, int32_t null_count = 0,
const std::shared_ptr<Buffer>& null_bitmap = nullptr);
// Constructor that allows sub-classes/builders to propagate there logical type up the
// class hierarchy.
BinaryArray(const TypePtr& type, int32_t length, const std::shared_ptr<Buffer>& offsets,
const std::shared_ptr<Buffer>& data, int32_t null_count = 0,
const std::shared_ptr<Buffer>& null_bitmap = nullptr);
// Return the pointer to the given elements bytes
// TODO(emkornfield) introduce a StringPiece or something similar to capture zero-copy
// pointer + offset
const uint8_t* GetValue(int i, int32_t* out_length) const {
const int32_t pos = offsets_[i];
*out_length = offsets_[i + 1] - pos;
return data_ + pos;
}
std::shared_ptr<Buffer> data() const { return data_buffer_; }
std::shared_ptr<Buffer> offsets() const { return offset_buffer_; }
const int32_t* raw_offsets() const { return offsets_; }
int32_t offset(int i) const { return offsets_[i]; }
// Neither of these functions will perform boundschecking
int32_t value_offset(int i) const { return offsets_[i]; }
int32_t value_length(int i) const { return offsets_[i + 1] - offsets_[i]; }
bool EqualsExact(const BinaryArray& other) const;
bool Equals(const std::shared_ptr<Array>& arr) const override;
bool RangeEquals(int32_t start_idx, int32_t end_idx, int32_t other_start_idx,
const ArrayPtr& arr) const override;
Status Validate() const override;
Status Accept(ArrayVisitor* visitor) const override;
private:
std::shared_ptr<Buffer> offset_buffer_;
const int32_t* offsets_;
std::shared_ptr<Buffer> data_buffer_;
const uint8_t* data_;
};
class ARROW_EXPORT StringArray : public BinaryArray {
public:
using TypeClass = StringType;
StringArray(int32_t length, const std::shared_ptr<Buffer>& offsets,
const std::shared_ptr<Buffer>& data, int32_t null_count = 0,
const std::shared_ptr<Buffer>& null_bitmap = nullptr);
// Construct a std::string
// TODO: std::bad_alloc possibility
std::string GetString(int i) const {
int32_t nchars;
const uint8_t* str = GetValue(i, &nchars);
return std::string(reinterpret_cast<const char*>(str), nchars);
}
Status Validate() const override;
Status Accept(ArrayVisitor* visitor) const override;
};
// ----------------------------------------------------------------------
// Struct
class ARROW_EXPORT StructArray : public Array {
public:
using TypeClass = StructType;
StructArray(const TypePtr& type, int32_t length, std::vector<ArrayPtr>& field_arrays,
int32_t null_count = 0, std::shared_ptr<Buffer> null_bitmap = nullptr)
: Array(type, length, null_count, null_bitmap) {
type_ = type;
field_arrays_ = field_arrays;
}
Status Validate() const override;
virtual ~StructArray() {}
// Return a shared pointer in case the requestor desires to share ownership
// with this array.
std::shared_ptr<Array> field(int32_t pos) const;
const std::vector<ArrayPtr>& fields() const { return field_arrays_; }
bool EqualsExact(const StructArray& other) const;
bool Equals(const std::shared_ptr<Array>& arr) const override;
bool RangeEquals(int32_t start_idx, int32_t end_idx, int32_t other_start_idx,
const std::shared_ptr<Array>& arr) const override;
Status Accept(ArrayVisitor* visitor) const override;
protected:
// The child arrays corresponding to each field of the struct data type.
std::vector<ArrayPtr> field_arrays_;
};
// ----------------------------------------------------------------------
// Union
class UnionArray : public Array {
protected:
// The data are types encoded as int16
Buffer* types_;
std::vector<std::shared_ptr<Array>> children_;
};
class DenseUnionArray : public UnionArray {
protected:
Buffer* offset_buf_;
};
class SparseUnionArray : public UnionArray {};
// ----------------------------------------------------------------------
// extern templates and other details
// gcc and clang disagree about how to handle template visibility when you have
// explicit specializations https://llvm.org/bugs/show_bug.cgi?id=24815
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wattributes"
#endif
// Only instantiate these templates once
extern template class ARROW_EXPORT NumericArray<Int8Type>;
extern template class ARROW_EXPORT NumericArray<UInt8Type>;
extern template class ARROW_EXPORT NumericArray<Int16Type>;
extern template class ARROW_EXPORT NumericArray<UInt16Type>;
extern template class ARROW_EXPORT NumericArray<Int32Type>;
extern template class ARROW_EXPORT NumericArray<UInt32Type>;
extern template class ARROW_EXPORT NumericArray<Int64Type>;
extern template class ARROW_EXPORT NumericArray<UInt64Type>;
extern template class ARROW_EXPORT NumericArray<HalfFloatType>;
extern template class ARROW_EXPORT NumericArray<FloatType>;
extern template class ARROW_EXPORT NumericArray<DoubleType>;
extern template class ARROW_EXPORT NumericArray<TimestampType>;
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif
// ----------------------------------------------------------------------
// Helper functions
// Create new arrays for logical types that are backed by primitive arrays.
Status ARROW_EXPORT MakePrimitiveArray(const std::shared_ptr<DataType>& type,
int32_t length, const std::shared_ptr<Buffer>& data, int32_t null_count,
const std::shared_ptr<Buffer>& null_bitmap, std::shared_ptr<Array>* out);
} // namespace arrow
#endif
+323
View File
@@ -19,8 +19,12 @@
#include <cstring>
#include "arrow/array.h"
#include "arrow/type.h"
#include "arrow/type_traits.h"
#include "arrow/util/bit-util.h"
#include "arrow/util/buffer.h"
#include "arrow/util/logging.h"
#include "arrow/util/status.h"
namespace arrow {
@@ -123,4 +127,323 @@ void ArrayBuilder::UnsafeSetNotNull(int32_t length) {
length_ = new_length;
}
template <typename T>
Status PrimitiveBuilder<T>::Init(int32_t capacity) {
RETURN_NOT_OK(ArrayBuilder::Init(capacity));
data_ = std::make_shared<PoolBuffer>(pool_);
int64_t nbytes = TypeTraits<T>::bytes_required(capacity);
RETURN_NOT_OK(data_->Resize(nbytes));
// TODO(emkornfield) valgrind complains without this
memset(data_->mutable_data(), 0, nbytes);
raw_data_ = reinterpret_cast<value_type*>(data_->mutable_data());
return Status::OK();
}
template <typename T>
Status PrimitiveBuilder<T>::Resize(int32_t capacity) {
// XXX: Set floor size for now
if (capacity < kMinBuilderCapacity) { capacity = kMinBuilderCapacity; }
if (capacity_ == 0) {
RETURN_NOT_OK(Init(capacity));
} else {
RETURN_NOT_OK(ArrayBuilder::Resize(capacity));
const int64_t old_bytes = data_->size();
const int64_t new_bytes = TypeTraits<T>::bytes_required(capacity);
RETURN_NOT_OK(data_->Resize(new_bytes));
raw_data_ = reinterpret_cast<value_type*>(data_->mutable_data());
memset(data_->mutable_data() + old_bytes, 0, new_bytes - old_bytes);
}
return Status::OK();
}
template <typename T>
Status PrimitiveBuilder<T>::Append(
const value_type* values, int32_t length, const uint8_t* valid_bytes) {
RETURN_NOT_OK(Reserve(length));
if (length > 0) {
memcpy(raw_data_ + length_, values, TypeTraits<T>::bytes_required(length));
}
// length_ is update by these
ArrayBuilder::UnsafeAppendToBitmap(valid_bytes, length);
return Status::OK();
}
template <typename T>
Status PrimitiveBuilder<T>::Finish(std::shared_ptr<Array>* out) {
const int64_t bytes_required = TypeTraits<T>::bytes_required(length_);
if (bytes_required > 0 && bytes_required < data_->size()) {
// Trim buffers
RETURN_NOT_OK(data_->Resize(bytes_required));
}
*out = std::make_shared<typename TypeTraits<T>::ArrayType>(
type_, length_, data_, null_count_, null_bitmap_);
data_ = null_bitmap_ = nullptr;
capacity_ = length_ = null_count_ = 0;
return Status::OK();
}
template class PrimitiveBuilder<UInt8Type>;
template class PrimitiveBuilder<UInt16Type>;
template class PrimitiveBuilder<UInt32Type>;
template class PrimitiveBuilder<UInt64Type>;
template class PrimitiveBuilder<Int8Type>;
template class PrimitiveBuilder<Int16Type>;
template class PrimitiveBuilder<Int32Type>;
template class PrimitiveBuilder<Int64Type>;
template class PrimitiveBuilder<TimestampType>;
template class PrimitiveBuilder<HalfFloatType>;
template class PrimitiveBuilder<FloatType>;
template class PrimitiveBuilder<DoubleType>;
Status BooleanBuilder::Init(int32_t capacity) {
RETURN_NOT_OK(ArrayBuilder::Init(capacity));
data_ = std::make_shared<PoolBuffer>(pool_);
int64_t nbytes = BitUtil::BytesForBits(capacity);
RETURN_NOT_OK(data_->Resize(nbytes));
// TODO(emkornfield) valgrind complains without this
memset(data_->mutable_data(), 0, nbytes);
raw_data_ = reinterpret_cast<uint8_t*>(data_->mutable_data());
return Status::OK();
}
Status BooleanBuilder::Resize(int32_t capacity) {
// XXX: Set floor size for now
if (capacity < kMinBuilderCapacity) { capacity = kMinBuilderCapacity; }
if (capacity_ == 0) {
RETURN_NOT_OK(Init(capacity));
} else {
RETURN_NOT_OK(ArrayBuilder::Resize(capacity));
const int64_t old_bytes = data_->size();
const int64_t new_bytes = BitUtil::BytesForBits(capacity);
RETURN_NOT_OK(data_->Resize(new_bytes));
raw_data_ = reinterpret_cast<uint8_t*>(data_->mutable_data());
memset(data_->mutable_data() + old_bytes, 0, new_bytes - old_bytes);
}
return Status::OK();
}
Status BooleanBuilder::Finish(std::shared_ptr<Array>* out) {
const int64_t bytes_required = BitUtil::BytesForBits(length_);
if (bytes_required > 0 && bytes_required < data_->size()) {
// Trim buffers
RETURN_NOT_OK(data_->Resize(bytes_required));
}
*out = std::make_shared<BooleanArray>(type_, length_, data_, null_count_, null_bitmap_);
data_ = null_bitmap_ = nullptr;
capacity_ = length_ = null_count_ = 0;
return Status::OK();
}
Status BooleanBuilder::Append(
const uint8_t* values, int32_t length, const uint8_t* valid_bytes) {
RETURN_NOT_OK(Reserve(length));
for (int i = 0; i < length; ++i) {
// Skip reading from unitialised memory
// TODO: This actually is only to keep valgrind happy but may or may not
// have a performance impact.
if ((valid_bytes != nullptr) && !valid_bytes[i]) continue;
if (values[i] > 0) {
BitUtil::SetBit(raw_data_, length_ + i);
} else {
BitUtil::ClearBit(raw_data_, length_ + i);
}
}
// this updates length_
ArrayBuilder::UnsafeAppendToBitmap(valid_bytes, length);
return Status::OK();
}
// ----------------------------------------------------------------------
// ListBuilder
ListBuilder::ListBuilder(
MemoryPool* pool, std::shared_ptr<ArrayBuilder> value_builder, const TypePtr& type)
: ArrayBuilder(
pool, type ? type : std::static_pointer_cast<DataType>(
std::make_shared<ListType>(value_builder->type()))),
offset_builder_(pool),
value_builder_(value_builder) {}
ListBuilder::ListBuilder(
MemoryPool* pool, std::shared_ptr<Array> values, const TypePtr& type)
: ArrayBuilder(pool, type ? type : std::static_pointer_cast<DataType>(
std::make_shared<ListType>(values->type()))),
offset_builder_(pool),
values_(values) {}
Status ListBuilder::Init(int32_t elements) {
DCHECK_LT(elements, std::numeric_limits<int32_t>::max());
RETURN_NOT_OK(ArrayBuilder::Init(elements));
// one more then requested for offsets
return offset_builder_.Resize((elements + 1) * sizeof(int32_t));
}
Status ListBuilder::Resize(int32_t capacity) {
DCHECK_LT(capacity, std::numeric_limits<int32_t>::max());
// one more then requested for offsets
RETURN_NOT_OK(offset_builder_.Resize((capacity + 1) * sizeof(int32_t)));
return ArrayBuilder::Resize(capacity);
}
Status ListBuilder::Finish(std::shared_ptr<Array>* out) {
std::shared_ptr<Array> items = values_;
if (!items) { RETURN_NOT_OK(value_builder_->Finish(&items)); }
RETURN_NOT_OK(offset_builder_.Append<int32_t>(items->length()));
std::shared_ptr<Buffer> offsets = offset_builder_.Finish();
*out = std::make_shared<ListArray>(
type_, length_, offsets, items, null_count_, null_bitmap_);
Reset();
return Status::OK();
}
void ListBuilder::Reset() {
capacity_ = length_ = null_count_ = 0;
null_bitmap_ = nullptr;
}
std::shared_ptr<ArrayBuilder> ListBuilder::value_builder() const {
DCHECK(!values_) << "Using value builder is pointless when values_ is set";
return value_builder_;
}
// ----------------------------------------------------------------------
// String and binary
// This used to be a static member variable of BinaryBuilder, but it can cause
// valgrind to report a (spurious?) memory leak when needed in other shared
// libraries. The problem came up while adding explicit visibility to libarrow
// and libparquet_arrow
static TypePtr kBinaryValueType = TypePtr(new UInt8Type());
BinaryBuilder::BinaryBuilder(MemoryPool* pool, const TypePtr& type)
: ListBuilder(pool, std::make_shared<UInt8Builder>(pool, kBinaryValueType), type) {
byte_builder_ = static_cast<UInt8Builder*>(value_builder_.get());
}
Status BinaryBuilder::Finish(std::shared_ptr<Array>* out) {
std::shared_ptr<Array> result;
RETURN_NOT_OK(ListBuilder::Finish(&result));
const auto list = std::dynamic_pointer_cast<ListArray>(result);
auto values = std::dynamic_pointer_cast<UInt8Array>(list->values());
*out = std::make_shared<BinaryArray>(list->length(), list->offsets(), values->data(),
list->null_count(), list->null_bitmap());
return Status::OK();
}
Status StringBuilder::Finish(std::shared_ptr<Array>* out) {
std::shared_ptr<Array> result;
RETURN_NOT_OK(ListBuilder::Finish(&result));
const auto list = std::dynamic_pointer_cast<ListArray>(result);
auto values = std::dynamic_pointer_cast<UInt8Array>(list->values());
*out = std::make_shared<StringArray>(list->length(), list->offsets(), values->data(),
list->null_count(), list->null_bitmap());
return Status::OK();
}
// ----------------------------------------------------------------------
// Struct
Status StructBuilder::Finish(std::shared_ptr<Array>* out) {
std::vector<std::shared_ptr<Array>> fields(field_builders_.size());
for (size_t i = 0; i < field_builders_.size(); ++i) {
RETURN_NOT_OK(field_builders_[i]->Finish(&fields[i]));
}
*out = std::make_shared<StructArray>(type_, length_, fields, null_count_, null_bitmap_);
null_bitmap_ = nullptr;
capacity_ = length_ = null_count_ = 0;
return Status::OK();
}
std::shared_ptr<ArrayBuilder> StructBuilder::field_builder(int pos) const {
DCHECK_GT(field_builders_.size(), 0);
return field_builders_[pos];
}
// ----------------------------------------------------------------------
// Helper functions
#define BUILDER_CASE(ENUM, BuilderType) \
case Type::ENUM: \
out->reset(new BuilderType(pool, type)); \
return Status::OK();
// Initially looked at doing this with vtables, but shared pointers makes it
// difficult
//
// TODO(wesm): come up with a less monolithic strategy
Status MakeBuilder(MemoryPool* pool, const std::shared_ptr<DataType>& type,
std::shared_ptr<ArrayBuilder>* out) {
switch (type->type) {
BUILDER_CASE(UINT8, UInt8Builder);
BUILDER_CASE(INT8, Int8Builder);
BUILDER_CASE(UINT16, UInt16Builder);
BUILDER_CASE(INT16, Int16Builder);
BUILDER_CASE(UINT32, UInt32Builder);
BUILDER_CASE(INT32, Int32Builder);
BUILDER_CASE(UINT64, UInt64Builder);
BUILDER_CASE(INT64, Int64Builder);
BUILDER_CASE(TIMESTAMP, TimestampBuilder);
BUILDER_CASE(BOOL, BooleanBuilder);
BUILDER_CASE(FLOAT, FloatBuilder);
BUILDER_CASE(DOUBLE, DoubleBuilder);
BUILDER_CASE(STRING, StringBuilder);
BUILDER_CASE(BINARY, BinaryBuilder);
case Type::LIST: {
std::shared_ptr<ArrayBuilder> value_builder;
std::shared_ptr<DataType> value_type =
static_cast<ListType*>(type.get())->value_type();
RETURN_NOT_OK(MakeBuilder(pool, value_type, &value_builder));
out->reset(new ListBuilder(pool, value_builder));
return Status::OK();
}
case Type::STRUCT: {
std::vector<FieldPtr>& fields = type->children_;
std::vector<std::shared_ptr<ArrayBuilder>> values_builder;
for (auto it : fields) {
std::shared_ptr<ArrayBuilder> builder;
RETURN_NOT_OK(MakeBuilder(pool, it->type, &builder));
values_builder.push_back(builder);
}
out->reset(new StructBuilder(pool, type, values_builder));
return Status::OK();
}
default:
return Status::NotImplemented(type->ToString());
}
}
} // namespace arrow
+311 -1
View File
@@ -23,6 +23,8 @@
#include <vector>
#include "arrow/type.h"
#include "arrow/util/bit-util.h"
#include "arrow/util/buffer.h"
#include "arrow/util/macros.h"
#include "arrow/util/status.h"
#include "arrow/util/visibility.h"
@@ -31,7 +33,6 @@ namespace arrow {
class Array;
class MemoryPool;
class PoolBuffer;
static constexpr int32_t kMinBuilderCapacity = 1 << 5;
@@ -130,6 +131,315 @@ class ARROW_EXPORT ArrayBuilder {
DISALLOW_COPY_AND_ASSIGN(ArrayBuilder);
};
template <typename Type>
class ARROW_EXPORT PrimitiveBuilder : public ArrayBuilder {
public:
using value_type = typename Type::c_type;
explicit PrimitiveBuilder(MemoryPool* pool, const TypePtr& type)
: ArrayBuilder(pool, type), data_(nullptr) {}
virtual ~PrimitiveBuilder() {}
using ArrayBuilder::Advance;
// Write nulls as uint8_t* (0 value indicates null) into pre-allocated memory
Status AppendNulls(const uint8_t* valid_bytes, int32_t length) {
RETURN_NOT_OK(Reserve(length));
UnsafeAppendToBitmap(valid_bytes, length);
return Status::OK();
}
Status AppendNull() {
RETURN_NOT_OK(Reserve(1));
UnsafeAppendToBitmap(false);
return Status::OK();
}
std::shared_ptr<Buffer> data() const { return data_; }
// Vector append
//
// If passed, valid_bytes is of equal length to values, and any zero byte
// will be considered as a null for that slot
Status Append(
const value_type* values, int32_t length, const uint8_t* valid_bytes = nullptr);
Status Finish(std::shared_ptr<Array>* out) override;
Status Init(int32_t capacity) override;
// Increase the capacity of the builder to accommodate at least the indicated
// number of elements
Status Resize(int32_t capacity) override;
protected:
std::shared_ptr<PoolBuffer> data_;
value_type* raw_data_;
};
template <typename T>
class ARROW_EXPORT NumericBuilder : public PrimitiveBuilder<T> {
public:
using typename PrimitiveBuilder<T>::value_type;
using PrimitiveBuilder<T>::PrimitiveBuilder;
using PrimitiveBuilder<T>::Append;
using PrimitiveBuilder<T>::Init;
using PrimitiveBuilder<T>::Resize;
using PrimitiveBuilder<T>::Reserve;
// Scalar append.
Status Append(value_type val) {
RETURN_NOT_OK(ArrayBuilder::Reserve(1));
UnsafeAppend(val);
return Status::OK();
}
// Does not capacity-check; make sure to call Reserve beforehand
void UnsafeAppend(value_type val) {
BitUtil::SetBit(null_bitmap_data_, length_);
raw_data_[length_++] = val;
}
protected:
using PrimitiveBuilder<T>::length_;
using PrimitiveBuilder<T>::null_bitmap_data_;
using PrimitiveBuilder<T>::raw_data_;
};
// Builders
using UInt8Builder = NumericBuilder<UInt8Type>;
using UInt16Builder = NumericBuilder<UInt16Type>;
using UInt32Builder = NumericBuilder<UInt32Type>;
using UInt64Builder = NumericBuilder<UInt64Type>;
using Int8Builder = NumericBuilder<Int8Type>;
using Int16Builder = NumericBuilder<Int16Type>;
using Int32Builder = NumericBuilder<Int32Type>;
using Int64Builder = NumericBuilder<Int64Type>;
using TimestampBuilder = NumericBuilder<TimestampType>;
using HalfFloatBuilder = NumericBuilder<HalfFloatType>;
using FloatBuilder = NumericBuilder<FloatType>;
using DoubleBuilder = NumericBuilder<DoubleType>;
class ARROW_EXPORT BooleanBuilder : public ArrayBuilder {
public:
explicit BooleanBuilder(MemoryPool* pool, const TypePtr& type)
: ArrayBuilder(pool, type), data_(nullptr) {}
virtual ~BooleanBuilder() {}
using ArrayBuilder::Advance;
// Write nulls as uint8_t* (0 value indicates null) into pre-allocated memory
Status AppendNulls(const uint8_t* valid_bytes, int32_t length) {
RETURN_NOT_OK(Reserve(length));
UnsafeAppendToBitmap(valid_bytes, length);
return Status::OK();
}
Status AppendNull() {
RETURN_NOT_OK(Reserve(1));
UnsafeAppendToBitmap(false);
return Status::OK();
}
std::shared_ptr<Buffer> data() const { return data_; }
// Scalar append
Status Append(bool val) {
Reserve(1);
BitUtil::SetBit(null_bitmap_data_, length_);
if (val) {
BitUtil::SetBit(raw_data_, length_);
} else {
BitUtil::ClearBit(raw_data_, length_);
}
++length_;
return Status::OK();
}
// Vector append
//
// If passed, valid_bytes is of equal length to values, and any zero byte
// will be considered as a null for that slot
Status Append(
const uint8_t* values, int32_t length, const uint8_t* valid_bytes = nullptr);
Status Finish(std::shared_ptr<Array>* out) override;
Status Init(int32_t capacity) override;
// Increase the capacity of the builder to accommodate at least the indicated
// number of elements
Status Resize(int32_t capacity) override;
protected:
std::shared_ptr<PoolBuffer> data_;
uint8_t* raw_data_;
};
// ----------------------------------------------------------------------
// List builder
// Builder class for variable-length list array value types
//
// To use this class, you must append values to the child array builder and use
// the Append function to delimit each distinct list value (once the values
// have been appended to the child array) or use the bulk API to append
// a sequence of offests and null values.
//
// A note on types. Per arrow/type.h all types in the c++ implementation are
// logical so even though this class always builds list array, this can
// represent multiple different logical types. If no logical type is provided
// at construction time, the class defaults to List<T> where t is taken from the
// value_builder/values that the object is constructed with.
class ARROW_EXPORT ListBuilder : public ArrayBuilder {
public:
// Use this constructor to incrementally build the value array along with offsets and
// null bitmap.
ListBuilder(MemoryPool* pool, std::shared_ptr<ArrayBuilder> value_builder,
const TypePtr& type = nullptr);
// Use this constructor to build the list with a pre-existing values array
ListBuilder(
MemoryPool* pool, std::shared_ptr<Array> values, const TypePtr& type = nullptr);
virtual ~ListBuilder() {}
Status Init(int32_t elements) override;
Status Resize(int32_t capacity) override;
Status Finish(std::shared_ptr<Array>* out) override;
// Vector append
//
// If passed, valid_bytes is of equal length to values, and any zero byte
// will be considered as a null for that slot
Status Append(
const int32_t* offsets, int32_t length, const uint8_t* valid_bytes = nullptr) {
RETURN_NOT_OK(Reserve(length));
UnsafeAppendToBitmap(valid_bytes, length);
offset_builder_.UnsafeAppend<int32_t>(offsets, length);
return Status::OK();
}
// Start a new variable-length list slot
//
// This function should be called before beginning to append elements to the
// value builder
Status Append(bool is_valid = true) {
RETURN_NOT_OK(Reserve(1));
UnsafeAppendToBitmap(is_valid);
RETURN_NOT_OK(offset_builder_.Append<int32_t>(value_builder_->length()));
return Status::OK();
}
Status AppendNull() { return Append(false); }
std::shared_ptr<ArrayBuilder> value_builder() const;
protected:
BufferBuilder offset_builder_;
std::shared_ptr<ArrayBuilder> value_builder_;
std::shared_ptr<Array> values_;
void Reset();
};
// ----------------------------------------------------------------------
// Binary and String
// BinaryBuilder : public ListBuilder
class ARROW_EXPORT BinaryBuilder : public ListBuilder {
public:
explicit BinaryBuilder(MemoryPool* pool, const TypePtr& type);
virtual ~BinaryBuilder() {}
Status Append(const uint8_t* value, int32_t length) {
RETURN_NOT_OK(ListBuilder::Append());
return byte_builder_->Append(value, length);
}
Status Append(const char* value, int32_t length) {
return Append(reinterpret_cast<const uint8_t*>(value), length);
}
Status Append(const std::string& value) { return Append(value.c_str(), value.size()); }
Status Finish(std::shared_ptr<Array>* out) override;
protected:
UInt8Builder* byte_builder_;
};
// String builder
class ARROW_EXPORT StringBuilder : public BinaryBuilder {
public:
explicit StringBuilder(MemoryPool* pool, const TypePtr& type)
: BinaryBuilder(pool, type) {}
using BinaryBuilder::Append;
Status Finish(std::shared_ptr<Array>* out) override;
Status Append(const std::vector<std::string>& values, uint8_t* null_bytes);
};
// ----------------------------------------------------------------------
// Struct
// ---------------------------------------------------------------------------------
// StructArray builder
// Append, Resize and Reserve methods are acting on StructBuilder.
// Please make sure all these methods of all child-builders' are consistently
// called to maintain data-structure consistency.
class ARROW_EXPORT StructBuilder : public ArrayBuilder {
public:
StructBuilder(MemoryPool* pool, const std::shared_ptr<DataType>& type,
const std::vector<std::shared_ptr<ArrayBuilder>>& field_builders)
: ArrayBuilder(pool, type) {
field_builders_ = field_builders;
}
Status Finish(std::shared_ptr<Array>* out) override;
// Null bitmap is of equal length to every child field, and any zero byte
// will be considered as a null for that field, but users must using app-
// end methods or advance methods of the child builders' independently to
// insert data.
Status Append(int32_t length, const uint8_t* valid_bytes) {
RETURN_NOT_OK(Reserve(length));
UnsafeAppendToBitmap(valid_bytes, length);
return Status::OK();
}
// Append an element to the Struct. All child-builders' Append method must
// be called independently to maintain data-structure consistency.
Status Append(bool is_valid = true) {
RETURN_NOT_OK(Reserve(1));
UnsafeAppendToBitmap(is_valid);
return Status::OK();
}
Status AppendNull() { return Append(false); }
std::shared_ptr<ArrayBuilder> field_builder(int pos) const;
const std::vector<std::shared_ptr<ArrayBuilder>>& field_builders() const {
return field_builders_;
}
protected:
std::vector<std::shared_ptr<ArrayBuilder>> field_builders_;
};
// ----------------------------------------------------------------------
// Helper functions
Status ARROW_EXPORT MakeBuilder(MemoryPool* pool, const std::shared_ptr<DataType>& type,
std::shared_ptr<ArrayBuilder>* out);
} // namespace arrow
#endif // ARROW_BUILDER_H_
+1 -1
View File
@@ -17,8 +17,8 @@
#include "benchmark/benchmark.h"
#include "arrow/array.h"
#include "arrow/test-util.h"
#include "arrow/types/primitive.h"
#include "arrow/util/memory-pool.h"
namespace arrow {
-1
View File
@@ -27,7 +27,6 @@
#include "arrow/schema.h"
#include "arrow/test-util.h"
#include "arrow/type.h"
#include "arrow/types/primitive.h"
using std::shared_ptr;
using std::vector;
-4
View File
@@ -33,10 +33,6 @@
#include "arrow/table.h"
#include "arrow/type.h"
#include "arrow/types/construct.h"
#include "arrow/types/list.h"
#include "arrow/types/primitive.h"
#include "arrow/types/string.h"
#include "arrow/types/struct.h"
#include "arrow/util/bit-util.h"
#include "arrow/util/buffer.h"
#include "arrow/util/logging.h"
-4
View File
@@ -31,10 +31,6 @@
#include "arrow/ipc/util.h"
#include "arrow/test-util.h"
#include "arrow/types/list.h"
#include "arrow/types/primitive.h"
#include "arrow/types/string.h"
#include "arrow/types/struct.h"
#include "arrow/util/bit-util.h"
#include "arrow/util/buffer.h"
#include "arrow/util/memory-pool.h"
+1 -4
View File
@@ -24,6 +24,7 @@
#include "gtest/gtest.h"
#include "arrow/array.h"
#include "arrow/io/memory.h"
#include "arrow/io/test-common.h"
#include "arrow/ipc/adapter.h"
@@ -32,10 +33,6 @@
#include "arrow/ipc/util.h"
#include "arrow/test-util.h"
#include "arrow/types/list.h"
#include "arrow/types/primitive.h"
#include "arrow/types/string.h"
#include "arrow/types/struct.h"
#include "arrow/util/bit-util.h"
#include "arrow/util/buffer.h"
#include "arrow/util/memory-pool.h"
+6 -8
View File
@@ -26,15 +26,13 @@
#include "gtest/gtest.h"
#include "arrow/array.h"
#include "arrow/builder.h"
#include "arrow/ipc/json-internal.h"
#include "arrow/ipc/json.h"
#include "arrow/table.h"
#include "arrow/test-util.h"
#include "arrow/type.h"
#include "arrow/type_traits.h"
#include "arrow/types/primitive.h"
#include "arrow/types/string.h"
#include "arrow/types/struct.h"
#include "arrow/util/memory-pool.h"
#include "arrow/util/status.h"
@@ -147,7 +145,7 @@ TEST(TestJsonArrayWriter, NestedTypes) {
std::vector<int32_t> values = {0, 1, 2, 3, 4, 5, 6};
std::shared_ptr<Array> values_array;
MakeArray<Int32Type, int32_t>(int32(), values_is_valid, values, &values_array);
ArrayFromVector<Int32Type, int32_t>(int32(), values_is_valid, values, &values_array);
// List
std::vector<bool> list_is_valid = {true, false, true, true, true};
@@ -188,10 +186,10 @@ void MakeBatchArrays(const std::shared_ptr<Schema>& schema, const int num_rows,
test::randint<int32_t>(num_rows, 0, 100, &v2_values);
std::shared_ptr<Array> v1;
MakeArray<Int8Type, int8_t>(schema->field(0)->type, is_valid, v1_values, &v1);
ArrayFromVector<Int8Type, int8_t>(schema->field(0)->type, is_valid, v1_values, &v1);
std::shared_ptr<Array> v2;
MakeArray<Int32Type, int32_t>(schema->field(1)->type, is_valid, v2_values, &v2);
ArrayFromVector<Int32Type, int32_t>(schema->field(1)->type, is_valid, v2_values, &v2);
static const int kBufferSize = 10;
static uint8_t buffer[kBufferSize];
@@ -323,13 +321,13 @@ TEST(TestJsonFileReadWrite, MinimalFormatExample) {
std::vector<bool> foo_valid = {true, false, true, true, true};
std::vector<int32_t> foo_values = {1, 2, 3, 4, 5};
std::shared_ptr<Array> foo;
MakeArray<Int32Type, int32_t>(int32(), foo_valid, foo_values, &foo);
ArrayFromVector<Int32Type, int32_t>(int32(), foo_valid, foo_values, &foo);
ASSERT_TRUE(batch->column(0)->Equals(foo));
std::vector<bool> bar_valid = {true, false, false, true, true};
std::vector<double> bar_values = {1, 2, 3, 4, 5};
std::shared_ptr<Array> bar;
MakeArray<DoubleType, double>(float64(), bar_valid, bar_values, &bar);
ArrayFromVector<DoubleType, double>(float64(), bar_valid, bar_values, &bar);
ASSERT_TRUE(batch->column(1)->Equals(bar));
}
+2 -4
View File
@@ -28,14 +28,12 @@
#include "rapidjson/writer.h"
#include "arrow/array.h"
#include "arrow/builder.h"
#include "arrow/schema.h"
#include "arrow/type.h"
#include "arrow/type_traits.h"
#include "arrow/types/list.h"
#include "arrow/types/primitive.h"
#include "arrow/types/string.h"
#include "arrow/types/struct.h"
#include "arrow/util/bit-util.h"
#include "arrow/util/logging.h"
#include "arrow/util/memory-pool.h"
#include "arrow/util/status.h"
+1 -4
View File
@@ -25,13 +25,10 @@
#include <vector>
#include "arrow/array.h"
#include "arrow/builder.h"
#include "arrow/table.h"
#include "arrow/test-util.h"
#include "arrow/type.h"
#include "arrow/types/list.h"
#include "arrow/types/primitive.h"
#include "arrow/types/string.h"
#include "arrow/types/struct.h"
#include "arrow/util/bit-util.h"
#include "arrow/util/buffer.h"
#include "arrow/util/memory-pool.h"
+1 -4
View File
@@ -26,14 +26,11 @@
#include "gtest/gtest.h"
#include "arrow/array.h"
#include "arrow/builder.h"
#include "arrow/pretty_print.h"
#include "arrow/test-util.h"
#include "arrow/type.h"
#include "arrow/type_traits.h"
#include "arrow/types/list.h"
#include "arrow/types/primitive.h"
#include "arrow/types/string.h"
#include "arrow/types/struct.h"
namespace arrow {
-3
View File
@@ -25,9 +25,6 @@
#include "arrow/table.h"
#include "arrow/type.h"
#include "arrow/type_traits.h"
#include "arrow/types/list.h"
#include "arrow/types/string.h"
#include "arrow/types/struct.h"
#include "arrow/util/status.h"
namespace arrow {
+1 -1
View File
@@ -21,12 +21,12 @@
#include "gtest/gtest.h"
#include "arrow/array.h"
#include "arrow/column.h"
#include "arrow/schema.h"
#include "arrow/table.h"
#include "arrow/test-util.h"
#include "arrow/type.h"
#include "arrow/types/primitive.h"
#include "arrow/util/status.h"
using std::shared_ptr;
+35 -2
View File
@@ -28,6 +28,7 @@
#include "gtest/gtest.h"
#include "arrow/array.h"
#include "arrow/builder.h"
#include "arrow/column.h"
#include "arrow/schema.h"
#include "arrow/table.h"
@@ -253,8 +254,9 @@ Status MakeRandomBytePoolBuffer(int32_t length, MemoryPool* pool,
} // namespace test
template <typename TYPE, typename C_TYPE>
void MakeArray(const std::shared_ptr<DataType>& type, const std::vector<bool>& is_valid,
const std::vector<C_TYPE>& values, std::shared_ptr<Array>* out) {
void ArrayFromVector(const std::shared_ptr<DataType>& type,
const std::vector<bool>& is_valid, const std::vector<C_TYPE>& values,
std::shared_ptr<Array>* out) {
std::shared_ptr<Buffer> values_buffer;
std::shared_ptr<Buffer> values_bitmap;
@@ -272,6 +274,37 @@ void MakeArray(const std::shared_ptr<DataType>& type, const std::vector<bool>& i
values_buffer, null_count, values_bitmap);
}
class TestBuilder : public ::testing::Test {
public:
void SetUp() {
pool_ = default_memory_pool();
type_ = TypePtr(new UInt8Type());
builder_.reset(new UInt8Builder(pool_, type_));
builder_nn_.reset(new UInt8Builder(pool_, type_));
}
protected:
MemoryPool* pool_;
TypePtr type_;
std::unique_ptr<ArrayBuilder> builder_;
std::unique_ptr<ArrayBuilder> builder_nn_;
};
template <class T, class Builder>
Status MakeArray(const std::vector<uint8_t>& valid_bytes, const std::vector<T>& values,
int size, Builder* builder, ArrayPtr* out) {
// Append the first 1000
for (int i = 0; i < size; ++i) {
if (valid_bytes[i] > 0) {
RETURN_NOT_OK(builder->Append(values[i]));
} else {
RETURN_NOT_OK(builder->AppendNull());
}
}
return builder->Finish(out);
}
} // namespace arrow
#endif // ARROW_TEST_UTIL_H_
+6
View File
@@ -220,6 +220,12 @@ std::vector<BufferDescr> UnionType::GetBufferLayout() const {
}
}
std::string DecimalType::ToString() const {
std::stringstream s;
s << "decimal(" << precision << ", " << scale << ")";
return s.str();
}
std::vector<BufferDescr> DecimalType::GetBufferLayout() const {
// TODO(wesm)
return {};
-39
View File
@@ -1,39 +0,0 @@
# 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.
#######################################
# arrow_types
#######################################
# Headers: top level
install(FILES
construct.h
datetime.h
decimal.h
list.h
primitive.h
string.h
struct.h
union.h
DESTINATION include/arrow/types)
ADD_ARROW_TEST(decimal-test)
ADD_ARROW_TEST(list-test)
ADD_ARROW_TEST(primitive-test)
ADD_ARROW_TEST(string-test)
ADD_ARROW_TEST(struct-test)
-124
View File
@@ -1,124 +0,0 @@
// 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 "arrow/types/construct.h"
#include <memory>
#include "arrow/type.h"
#include "arrow/types/list.h"
#include "arrow/types/primitive.h"
#include "arrow/types/string.h"
#include "arrow/types/struct.h"
#include "arrow/util/buffer.h"
#include "arrow/util/status.h"
namespace arrow {
class ArrayBuilder;
#define BUILDER_CASE(ENUM, BuilderType) \
case Type::ENUM: \
out->reset(new BuilderType(pool, type)); \
return Status::OK();
// Initially looked at doing this with vtables, but shared pointers makes it
// difficult
//
// TODO(wesm): come up with a less monolithic strategy
Status MakeBuilder(MemoryPool* pool, const std::shared_ptr<DataType>& type,
std::shared_ptr<ArrayBuilder>* out) {
switch (type->type) {
BUILDER_CASE(UINT8, UInt8Builder);
BUILDER_CASE(INT8, Int8Builder);
BUILDER_CASE(UINT16, UInt16Builder);
BUILDER_CASE(INT16, Int16Builder);
BUILDER_CASE(UINT32, UInt32Builder);
BUILDER_CASE(INT32, Int32Builder);
BUILDER_CASE(UINT64, UInt64Builder);
BUILDER_CASE(INT64, Int64Builder);
BUILDER_CASE(TIMESTAMP, TimestampBuilder);
BUILDER_CASE(BOOL, BooleanBuilder);
BUILDER_CASE(FLOAT, FloatBuilder);
BUILDER_CASE(DOUBLE, DoubleBuilder);
BUILDER_CASE(STRING, StringBuilder);
BUILDER_CASE(BINARY, BinaryBuilder);
case Type::LIST: {
std::shared_ptr<ArrayBuilder> value_builder;
std::shared_ptr<DataType> value_type =
static_cast<ListType*>(type.get())->value_type();
RETURN_NOT_OK(MakeBuilder(pool, value_type, &value_builder));
out->reset(new ListBuilder(pool, value_builder));
return Status::OK();
}
case Type::STRUCT: {
std::vector<FieldPtr>& fields = type->children_;
std::vector<std::shared_ptr<ArrayBuilder>> values_builder;
for (auto it : fields) {
std::shared_ptr<ArrayBuilder> builder;
RETURN_NOT_OK(MakeBuilder(pool, it->type, &builder));
values_builder.push_back(builder);
}
out->reset(new StructBuilder(pool, type, values_builder));
return Status::OK();
}
default:
return Status::NotImplemented(type->ToString());
}
}
#define MAKE_PRIMITIVE_ARRAY_CASE(ENUM, ArrayType) \
case Type::ENUM: \
out->reset(new ArrayType(type, length, data, null_count, null_bitmap)); \
break;
Status MakePrimitiveArray(const TypePtr& type, int32_t length,
const std::shared_ptr<Buffer>& data, int32_t null_count,
const std::shared_ptr<Buffer>& null_bitmap, ArrayPtr* out) {
switch (type->type) {
MAKE_PRIMITIVE_ARRAY_CASE(BOOL, BooleanArray);
MAKE_PRIMITIVE_ARRAY_CASE(UINT8, UInt8Array);
MAKE_PRIMITIVE_ARRAY_CASE(INT8, Int8Array);
MAKE_PRIMITIVE_ARRAY_CASE(UINT16, UInt16Array);
MAKE_PRIMITIVE_ARRAY_CASE(INT16, Int16Array);
MAKE_PRIMITIVE_ARRAY_CASE(UINT32, UInt32Array);
MAKE_PRIMITIVE_ARRAY_CASE(INT32, Int32Array);
MAKE_PRIMITIVE_ARRAY_CASE(UINT64, UInt64Array);
MAKE_PRIMITIVE_ARRAY_CASE(INT64, Int64Array);
MAKE_PRIMITIVE_ARRAY_CASE(FLOAT, FloatArray);
MAKE_PRIMITIVE_ARRAY_CASE(DOUBLE, DoubleArray);
MAKE_PRIMITIVE_ARRAY_CASE(TIME, Int64Array);
MAKE_PRIMITIVE_ARRAY_CASE(TIMESTAMP, TimestampArray);
MAKE_PRIMITIVE_ARRAY_CASE(TIMESTAMP_DOUBLE, DoubleArray);
default:
return Status::NotImplemented(type->ToString());
}
#ifdef NDEBUG
return Status::OK();
#else
return (*out)->Validate();
#endif
}
} // namespace arrow
-47
View File
@@ -1,47 +0,0 @@
// 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.
#ifndef ARROW_TYPES_CONSTRUCT_H
#define ARROW_TYPES_CONSTRUCT_H
#include <cstdint>
#include <memory>
#include <vector>
#include "arrow/util/visibility.h"
namespace arrow {
class Array;
class ArrayBuilder;
class Buffer;
struct DataType;
struct Field;
class MemoryPool;
class Status;
Status ARROW_EXPORT MakeBuilder(MemoryPool* pool, const std::shared_ptr<DataType>& type,
std::shared_ptr<ArrayBuilder>* out);
// Create new arrays for logical types that are backed by primitive arrays.
Status ARROW_EXPORT MakePrimitiveArray(const std::shared_ptr<DataType>& type,
int32_t length, const std::shared_ptr<Buffer>& data, int32_t null_count,
const std::shared_ptr<Buffer>& null_bitmap, std::shared_ptr<Array>* out);
} // namespace arrow
#endif // ARROW_BUILDER_H_
-27
View File
@@ -1,27 +0,0 @@
// 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.
#ifndef ARROW_TYPES_DATETIME_H
#define ARROW_TYPES_DATETIME_H
#include <string>
#include "arrow/type.h"
namespace arrow {} // namespace arrow
#endif // ARROW_TYPES_DATETIME_H
-31
View File
@@ -1,31 +0,0 @@
// 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 "arrow/types/decimal.h"
#include <sstream>
#include <string>
namespace arrow {
std::string DecimalType::ToString() const {
std::stringstream s;
s << "decimal(" << precision << ", " << scale << ")";
return s.str();
}
} // namespace arrow
-28
View File
@@ -1,28 +0,0 @@
// 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.
#ifndef ARROW_TYPES_DECIMAL_H
#define ARROW_TYPES_DECIMAL_H
#include <string>
#include "arrow/type.h"
#include "arrow/util/visibility.h"
namespace arrow {} // namespace arrow
#endif // ARROW_TYPES_DECIMAL_H
-162
View File
@@ -1,162 +0,0 @@
// 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 "arrow/types/list.h"
#include <sstream>
namespace arrow {
bool ListArray::EqualsExact(const ListArray& other) const {
if (this == &other) { return true; }
if (null_count_ != other.null_count_) { return false; }
bool equal_offsets =
offset_buffer_->Equals(*other.offset_buffer_, (length_ + 1) * sizeof(int32_t));
if (!equal_offsets) { return false; }
bool equal_null_bitmap = true;
if (null_count_ > 0) {
equal_null_bitmap =
null_bitmap_->Equals(*other.null_bitmap_, BitUtil::BytesForBits(length_));
}
if (!equal_null_bitmap) { return false; }
return values()->Equals(other.values());
}
bool ListArray::Equals(const std::shared_ptr<Array>& arr) const {
if (this == arr.get()) { return true; }
if (this->type_enum() != arr->type_enum()) { return false; }
return EqualsExact(*static_cast<const ListArray*>(arr.get()));
}
bool ListArray::RangeEquals(int32_t start_idx, int32_t end_idx, int32_t other_start_idx,
const std::shared_ptr<Array>& arr) const {
if (this == arr.get()) { return true; }
if (!arr) { return false; }
if (this->type_enum() != arr->type_enum()) { return false; }
const auto other = static_cast<ListArray*>(arr.get());
for (int32_t i = start_idx, o_i = other_start_idx; i < end_idx; ++i, ++o_i) {
const bool is_null = IsNull(i);
if (is_null != arr->IsNull(o_i)) { return false; }
if (is_null) continue;
const int32_t begin_offset = offset(i);
const int32_t end_offset = offset(i + 1);
const int32_t other_begin_offset = other->offset(o_i);
const int32_t other_end_offset = other->offset(o_i + 1);
// Underlying can't be equal if the size isn't equal
if (end_offset - begin_offset != other_end_offset - other_begin_offset) {
return false;
}
if (!values_->RangeEquals(
begin_offset, end_offset, other_begin_offset, other->values())) {
return false;
}
}
return true;
}
Status ListArray::Validate() const {
if (length_ < 0) { return Status::Invalid("Length was negative"); }
if (!offset_buffer_) { return Status::Invalid("offset_buffer_ was null"); }
if (offset_buffer_->size() / static_cast<int>(sizeof(int32_t)) < length_) {
std::stringstream ss;
ss << "offset buffer size (bytes): " << offset_buffer_->size()
<< " isn't large enough for length: " << length_;
return Status::Invalid(ss.str());
}
const int32_t last_offset = offset(length_);
if (last_offset > 0) {
if (!values_) {
return Status::Invalid("last offset was non-zero and values was null");
}
if (values_->length() != last_offset) {
std::stringstream ss;
ss << "Final offset invariant not equal to values length: " << last_offset
<< "!=" << values_->length();
return Status::Invalid(ss.str());
}
const Status child_valid = values_->Validate();
if (!child_valid.ok()) {
std::stringstream ss;
ss << "Child array invalid: " << child_valid.ToString();
return Status::Invalid(ss.str());
}
}
int32_t prev_offset = offset(0);
if (prev_offset != 0) { return Status::Invalid("The first offset wasn't zero"); }
for (int32_t i = 1; i <= length_; ++i) {
int32_t current_offset = offset(i);
if (IsNull(i - 1) && current_offset != prev_offset) {
std::stringstream ss;
ss << "Offset invariant failure at: " << i << " inconsistent offsets for null slot"
<< current_offset << "!=" << prev_offset;
return Status::Invalid(ss.str());
}
if (current_offset < prev_offset) {
std::stringstream ss;
ss << "Offset invariant failure: " << i
<< " inconsistent offset for non-null slot: " << current_offset << "<"
<< prev_offset;
return Status::Invalid(ss.str());
}
prev_offset = current_offset;
}
return Status::OK();
}
Status ListBuilder::Init(int32_t elements) {
DCHECK_LT(elements, std::numeric_limits<int32_t>::max());
RETURN_NOT_OK(ArrayBuilder::Init(elements));
// one more then requested for offsets
return offset_builder_.Resize((elements + 1) * sizeof(int32_t));
}
Status ListBuilder::Resize(int32_t capacity) {
DCHECK_LT(capacity, std::numeric_limits<int32_t>::max());
// one more then requested for offsets
RETURN_NOT_OK(offset_builder_.Resize((capacity + 1) * sizeof(int32_t)));
return ArrayBuilder::Resize(capacity);
}
Status ListBuilder::Finish(std::shared_ptr<Array>* out) {
std::shared_ptr<Array> items = values_;
if (!items) { RETURN_NOT_OK(value_builder_->Finish(&items)); }
RETURN_NOT_OK(offset_builder_.Append<int32_t>(items->length()));
std::shared_ptr<Buffer> offsets = offset_builder_.Finish();
*out = std::make_shared<ListArray>(
type_, length_, offsets, items, null_count_, null_bitmap_);
Reset();
return Status::OK();
}
void ListBuilder::Reset() {
capacity_ = length_ = null_count_ = 0;
null_bitmap_ = nullptr;
}
Status ListArray::Accept(ArrayVisitor* visitor) const {
return visitor->Visit(*this);
}
} // namespace arrow
-170
View File
@@ -1,170 +0,0 @@
// 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.
#ifndef ARROW_TYPES_LIST_H
#define ARROW_TYPES_LIST_H
#include <cstdint>
#include <cstring>
#include <limits>
#include <memory>
#include "arrow/array.h"
#include "arrow/builder.h"
#include "arrow/type.h"
#include "arrow/types/primitive.h"
#include "arrow/util/bit-util.h"
#include "arrow/util/buffer.h"
#include "arrow/util/logging.h"
#include "arrow/util/status.h"
#include "arrow/util/visibility.h"
namespace arrow {
class MemoryPool;
class ARROW_EXPORT ListArray : public Array {
public:
using TypeClass = ListType;
ListArray(const TypePtr& type, int32_t length, std::shared_ptr<Buffer> offsets,
const ArrayPtr& values, int32_t null_count = 0,
std::shared_ptr<Buffer> null_bitmap = nullptr)
: Array(type, length, null_count, null_bitmap) {
offset_buffer_ = offsets;
offsets_ = offsets == nullptr ? nullptr : reinterpret_cast<const int32_t*>(
offset_buffer_->data());
values_ = values;
}
Status Validate() const override;
virtual ~ListArray() = default;
// Return a shared pointer in case the requestor desires to share ownership
// with this array.
std::shared_ptr<Array> values() const { return values_; }
std::shared_ptr<Buffer> offsets() const {
return std::static_pointer_cast<Buffer>(offset_buffer_);
}
std::shared_ptr<DataType> value_type() const { return values_->type(); }
const int32_t* raw_offsets() const { return offsets_; }
int32_t offset(int i) const { return offsets_[i]; }
// Neither of these functions will perform boundschecking
int32_t value_offset(int i) const { return offsets_[i]; }
int32_t value_length(int i) const { return offsets_[i + 1] - offsets_[i]; }
bool EqualsExact(const ListArray& other) const;
bool Equals(const std::shared_ptr<Array>& arr) const override;
bool RangeEquals(int32_t start_idx, int32_t end_idx, int32_t other_start_idx,
const ArrayPtr& arr) const override;
Status Accept(ArrayVisitor* visitor) const override;
protected:
std::shared_ptr<Buffer> offset_buffer_;
const int32_t* offsets_;
ArrayPtr values_;
};
// ----------------------------------------------------------------------
// Array builder
// Builder class for variable-length list array value types
//
// To use this class, you must append values to the child array builder and use
// the Append function to delimit each distinct list value (once the values
// have been appended to the child array) or use the bulk API to append
// a sequence of offests and null values.
//
// A note on types. Per arrow/type.h all types in the c++ implementation are
// logical so even though this class always builds list array, this can
// represent multiple different logical types. If no logical type is provided
// at construction time, the class defaults to List<T> where t is taken from the
// value_builder/values that the object is constructed with.
class ARROW_EXPORT ListBuilder : public ArrayBuilder {
public:
// Use this constructor to incrementally build the value array along with offsets and
// null bitmap.
ListBuilder(MemoryPool* pool, std::shared_ptr<ArrayBuilder> value_builder,
const TypePtr& type = nullptr)
: ArrayBuilder(
pool, type ? type : std::static_pointer_cast<DataType>(
std::make_shared<ListType>(value_builder->type()))),
offset_builder_(pool),
value_builder_(value_builder) {}
// Use this constructor to build the list with a pre-existing values array
ListBuilder(
MemoryPool* pool, std::shared_ptr<Array> values, const TypePtr& type = nullptr)
: ArrayBuilder(pool, type ? type : std::static_pointer_cast<DataType>(
std::make_shared<ListType>(values->type()))),
offset_builder_(pool),
values_(values) {}
virtual ~ListBuilder() {}
Status Init(int32_t elements) override;
Status Resize(int32_t capacity) override;
Status Finish(std::shared_ptr<Array>* out) override;
// Vector append
//
// If passed, valid_bytes is of equal length to values, and any zero byte
// will be considered as a null for that slot
Status Append(
const int32_t* offsets, int32_t length, const uint8_t* valid_bytes = nullptr) {
RETURN_NOT_OK(Reserve(length));
UnsafeAppendToBitmap(valid_bytes, length);
offset_builder_.UnsafeAppend<int32_t>(offsets, length);
return Status::OK();
}
// Start a new variable-length list slot
//
// This function should be called before beginning to append elements to the
// value builder
Status Append(bool is_valid = true) {
RETURN_NOT_OK(Reserve(1));
UnsafeAppendToBitmap(is_valid);
RETURN_NOT_OK(offset_builder_.Append<int32_t>(value_builder_->length()));
return Status::OK();
}
Status AppendNull() { return Append(false); }
std::shared_ptr<ArrayBuilder> value_builder() const {
DCHECK(!values_) << "Using value builder is pointless when values_ is set";
return value_builder_;
}
protected:
BufferBuilder offset_builder_;
std::shared_ptr<ArrayBuilder> value_builder_;
std::shared_ptr<Array> values_;
void Reset();
};
} // namespace arrow
#endif // ARROW_TYPES_LIST_H
-294
View File
@@ -1,294 +0,0 @@
// 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 "arrow/types/primitive.h"
#include <cmath>
#include <memory>
#include "arrow/type_traits.h"
#include "arrow/util/bit-util.h"
#include "arrow/util/buffer.h"
#include "arrow/util/logging.h"
namespace arrow {
// ----------------------------------------------------------------------
// Primitive array base
PrimitiveArray::PrimitiveArray(const TypePtr& type, int32_t length,
const std::shared_ptr<Buffer>& data, int32_t null_count,
const std::shared_ptr<Buffer>& null_bitmap)
: Array(type, length, null_count, null_bitmap) {
data_ = data;
raw_data_ = data == nullptr ? nullptr : data_->data();
}
bool PrimitiveArray::EqualsExact(const PrimitiveArray& other) const {
if (this == &other) { return true; }
if (null_count_ != other.null_count_) { return false; }
if (null_count_ > 0) {
bool equal_bitmap =
null_bitmap_->Equals(*other.null_bitmap_, BitUtil::CeilByte(length_) / 8);
if (!equal_bitmap) { return false; }
const uint8_t* this_data = raw_data_;
const uint8_t* other_data = other.raw_data_;
auto size_meta = dynamic_cast<const FixedWidthType*>(type_.get());
int value_byte_size = size_meta->bit_width() / 8;
DCHECK_GT(value_byte_size, 0);
for (int i = 0; i < length_; ++i) {
if (!IsNull(i) && memcmp(this_data, other_data, value_byte_size)) { return false; }
this_data += value_byte_size;
other_data += value_byte_size;
}
return true;
} else {
if (length_ == 0 && other.length_ == 0) { return true; }
return data_->Equals(*other.data_, length_);
}
}
bool PrimitiveArray::Equals(const std::shared_ptr<Array>& arr) const {
if (this == arr.get()) { return true; }
if (!arr) { return false; }
if (this->type_enum() != arr->type_enum()) { return false; }
return EqualsExact(*static_cast<const PrimitiveArray*>(arr.get()));
}
template <typename T>
Status NumericArray<T>::Accept(ArrayVisitor* visitor) const {
return visitor->Visit(*this);
}
template class NumericArray<UInt8Type>;
template class NumericArray<UInt16Type>;
template class NumericArray<UInt32Type>;
template class NumericArray<UInt64Type>;
template class NumericArray<Int8Type>;
template class NumericArray<Int16Type>;
template class NumericArray<Int32Type>;
template class NumericArray<Int64Type>;
template class NumericArray<TimestampType>;
template class NumericArray<HalfFloatType>;
template class NumericArray<FloatType>;
template class NumericArray<DoubleType>;
template <typename T>
Status PrimitiveBuilder<T>::Init(int32_t capacity) {
RETURN_NOT_OK(ArrayBuilder::Init(capacity));
data_ = std::make_shared<PoolBuffer>(pool_);
int64_t nbytes = TypeTraits<T>::bytes_required(capacity);
RETURN_NOT_OK(data_->Resize(nbytes));
// TODO(emkornfield) valgrind complains without this
memset(data_->mutable_data(), 0, nbytes);
raw_data_ = reinterpret_cast<value_type*>(data_->mutable_data());
return Status::OK();
}
template <typename T>
Status PrimitiveBuilder<T>::Resize(int32_t capacity) {
// XXX: Set floor size for now
if (capacity < kMinBuilderCapacity) { capacity = kMinBuilderCapacity; }
if (capacity_ == 0) {
RETURN_NOT_OK(Init(capacity));
} else {
RETURN_NOT_OK(ArrayBuilder::Resize(capacity));
const int64_t old_bytes = data_->size();
const int64_t new_bytes = TypeTraits<T>::bytes_required(capacity);
RETURN_NOT_OK(data_->Resize(new_bytes));
raw_data_ = reinterpret_cast<value_type*>(data_->mutable_data());
memset(data_->mutable_data() + old_bytes, 0, new_bytes - old_bytes);
}
return Status::OK();
}
template <typename T>
Status PrimitiveBuilder<T>::Append(
const value_type* values, int32_t length, const uint8_t* valid_bytes) {
RETURN_NOT_OK(Reserve(length));
if (length > 0) {
memcpy(raw_data_ + length_, values, TypeTraits<T>::bytes_required(length));
}
// length_ is update by these
ArrayBuilder::UnsafeAppendToBitmap(valid_bytes, length);
return Status::OK();
}
template <typename T>
Status PrimitiveBuilder<T>::Finish(std::shared_ptr<Array>* out) {
const int64_t bytes_required = TypeTraits<T>::bytes_required(length_);
if (bytes_required > 0 && bytes_required < data_->size()) {
// Trim buffers
RETURN_NOT_OK(data_->Resize(bytes_required));
}
*out = std::make_shared<typename TypeTraits<T>::ArrayType>(
type_, length_, data_, null_count_, null_bitmap_);
data_ = null_bitmap_ = nullptr;
capacity_ = length_ = null_count_ = 0;
return Status::OK();
}
template class PrimitiveBuilder<UInt8Type>;
template class PrimitiveBuilder<UInt16Type>;
template class PrimitiveBuilder<UInt32Type>;
template class PrimitiveBuilder<UInt64Type>;
template class PrimitiveBuilder<Int8Type>;
template class PrimitiveBuilder<Int16Type>;
template class PrimitiveBuilder<Int32Type>;
template class PrimitiveBuilder<Int64Type>;
template class PrimitiveBuilder<TimestampType>;
template class PrimitiveBuilder<HalfFloatType>;
template class PrimitiveBuilder<FloatType>;
template class PrimitiveBuilder<DoubleType>;
Status BooleanBuilder::Init(int32_t capacity) {
RETURN_NOT_OK(ArrayBuilder::Init(capacity));
data_ = std::make_shared<PoolBuffer>(pool_);
int64_t nbytes = BitUtil::BytesForBits(capacity);
RETURN_NOT_OK(data_->Resize(nbytes));
// TODO(emkornfield) valgrind complains without this
memset(data_->mutable_data(), 0, nbytes);
raw_data_ = reinterpret_cast<uint8_t*>(data_->mutable_data());
return Status::OK();
}
Status BooleanBuilder::Resize(int32_t capacity) {
// XXX: Set floor size for now
if (capacity < kMinBuilderCapacity) { capacity = kMinBuilderCapacity; }
if (capacity_ == 0) {
RETURN_NOT_OK(Init(capacity));
} else {
RETURN_NOT_OK(ArrayBuilder::Resize(capacity));
const int64_t old_bytes = data_->size();
const int64_t new_bytes = BitUtil::BytesForBits(capacity);
RETURN_NOT_OK(data_->Resize(new_bytes));
raw_data_ = reinterpret_cast<uint8_t*>(data_->mutable_data());
memset(data_->mutable_data() + old_bytes, 0, new_bytes - old_bytes);
}
return Status::OK();
}
Status BooleanBuilder::Finish(std::shared_ptr<Array>* out) {
const int64_t bytes_required = BitUtil::BytesForBits(length_);
if (bytes_required > 0 && bytes_required < data_->size()) {
// Trim buffers
RETURN_NOT_OK(data_->Resize(bytes_required));
}
*out = std::make_shared<BooleanArray>(type_, length_, data_, null_count_, null_bitmap_);
data_ = null_bitmap_ = nullptr;
capacity_ = length_ = null_count_ = 0;
return Status::OK();
}
Status BooleanBuilder::Append(
const uint8_t* values, int32_t length, const uint8_t* valid_bytes) {
RETURN_NOT_OK(Reserve(length));
for (int i = 0; i < length; ++i) {
// Skip reading from unitialised memory
// TODO: This actually is only to keep valgrind happy but may or may not
// have a performance impact.
if ((valid_bytes != nullptr) && !valid_bytes[i]) continue;
if (values[i] > 0) {
BitUtil::SetBit(raw_data_, length_ + i);
} else {
BitUtil::ClearBit(raw_data_, length_ + i);
}
}
// this updates length_
ArrayBuilder::UnsafeAppendToBitmap(valid_bytes, length);
return Status::OK();
}
BooleanArray::BooleanArray(int32_t length, const std::shared_ptr<Buffer>& data,
int32_t null_count, const std::shared_ptr<Buffer>& null_bitmap)
: PrimitiveArray(
std::make_shared<BooleanType>(), length, data, null_count, null_bitmap) {}
BooleanArray::BooleanArray(const TypePtr& type, int32_t length,
const std::shared_ptr<Buffer>& data, int32_t null_count,
const std::shared_ptr<Buffer>& null_bitmap)
: PrimitiveArray(type, length, data, null_count, null_bitmap) {}
bool BooleanArray::EqualsExact(const BooleanArray& other) const {
if (this == &other) return true;
if (null_count_ != other.null_count_) { return false; }
if (null_count_ > 0) {
bool equal_bitmap =
null_bitmap_->Equals(*other.null_bitmap_, BitUtil::BytesForBits(length_));
if (!equal_bitmap) { return false; }
const uint8_t* this_data = raw_data_;
const uint8_t* other_data = other.raw_data_;
for (int i = 0; i < length_; ++i) {
if (!IsNull(i) && BitUtil::GetBit(this_data, i) != BitUtil::GetBit(other_data, i)) {
return false;
}
}
return true;
} else {
return data_->Equals(*other.data_, BitUtil::BytesForBits(length_));
}
}
bool BooleanArray::Equals(const ArrayPtr& arr) const {
if (this == arr.get()) return true;
if (Type::BOOL != arr->type_enum()) { return false; }
return EqualsExact(*static_cast<const BooleanArray*>(arr.get()));
}
bool BooleanArray::RangeEquals(int32_t start_idx, int32_t end_idx,
int32_t other_start_idx, const ArrayPtr& arr) const {
if (this == arr.get()) { return true; }
if (!arr) { return false; }
if (this->type_enum() != arr->type_enum()) { return false; }
const auto other = static_cast<BooleanArray*>(arr.get());
for (int32_t i = start_idx, o_i = other_start_idx; i < end_idx; ++i, ++o_i) {
const bool is_null = IsNull(i);
if (is_null != arr->IsNull(o_i) || (!is_null && Value(i) != other->Value(o_i))) {
return false;
}
}
return true;
}
Status BooleanArray::Accept(ArrayVisitor* visitor) const {
return visitor->Visit(*this);
}
} // namespace arrow
-371
View File
@@ -1,371 +0,0 @@
// 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.
#ifndef ARROW_TYPES_PRIMITIVE_H
#define ARROW_TYPES_PRIMITIVE_H
#include <cmath>
#include <cstdint>
#include <cstring>
#include <iostream>
#include <memory>
#include <vector>
#include "arrow/array.h"
#include "arrow/builder.h"
#include "arrow/type.h"
#include "arrow/type_fwd.h"
#include "arrow/types/datetime.h"
#include "arrow/util/bit-util.h"
#include "arrow/util/buffer.h"
#include "arrow/util/status.h"
#include "arrow/util/visibility.h"
namespace arrow {
class MemoryPool;
// Base class for fixed-size logical types. See MakePrimitiveArray
// (types/construct.h) for constructing a specific subclass.
class ARROW_EXPORT PrimitiveArray : public Array {
public:
virtual ~PrimitiveArray() {}
std::shared_ptr<Buffer> data() const { return data_; }
bool EqualsExact(const PrimitiveArray& other) const;
bool Equals(const std::shared_ptr<Array>& arr) const override;
protected:
PrimitiveArray(const TypePtr& type, int32_t length, const std::shared_ptr<Buffer>& data,
int32_t null_count = 0, const std::shared_ptr<Buffer>& null_bitmap = nullptr);
std::shared_ptr<Buffer> data_;
const uint8_t* raw_data_;
};
template <typename TYPE>
class ARROW_EXPORT NumericArray : public PrimitiveArray {
public:
using TypeClass = TYPE;
using value_type = typename TypeClass::c_type;
NumericArray(int32_t length, const std::shared_ptr<Buffer>& data,
int32_t null_count = 0, const std::shared_ptr<Buffer>& null_bitmap = nullptr)
: PrimitiveArray(
std::make_shared<TypeClass>(), length, data, null_count, null_bitmap) {}
NumericArray(const TypePtr& type, int32_t length, const std::shared_ptr<Buffer>& data,
int32_t null_count = 0, const std::shared_ptr<Buffer>& null_bitmap = nullptr)
: PrimitiveArray(type, length, data, null_count, null_bitmap) {}
bool EqualsExact(const NumericArray<TypeClass>& other) const {
return PrimitiveArray::EqualsExact(static_cast<const PrimitiveArray&>(other));
}
bool ApproxEquals(const std::shared_ptr<Array>& arr) const { return Equals(arr); }
bool RangeEquals(int32_t start_idx, int32_t end_idx, int32_t other_start_idx,
const ArrayPtr& arr) const override {
if (this == arr.get()) { return true; }
if (!arr) { return false; }
if (this->type_enum() != arr->type_enum()) { return false; }
const auto other = static_cast<NumericArray<TypeClass>*>(arr.get());
for (int32_t i = start_idx, o_i = other_start_idx; i < end_idx; ++i, ++o_i) {
const bool is_null = IsNull(i);
if (is_null != arr->IsNull(o_i) || (!is_null && Value(i) != other->Value(o_i))) {
return false;
}
}
return true;
}
const value_type* raw_data() const {
return reinterpret_cast<const value_type*>(raw_data_);
}
Status Accept(ArrayVisitor* visitor) const override;
value_type Value(int i) const { return raw_data()[i]; }
};
template <>
inline bool NumericArray<FloatType>::ApproxEquals(
const std::shared_ptr<Array>& arr) const {
if (this == arr.get()) { return true; }
if (!arr) { return false; }
if (this->type_enum() != arr->type_enum()) { return false; }
const auto& other = *static_cast<NumericArray<FloatType>*>(arr.get());
if (this == &other) { return true; }
if (null_count_ != other.null_count_) { return false; }
auto this_data = reinterpret_cast<const float*>(raw_data_);
auto other_data = reinterpret_cast<const float*>(other.raw_data_);
static constexpr float EPSILON = 1E-5;
if (length_ == 0 && other.length_ == 0) { return true; }
if (null_count_ > 0) {
bool equal_bitmap =
null_bitmap_->Equals(*other.null_bitmap_, BitUtil::CeilByte(length_) / 8);
if (!equal_bitmap) { return false; }
for (int i = 0; i < length_; ++i) {
if (IsNull(i)) continue;
if (fabs(this_data[i] - other_data[i]) > EPSILON) { return false; }
}
} else {
for (int i = 0; i < length_; ++i) {
if (fabs(this_data[i] - other_data[i]) > EPSILON) { return false; }
}
}
return true;
}
template <>
inline bool NumericArray<DoubleType>::ApproxEquals(
const std::shared_ptr<Array>& arr) const {
if (this == arr.get()) { return true; }
if (!arr) { return false; }
if (this->type_enum() != arr->type_enum()) { return false; }
const auto& other = *static_cast<NumericArray<DoubleType>*>(arr.get());
if (this == &other) { return true; }
if (null_count_ != other.null_count_) { return false; }
auto this_data = reinterpret_cast<const double*>(raw_data_);
auto other_data = reinterpret_cast<const double*>(other.raw_data_);
if (length_ == 0 && other.length_ == 0) { return true; }
static constexpr double EPSILON = 1E-5;
if (null_count_ > 0) {
bool equal_bitmap =
null_bitmap_->Equals(*other.null_bitmap_, BitUtil::CeilByte(length_) / 8);
if (!equal_bitmap) { return false; }
for (int i = 0; i < length_; ++i) {
if (IsNull(i)) continue;
if (fabs(this_data[i] - other_data[i]) > EPSILON) { return false; }
}
} else {
for (int i = 0; i < length_; ++i) {
if (fabs(this_data[i] - other_data[i]) > EPSILON) { return false; }
}
}
return true;
}
template <typename Type>
class ARROW_EXPORT PrimitiveBuilder : public ArrayBuilder {
public:
using value_type = typename Type::c_type;
explicit PrimitiveBuilder(MemoryPool* pool, const TypePtr& type)
: ArrayBuilder(pool, type), data_(nullptr) {}
virtual ~PrimitiveBuilder() {}
using ArrayBuilder::Advance;
// Write nulls as uint8_t* (0 value indicates null) into pre-allocated memory
Status AppendNulls(const uint8_t* valid_bytes, int32_t length) {
RETURN_NOT_OK(Reserve(length));
UnsafeAppendToBitmap(valid_bytes, length);
return Status::OK();
}
Status AppendNull() {
RETURN_NOT_OK(Reserve(1));
UnsafeAppendToBitmap(false);
return Status::OK();
}
std::shared_ptr<Buffer> data() const { return data_; }
// Vector append
//
// If passed, valid_bytes is of equal length to values, and any zero byte
// will be considered as a null for that slot
Status Append(
const value_type* values, int32_t length, const uint8_t* valid_bytes = nullptr);
Status Finish(std::shared_ptr<Array>* out) override;
Status Init(int32_t capacity) override;
// Increase the capacity of the builder to accommodate at least the indicated
// number of elements
Status Resize(int32_t capacity) override;
protected:
std::shared_ptr<PoolBuffer> data_;
value_type* raw_data_;
};
template <typename T>
class ARROW_EXPORT NumericBuilder : public PrimitiveBuilder<T> {
public:
using typename PrimitiveBuilder<T>::value_type;
using PrimitiveBuilder<T>::PrimitiveBuilder;
using PrimitiveBuilder<T>::Append;
using PrimitiveBuilder<T>::Init;
using PrimitiveBuilder<T>::Resize;
using PrimitiveBuilder<T>::Reserve;
// Scalar append.
Status Append(value_type val) {
RETURN_NOT_OK(ArrayBuilder::Reserve(1));
UnsafeAppend(val);
return Status::OK();
}
// Does not capacity-check; make sure to call Reserve beforehand
void UnsafeAppend(value_type val) {
BitUtil::SetBit(null_bitmap_data_, length_);
raw_data_[length_++] = val;
}
protected:
using PrimitiveBuilder<T>::length_;
using PrimitiveBuilder<T>::null_bitmap_data_;
using PrimitiveBuilder<T>::raw_data_;
};
// Builders
using UInt8Builder = NumericBuilder<UInt8Type>;
using UInt16Builder = NumericBuilder<UInt16Type>;
using UInt32Builder = NumericBuilder<UInt32Type>;
using UInt64Builder = NumericBuilder<UInt64Type>;
using Int8Builder = NumericBuilder<Int8Type>;
using Int16Builder = NumericBuilder<Int16Type>;
using Int32Builder = NumericBuilder<Int32Type>;
using Int64Builder = NumericBuilder<Int64Type>;
using TimestampBuilder = NumericBuilder<TimestampType>;
using HalfFloatBuilder = NumericBuilder<HalfFloatType>;
using FloatBuilder = NumericBuilder<FloatType>;
using DoubleBuilder = NumericBuilder<DoubleType>;
class ARROW_EXPORT BooleanArray : public PrimitiveArray {
public:
using TypeClass = BooleanType;
BooleanArray(int32_t length, const std::shared_ptr<Buffer>& data,
int32_t null_count = 0, const std::shared_ptr<Buffer>& null_bitmap = nullptr);
BooleanArray(const TypePtr& type, int32_t length, const std::shared_ptr<Buffer>& data,
int32_t null_count = 0, const std::shared_ptr<Buffer>& null_bitmap = nullptr);
bool EqualsExact(const BooleanArray& other) const;
bool Equals(const ArrayPtr& arr) const override;
bool RangeEquals(int32_t start_idx, int32_t end_idx, int32_t other_start_idx,
const ArrayPtr& arr) const override;
Status Accept(ArrayVisitor* visitor) const override;
const uint8_t* raw_data() const { return reinterpret_cast<const uint8_t*>(raw_data_); }
bool Value(int i) const { return BitUtil::GetBit(raw_data(), i); }
};
class ARROW_EXPORT BooleanBuilder : public ArrayBuilder {
public:
explicit BooleanBuilder(MemoryPool* pool, const TypePtr& type)
: ArrayBuilder(pool, type), data_(nullptr) {}
virtual ~BooleanBuilder() {}
using ArrayBuilder::Advance;
// Write nulls as uint8_t* (0 value indicates null) into pre-allocated memory
Status AppendNulls(const uint8_t* valid_bytes, int32_t length) {
RETURN_NOT_OK(Reserve(length));
UnsafeAppendToBitmap(valid_bytes, length);
return Status::OK();
}
Status AppendNull() {
RETURN_NOT_OK(Reserve(1));
UnsafeAppendToBitmap(false);
return Status::OK();
}
std::shared_ptr<Buffer> data() const { return data_; }
// Scalar append
Status Append(bool val) {
Reserve(1);
BitUtil::SetBit(null_bitmap_data_, length_);
if (val) {
BitUtil::SetBit(raw_data_, length_);
} else {
BitUtil::ClearBit(raw_data_, length_);
}
++length_;
return Status::OK();
}
// Vector append
//
// If passed, valid_bytes is of equal length to values, and any zero byte
// will be considered as a null for that slot
Status Append(
const uint8_t* values, int32_t length, const uint8_t* valid_bytes = nullptr);
Status Finish(std::shared_ptr<Array>* out) override;
Status Init(int32_t capacity) override;
// Increase the capacity of the builder to accommodate at least the indicated
// number of elements
Status Resize(int32_t capacity) override;
protected:
std::shared_ptr<PoolBuffer> data_;
uint8_t* raw_data_;
};
// gcc and clang disagree about how to handle template visibility when you have
// explicit specializations https://llvm.org/bugs/show_bug.cgi?id=24815
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wattributes"
#endif
// Only instantiate these templates once
extern template class ARROW_EXPORT NumericArray<Int8Type>;
extern template class ARROW_EXPORT NumericArray<UInt8Type>;
extern template class ARROW_EXPORT NumericArray<Int16Type>;
extern template class ARROW_EXPORT NumericArray<UInt16Type>;
extern template class ARROW_EXPORT NumericArray<Int32Type>;
extern template class ARROW_EXPORT NumericArray<UInt32Type>;
extern template class ARROW_EXPORT NumericArray<Int64Type>;
extern template class ARROW_EXPORT NumericArray<UInt64Type>;
extern template class ARROW_EXPORT NumericArray<HalfFloatType>;
extern template class ARROW_EXPORT NumericArray<FloatType>;
extern template class ARROW_EXPORT NumericArray<DoubleType>;
extern template class ARROW_EXPORT NumericArray<TimestampType>;
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif
} // namespace arrow
#endif // ARROW_TYPES_PRIMITIVE_H
-150
View File
@@ -1,150 +0,0 @@
// 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 "arrow/types/string.h"
#include <cstring>
#include <sstream>
#include <string>
#include "arrow/type.h"
namespace arrow {
static std::shared_ptr<DataType> kBinary = std::make_shared<BinaryType>();
static std::shared_ptr<DataType> kString = std::make_shared<StringType>();
BinaryArray::BinaryArray(int32_t length, const std::shared_ptr<Buffer>& offsets,
const std::shared_ptr<Buffer>& data, int32_t null_count,
const std::shared_ptr<Buffer>& null_bitmap)
: BinaryArray(kBinary, length, offsets, data, null_count, null_bitmap) {}
BinaryArray::BinaryArray(const TypePtr& type, int32_t length,
const std::shared_ptr<Buffer>& offsets, const std::shared_ptr<Buffer>& data,
int32_t null_count, const std::shared_ptr<Buffer>& null_bitmap)
: Array(type, length, null_count, null_bitmap),
offset_buffer_(offsets),
offsets_(reinterpret_cast<const int32_t*>(offset_buffer_->data())),
data_buffer_(data),
data_(nullptr) {
if (data_buffer_ != nullptr) { data_ = data_buffer_->data(); }
}
Status BinaryArray::Validate() const {
// TODO(wesm): what to do here?
return Status::OK();
}
bool BinaryArray::EqualsExact(const BinaryArray& other) const {
if (!Array::EqualsExact(other)) { return false; }
bool equal_offsets =
offset_buffer_->Equals(*other.offset_buffer_, (length_ + 1) * sizeof(int32_t));
if (!equal_offsets) { return false; }
if (!data_buffer_ && !(other.data_buffer_)) { return true; }
return data_buffer_->Equals(*other.data_buffer_, data_buffer_->size());
}
bool BinaryArray::Equals(const std::shared_ptr<Array>& arr) const {
if (this == arr.get()) { return true; }
if (this->type_enum() != arr->type_enum()) { return false; }
return EqualsExact(*static_cast<const BinaryArray*>(arr.get()));
}
bool BinaryArray::RangeEquals(int32_t start_idx, int32_t end_idx, int32_t other_start_idx,
const std::shared_ptr<Array>& arr) const {
if (this == arr.get()) { return true; }
if (!arr) { return false; }
if (this->type_enum() != arr->type_enum()) { return false; }
const auto other = static_cast<const BinaryArray*>(arr.get());
for (int32_t i = start_idx, o_i = other_start_idx; i < end_idx; ++i, ++o_i) {
const bool is_null = IsNull(i);
if (is_null != arr->IsNull(o_i)) { return false; }
if (is_null) continue;
const int32_t begin_offset = offset(i);
const int32_t end_offset = offset(i + 1);
const int32_t other_begin_offset = other->offset(o_i);
const int32_t other_end_offset = other->offset(o_i + 1);
// Underlying can't be equal if the size isn't equal
if (end_offset - begin_offset != other_end_offset - other_begin_offset) {
return false;
}
if (std::memcmp(data_ + begin_offset, other->data_ + other_begin_offset,
end_offset - begin_offset)) {
return false;
}
}
return true;
}
Status BinaryArray::Accept(ArrayVisitor* visitor) const {
return visitor->Visit(*this);
}
StringArray::StringArray(int32_t length, const std::shared_ptr<Buffer>& offsets,
const std::shared_ptr<Buffer>& data, int32_t null_count,
const std::shared_ptr<Buffer>& null_bitmap)
: BinaryArray(kString, length, offsets, data, null_count, null_bitmap) {}
Status StringArray::Validate() const {
// TODO(emkornfield) Validate proper UTF8 code points?
return BinaryArray::Validate();
}
Status StringArray::Accept(ArrayVisitor* visitor) const {
return visitor->Visit(*this);
}
// This used to be a static member variable of BinaryBuilder, but it can cause
// valgrind to report a (spurious?) memory leak when needed in other shared
// libraries. The problem came up while adding explicit visibility to libarrow
// and libparquet_arrow
static TypePtr kBinaryValueType = TypePtr(new UInt8Type());
BinaryBuilder::BinaryBuilder(MemoryPool* pool, const TypePtr& type)
: ListBuilder(pool, std::make_shared<UInt8Builder>(pool, kBinaryValueType), type) {
byte_builder_ = static_cast<UInt8Builder*>(value_builder_.get());
}
Status BinaryBuilder::Finish(std::shared_ptr<Array>* out) {
std::shared_ptr<Array> result;
RETURN_NOT_OK(ListBuilder::Finish(&result));
const auto list = std::dynamic_pointer_cast<ListArray>(result);
auto values = std::dynamic_pointer_cast<UInt8Array>(list->values());
*out = std::make_shared<BinaryArray>(list->length(), list->offsets(), values->data(),
list->null_count(), list->null_bitmap());
return Status::OK();
}
Status StringBuilder::Finish(std::shared_ptr<Array>* out) {
std::shared_ptr<Array> result;
RETURN_NOT_OK(ListBuilder::Finish(&result));
const auto list = std::dynamic_pointer_cast<ListArray>(result);
auto values = std::dynamic_pointer_cast<UInt8Array>(list->values());
*out = std::make_shared<StringArray>(list->length(), list->offsets(), values->data(),
list->null_count(), list->null_bitmap());
return Status::OK();
}
} // namespace arrow
-149
View File
@@ -1,149 +0,0 @@
// 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.
#ifndef ARROW_TYPES_STRING_H
#define ARROW_TYPES_STRING_H
#include <cstdint>
#include <memory>
#include <string>
#include <vector>
#include "arrow/array.h"
#include "arrow/type.h"
#include "arrow/types/list.h"
#include "arrow/types/primitive.h"
#include "arrow/util/status.h"
#include "arrow/util/visibility.h"
namespace arrow {
class Buffer;
class MemoryPool;
class ARROW_EXPORT BinaryArray : public Array {
public:
using TypeClass = BinaryType;
BinaryArray(int32_t length, const std::shared_ptr<Buffer>& offsets,
const std::shared_ptr<Buffer>& data, int32_t null_count = 0,
const std::shared_ptr<Buffer>& null_bitmap = nullptr);
// Constructor that allows sub-classes/builders to propagate there logical type up the
// class hierarchy.
BinaryArray(const TypePtr& type, int32_t length, const std::shared_ptr<Buffer>& offsets,
const std::shared_ptr<Buffer>& data, int32_t null_count = 0,
const std::shared_ptr<Buffer>& null_bitmap = nullptr);
// Return the pointer to the given elements bytes
// TODO(emkornfield) introduce a StringPiece or something similar to capture zero-copy
// pointer + offset
const uint8_t* GetValue(int i, int32_t* out_length) const {
DCHECK(out_length);
const int32_t pos = offsets_[i];
*out_length = offsets_[i + 1] - pos;
return data_ + pos;
}
std::shared_ptr<Buffer> data() const { return data_buffer_; }
std::shared_ptr<Buffer> offsets() const { return offset_buffer_; }
const int32_t* raw_offsets() const { return offsets_; }
int32_t offset(int i) const { return offsets_[i]; }
// Neither of these functions will perform boundschecking
int32_t value_offset(int i) const { return offsets_[i]; }
int32_t value_length(int i) const { return offsets_[i + 1] - offsets_[i]; }
bool EqualsExact(const BinaryArray& other) const;
bool Equals(const std::shared_ptr<Array>& arr) const override;
bool RangeEquals(int32_t start_idx, int32_t end_idx, int32_t other_start_idx,
const ArrayPtr& arr) const override;
Status Validate() const override;
Status Accept(ArrayVisitor* visitor) const override;
private:
std::shared_ptr<Buffer> offset_buffer_;
const int32_t* offsets_;
std::shared_ptr<Buffer> data_buffer_;
const uint8_t* data_;
};
class ARROW_EXPORT StringArray : public BinaryArray {
public:
using TypeClass = StringType;
StringArray(int32_t length, const std::shared_ptr<Buffer>& offsets,
const std::shared_ptr<Buffer>& data, int32_t null_count = 0,
const std::shared_ptr<Buffer>& null_bitmap = nullptr);
// Construct a std::string
// TODO: std::bad_alloc possibility
std::string GetString(int i) const {
int32_t nchars;
const uint8_t* str = GetValue(i, &nchars);
return std::string(reinterpret_cast<const char*>(str), nchars);
}
Status Validate() const override;
Status Accept(ArrayVisitor* visitor) const override;
};
// BinaryBuilder : public ListBuilder
class ARROW_EXPORT BinaryBuilder : public ListBuilder {
public:
explicit BinaryBuilder(MemoryPool* pool, const TypePtr& type);
virtual ~BinaryBuilder() {}
Status Append(const uint8_t* value, int32_t length) {
RETURN_NOT_OK(ListBuilder::Append());
return byte_builder_->Append(value, length);
}
Status Append(const char* value, int32_t length) {
return Append(reinterpret_cast<const uint8_t*>(value), length);
}
Status Append(const std::string& value) { return Append(value.c_str(), value.size()); }
Status Finish(std::shared_ptr<Array>* out) override;
protected:
UInt8Builder* byte_builder_;
};
// String builder
class ARROW_EXPORT StringBuilder : public BinaryBuilder {
public:
explicit StringBuilder(MemoryPool* pool, const TypePtr& type)
: BinaryBuilder(pool, type) {}
using BinaryBuilder::Append;
Status Finish(std::shared_ptr<Array>* out) override;
Status Append(const std::vector<std::string>& values, uint8_t* null_bytes);
};
} // namespace arrow
#endif // ARROW_TYPES_STRING_H
-108
View File
@@ -1,108 +0,0 @@
// 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 "arrow/types/struct.h"
#include <sstream>
namespace arrow {
bool StructArray::Equals(const std::shared_ptr<Array>& arr) const {
if (this == arr.get()) { return true; }
if (!arr) { return false; }
if (this->type_enum() != arr->type_enum()) { return false; }
if (null_count_ != arr->null_count()) { return false; }
return RangeEquals(0, length_, 0, arr);
}
bool StructArray::RangeEquals(int32_t start_idx, int32_t end_idx, int32_t other_start_idx,
const std::shared_ptr<Array>& arr) const {
if (this == arr.get()) { return true; }
if (!arr) { return false; }
if (Type::STRUCT != arr->type_enum()) { return false; }
const auto other = static_cast<StructArray*>(arr.get());
bool equal_fields = true;
for (int32_t i = start_idx, o_i = other_start_idx; i < end_idx; ++i, ++o_i) {
if (IsNull(i) != arr->IsNull(o_i)) { return false; }
if (IsNull(i)) continue;
for (size_t j = 0; j < field_arrays_.size(); ++j) {
// TODO: really we should be comparing stretches of non-null data rather
// than looking at one value at a time.
equal_fields = field(j)->RangeEquals(i, i + 1, o_i, other->field(j));
if (!equal_fields) { return false; }
}
}
return true;
}
Status StructArray::Validate() const {
if (length_ < 0) { return Status::Invalid("Length was negative"); }
if (null_count() > length_) {
return Status::Invalid("Null count exceeds the length of this struct");
}
if (field_arrays_.size() > 0) {
// Validate fields
int32_t array_length = field_arrays_[0]->length();
size_t idx = 0;
for (auto it : field_arrays_) {
if (it->length() != array_length) {
std::stringstream ss;
ss << "Length is not equal from field " << it->type()->ToString()
<< " at position {" << idx << "}";
return Status::Invalid(ss.str());
}
const Status child_valid = it->Validate();
if (!child_valid.ok()) {
std::stringstream ss;
ss << "Child array invalid: " << child_valid.ToString() << " at position {" << idx
<< "}";
return Status::Invalid(ss.str());
}
++idx;
}
if (array_length > 0 && array_length != length_) {
return Status::Invalid("Struct's length is not equal to its child arrays");
}
}
return Status::OK();
}
Status StructArray::Accept(ArrayVisitor* visitor) const {
return visitor->Visit(*this);
}
Status StructBuilder::Finish(std::shared_ptr<Array>* out) {
std::vector<std::shared_ptr<Array>> fields(field_builders_.size());
for (size_t i = 0; i < field_builders_.size(); ++i) {
RETURN_NOT_OK(field_builders_[i]->Finish(&fields[i]));
}
*out = std::make_shared<StructArray>(type_, length_, fields, null_count_, null_bitmap_);
null_bitmap_ = nullptr;
capacity_ = length_ = null_count_ = 0;
return Status::OK();
}
} // namespace arrow
-116
View File
@@ -1,116 +0,0 @@
// 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.
#ifndef ARROW_TYPES_STRUCT_H
#define ARROW_TYPES_STRUCT_H
#include <memory>
#include <string>
#include <vector>
#include "arrow/type.h"
#include "arrow/types/list.h"
#include "arrow/types/primitive.h"
#include "arrow/util/visibility.h"
namespace arrow {
class ARROW_EXPORT StructArray : public Array {
public:
using TypeClass = StructType;
StructArray(const TypePtr& type, int32_t length, std::vector<ArrayPtr>& field_arrays,
int32_t null_count = 0, std::shared_ptr<Buffer> null_bitmap = nullptr)
: Array(type, length, null_count, null_bitmap) {
type_ = type;
field_arrays_ = field_arrays;
}
Status Validate() const override;
virtual ~StructArray() {}
// Return a shared pointer in case the requestor desires to share ownership
// with this array.
std::shared_ptr<Array> field(int32_t pos) const {
DCHECK_GT(field_arrays_.size(), 0);
return field_arrays_[pos];
}
const std::vector<ArrayPtr>& fields() const { return field_arrays_; }
bool EqualsExact(const StructArray& other) const;
bool Equals(const std::shared_ptr<Array>& arr) const override;
bool RangeEquals(int32_t start_idx, int32_t end_idx, int32_t other_start_idx,
const std::shared_ptr<Array>& arr) const override;
Status Accept(ArrayVisitor* visitor) const override;
protected:
// The child arrays corresponding to each field of the struct data type.
std::vector<ArrayPtr> field_arrays_;
};
// ---------------------------------------------------------------------------------
// StructArray builder
// Append, Resize and Reserve methods are acting on StructBuilder.
// Please make sure all these methods of all child-builders' are consistently
// called to maintain data-structure consistency.
class ARROW_EXPORT StructBuilder : public ArrayBuilder {
public:
StructBuilder(MemoryPool* pool, const std::shared_ptr<DataType>& type,
const std::vector<std::shared_ptr<ArrayBuilder>>& field_builders)
: ArrayBuilder(pool, type) {
field_builders_ = field_builders;
}
Status Finish(std::shared_ptr<Array>* out) override;
// Null bitmap is of equal length to every child field, and any zero byte
// will be considered as a null for that field, but users must using app-
// end methods or advance methods of the child builders' independently to
// insert data.
Status Append(int32_t length, const uint8_t* valid_bytes) {
RETURN_NOT_OK(Reserve(length));
UnsafeAppendToBitmap(valid_bytes, length);
return Status::OK();
}
// Append an element to the Struct. All child-builders' Append method must
// be called independently to maintain data-structure consistency.
Status Append(bool is_valid = true) {
RETURN_NOT_OK(Reserve(1));
UnsafeAppendToBitmap(is_valid);
return Status::OK();
}
Status AppendNull() { return Append(false); }
std::shared_ptr<ArrayBuilder> field_builder(int pos) const {
DCHECK_GT(field_builders_.size(), 0);
return field_builders_[pos];
}
const std::vector<std::shared_ptr<ArrayBuilder>>& field_builders() const {
return field_builders_;
}
protected:
std::vector<std::shared_ptr<ArrayBuilder>> field_builders_;
};
} // namespace arrow
#endif // ARROW_TYPES_STRUCT_H
-70
View File
@@ -1,70 +0,0 @@
// 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.
#ifndef ARROW_TYPES_TEST_COMMON_H
#define ARROW_TYPES_TEST_COMMON_H
#include <memory>
#include <string>
#include <vector>
#include "gtest/gtest.h"
#include "arrow/array.h"
#include "arrow/builder.h"
#include "arrow/test-util.h"
#include "arrow/type.h"
#include "arrow/util/memory-pool.h"
namespace arrow {
using std::unique_ptr;
class TestBuilder : public ::testing::Test {
public:
void SetUp() {
pool_ = default_memory_pool();
type_ = TypePtr(new UInt8Type());
builder_.reset(new UInt8Builder(pool_, type_));
builder_nn_.reset(new UInt8Builder(pool_, type_));
}
protected:
MemoryPool* pool_;
TypePtr type_;
unique_ptr<ArrayBuilder> builder_;
unique_ptr<ArrayBuilder> builder_nn_;
};
template <class T, class Builder>
Status MakeArray(const std::vector<uint8_t>& valid_bytes, const std::vector<T>& values,
int size, Builder* builder, ArrayPtr* out) {
// Append the first 1000
for (int i = 0; i < size; ++i) {
if (valid_bytes[i] > 0) {
RETURN_NOT_OK(builder->Append(values[i]));
} else {
RETURN_NOT_OK(builder->AppendNull());
}
}
return builder->Finish(out);
}
} // namespace arrow
#endif // ARROW_TYPES_TEST_COMMON_H
-27
View File
@@ -1,27 +0,0 @@
// 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 "arrow/types/union.h"
#include <cstdlib>
#include <sstream>
#include <string>
#include <vector>
#include "arrow/type.h"
namespace arrow {} // namespace arrow
-48
View File
@@ -1,48 +0,0 @@
// 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.
#ifndef ARROW_TYPES_UNION_H
#define ARROW_TYPES_UNION_H
#include <memory>
#include <string>
#include <vector>
#include "arrow/array.h"
#include "arrow/type.h"
namespace arrow {
class Buffer;
class UnionArray : public Array {
protected:
// The data are types encoded as int16
Buffer* types_;
std::vector<std::shared_ptr<Array>> children_;
};
class DenseUnionArray : public UnionArray {
protected:
Buffer* offset_buf_;
};
class SparseUnionArray : public UnionArray {};
} // namespace arrow
#endif // ARROW_TYPES_UNION_H