Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions cpp/src/arrow/array/array_test.cc
Original file line numberDiff line numberDiff line change
Expand Up@@ -38,6 +38,7 @@
#include "arrow/array/builder_binary.h"
#include "arrow/array/builder_decimal.h"
#include "arrow/array/builder_dict.h"
#include "arrow/array/builder_primitive.h"
#include "arrow/array/builder_run_end.h"
#include "arrow/array/builder_time.h"
#include "arrow/array/data.h"
Expand All@@ -60,6 +61,7 @@
#include "arrow/util/bitmap_builders.h"
#include "arrow/util/checked_cast.h"
#include "arrow/util/decimal.h"
#include "arrow/util/float16.h"
#include "arrow/util/key_value_metadata.h"
#include "arrow/util/macros.h"
#include "arrow/util/range.h"
Expand All@@ -72,6 +74,7 @@ namespace arrow {

using internal::checked_cast;
using internal::checked_pointer_cast;
using util::Float16;

class TestArray : public ::testing::Test {
public:
Expand DownExpand Up@@ -4099,4 +4102,73 @@ TYPED_TEST(TestPrimitiveArray, IndexOperator) {
}
}

class TestHalfFloatBuilder : public ::testing::Test {
public:
void VerifyValue(const HalfFloatBuilder& builder, int64_t index, float expected) {
ASSERT_EQ(builder.GetValue(index), Float16(expected).bits());
ASSERT_EQ(builder.GetValue<Float16>(index), Float16(expected));
ASSERT_EQ(builder.GetValue<uint16_t>(index), Float16(expected).bits());
ASSERT_EQ(builder[index], Float16(expected).bits());
}
};

TEST_F(TestHalfFloatBuilder, TestAppend) {
HalfFloatBuilder builder;
ASSERT_OK(builder.Append(Float16(0.0f)));
ASSERT_OK(builder.Append(Float16(1.0f).bits()));
ASSERT_OK(builder.AppendNull());
ASSERT_OK(builder.Reserve(3));
builder.UnsafeAppend(Float16(3.0f));
builder.UnsafeAppend(Float16(4.0f).bits());
builder.UnsafeAppend(uint16_t{15872}); // 1.5f

VerifyValue(builder, 0, 0.0f);
VerifyValue(builder, 1, 1.0f);
VerifyValue(builder, 3, 3.0f);
VerifyValue(builder, 4, 4.0f);
VerifyValue(builder, 5, 1.5f);
}

TEST_F(TestHalfFloatBuilder, TestBulkAppend) {
HalfFloatBuilder builder;

ASSERT_OK(builder.AppendValues(5, Float16(1.5)));
uint16_t val = Float16(2.0f).bits();
ASSERT_OK(builder.AppendValues({val, val, val, val}, {0, 1, 0, 1}));
ASSERT_EQ(builder.length(), 9);
for (int i = 0; i < 5; i++) {
VerifyValue(builder, i, 1.5f);
}

{
ASSERT_OK_AND_ASSIGN(auto array, builder.Finish());
ASSERT_OK(array->ValidateFull());
ASSERT_EQ(array->null_count(), 2);
ASSERT_EQ(array->length(), 9);
auto comp = ArrayFromJSON(float16(), "[1.5,1.5,1.5,1.5,1.5,null,2,null,2]");
AssertArraysEqual(*array, *comp);
}

std::vector<Float16> vals = {Float16(1.0f), Float16(2.0f), Float16(3.0f)};
std::vector<bool> is_valid = {true, false, true};
std::vector<uint8_t> valid_bytes = {1, 0, 1};
std::vector<uint8_t> bitmap = {0b00000101};
ASSERT_OK(builder.AppendValues(vals));
ASSERT_OK(builder.AppendValues(vals, is_valid));
ASSERT_OK(builder.AppendValues(vals.data(), vals.size(), is_valid));
ASSERT_OK(builder.AppendValues(vals.data(), vals.size()));
ASSERT_OK(builder.AppendValues(vals.data(), vals.size(), valid_bytes.data()));
ASSERT_OK(builder.AppendValues(vals.data(), vals.size(), bitmap.data(), 0));

{
ASSERT_OK_AND_ASSIGN(auto array, builder.Finish());
ASSERT_OK(array->ValidateFull());
ASSERT_EQ(array->null_count(), 4);
ASSERT_EQ(array->length(), 18);
auto comp =
ArrayFromJSON(float16(), "[1,2,3,1,null,3,1,null,3,1,2,3,1,null,3,1,null,3]");
AssertArraysEqual(*array, *comp);
}
}

} // namespace arrow
103 changes: 102 additions & 1 deletion cpp/src/arrow/array/builder_primitive.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,6 +26,7 @@
#include "arrow/result.h"
#include "arrow/type.h"
#include "arrow/type_traits.h"
#include "arrow/util/float16.h"

namespace arrow {

Expand DownExpand Up@@ -364,7 +365,6 @@ using Int16Builder = NumericBuilder<Int16Type>;
using Int32Builder = NumericBuilder<Int32Type>;
using Int64Builder = NumericBuilder<Int64Type>;

using HalfFloatBuilder = NumericBuilder<HalfFloatType>;
using FloatBuilder = NumericBuilder<FloatType>;
using DoubleBuilder = NumericBuilder<DoubleType>;

Expand All@@ -384,6 +384,107 @@ using DurationBuilder = NumericBuilder<DurationType>;

/// @}

/// \addtogroup numeric-builders
///
/// @{

class ARROW_EXPORT HalfFloatBuilder : public NumericBuilder<HalfFloatType> {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps /// \addtogroup numeric-builders so as to inject it at the right place in the documentation?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

public:
using BaseClass = NumericBuilder<HalfFloatType>;
using Float16 = arrow::util::Float16;

using BaseClass::Append;
using BaseClass::AppendValues;
using BaseClass::BaseClass;
using BaseClass::GetValue;
using BaseClass::UnsafeAppend;

/// Scalar append a arrow::util::Float16
Status Append(const Float16 val) { return Append(val.bits()); }

/// Scalar append a arrow::util::Float16, without checking for capacity
void UnsafeAppend(const Float16 val) { UnsafeAppend(val.bits()); }

/// \brief Append a sequence of elements in one shot
/// \param[in] values a contiguous array of arrow::util::Float16
/// \param[in] length the number of values to append
/// \param[in] valid_bytes an optional sequence of bytes where non-zero
/// indicates a valid (non-null) value
/// \return Status
Status AppendValues(const Float16* values, int64_t length,
const uint8_t* valid_bytes = NULLPTR) {
return BaseClass::AppendValues(reinterpret_cast<const uint16_t*>(values), length,
valid_bytes);
}

/// \brief Append a sequence of elements in one shot
/// \param[in] values a contiguous array of arrow::util::Float16
/// \param[in] length the number of values to append
/// \param[in] bitmap a validity bitmap to copy (may be null)
/// \param[in] bitmap_offset an offset into the validity bitmap
/// \return Status
Status AppendValues(const Float16* values, int64_t length, const uint8_t* bitmap,
int64_t bitmap_offset) {
return BaseClass::AppendValues(reinterpret_cast<const uint16_t*>(values), length,
bitmap, bitmap_offset);
}

/// \brief Append a sequence of elements in one shot
/// \param[in] values a contiguous array of arrow::util::Float16
/// \param[in] length the number of values to append
/// \param[in] is_valid a std::vector<bool> indicating valid (1) or null
/// (0). Equal in length to values
/// \return Status
Status AppendValues(const Float16* values, int64_t length,
const std::vector<bool>& is_valid) {
return BaseClass::AppendValues(reinterpret_cast<const uint16_t*>(values), length,
is_valid);
}

/// \brief Append a sequence of elements in one shot
/// \param[in] values a std::vector<arrow::util::Float16>
/// \param[in] is_valid a std::vector<bool> indicating valid (1) or null
/// (0). Equal in length to values
/// \return Status
Status AppendValues(const std::vector<Float16>& values,
const std::vector<bool>& is_valid) {
return AppendValues(values.data(), static_cast<int64_t>(values.size()), is_valid);
}

/// \brief Append a sequence of elements in one shot
/// \param[in] values a std::vector<arrow::util::Float16>
/// \return Status
Status AppendValues(const std::vector<Float16>& values) {
return AppendValues(values.data(), static_cast<int64_t>(values.size()));
}

/// \brief Append one value many times in one shot
/// \param[in] length the number of values to append
/// \param[in] value a arrow::util::Float16
Status AppendValues(int64_t length, Float16 value) {
RETURN_NOT_OK(Reserve(length));
data_builder_.UnsafeAppend(length, value.bits());
ArrayBuilder::UnsafeSetNotNull(length);
return Status::OK();
}

/// \brief Get the value at a certain index
/// \param[in] index the zero-based index
/// @tparam T arrow::util::Float16 or value_type (uint16_t)
template <typename T = BaseClass::value_type>
T GetValue(int64_t index) const {
static_assert(std::is_same_v<T, BaseClass::value_type> ||
std::is_same_v<T, arrow::util::Float16>);
if constexpr (std::is_same_v<T, BaseClass::value_type>) {
return BaseClass::GetValue(index);
} else {
return Float16::FromBits(BaseClass::GetValue(index));
}
}
};

/// @}

class ARROW_EXPORT BooleanBuilder
: public ArrayBuilder,
public internal::ArrayBuilderExtraOps<BooleanBuilder, bool> {
Expand Down
7 changes: 6 additions & 1 deletion cpp/src/arrow/type_fwd.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -242,12 +242,17 @@ _NUMERIC_TYPE_DECL(UInt8)
_NUMERIC_TYPE_DECL(UInt16)
_NUMERIC_TYPE_DECL(UInt32)
_NUMERIC_TYPE_DECL(UInt64)
_NUMERIC_TYPE_DECL(HalfFloat)
_NUMERIC_TYPE_DECL(Float)
_NUMERIC_TYPE_DECL(Double)

#undef _NUMERIC_TYPE_DECL

class HalfFloatType;
using HalfFloatArray = NumericArray<HalfFloatType>;
class HalfFloatBuilder;
struct HalfFloatScalar;
using HalfFloatTensor = NumericTensor<HalfFloatType>;

enum class DateUnit : char { DAY = 0, MILLI = 1 };

class DateType;
Expand Down
1 change: 1 addition & 0 deletions cpp/src/arrow/util/float16.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -178,6 +178,7 @@ class ARROW_EXPORT Float16 {
}
};

static_assert(std::is_standard_layout_v<Float16>);
static_assert(std::is_trivial_v<Float16>);
static_assert(sizeof(Float16) == sizeof(uint16_t));

Expand Down