Skip to content
Closed
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
71 changes: 71 additions & 0 deletions cpp/src/arrow/array/array_test.cc
Original file line number Diff line number Diff 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 Down Expand Up @@ -4075,4 +4078,72 @@ TYPED_TEST(TestPrimitiveArray, IndexOperator) {
}
}

class TestHalfFloatBuilder : public ::testing::Test {
public:
void VerifyValue(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_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]");
ASSERT_TRUE(array->Equals(*comp));

std::vector<Float16> vals = {Float16(2.5), Float16(3.5)};
std::vector<bool> is_valid = {true, true};
std::vector<uint8_t> bitmap = {1, 1};
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(), bitmap.data(), 0));

for (int i = 0; i < 5; i++) {
VerifyValue(builder, (2 * i), 2.5);
VerifyValue(builder, (2 * i) + 1, 3.5);
}
}

TEST_F(TestHalfFloatBuilder, TestReinterpretCast) {
std::vector<Float16> vf{Float16(1.0f), Float16(2.0f), Float16(3.0f)};
Float16* fdata = vf.data();
uint16_t* udata = reinterpret_cast<uint16_t*>(fdata);

ASSERT_EQ(udata[0], vf[0].bits());
ASSERT_EQ(udata[1], vf[1].bits());
ASSERT_EQ(udata[2], vf[2].bits());
}

} // namespace arrow
99 changes: 97 additions & 2 deletions cpp/src/arrow/array/builder_primitive.h
Original file line number Diff line number Diff 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 Down Expand Up @@ -196,7 +197,7 @@ class NumericBuilder
/// \brief Append a sequence of elements in one shot
/// \param[in] values a contiguous C array of values
/// \param[in] length the number of values to append
/// \param[in] is_valid an std::vector<bool> indicating valid (1) or null
/// \param[in] is_valid a std::vector<bool> indicating valid (1) or null
/// (0). Equal in length to values
/// \return Status
Status AppendValues(const value_type* values, int64_t length,
Expand Down Expand 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,101 @@ using DurationBuilder = NumericBuilder<DurationType>;

/// @}

class ARROW_EXPORT HalfFloatBuilder : public NumericBuilder<HalfFloatType> {
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 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 number Diff line number Diff 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 number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ class ARROW_EXPORT Float16 {
};

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

} // namespace util
Expand Down
3 changes: 3 additions & 0 deletions docs/source/cpp/api/builder.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ Primitive
.. doxygenclass:: arrow::BooleanBuilder
:members:

.. doxygenclass:: arrow::HalfFloatBuilder
:members:

.. doxygengroup:: numeric-builders
:content-only:
:members:
Expand Down