Skip to content

[C++] Choose the Correct Value in ArrayBuilder::AppendEmptyValue() for Floating-Point Types #50509

Description

@andishgar

Describe the enhancement requested

ArrayBuilder::AppendEmptyValue() was introduced and implemented in ARROW-25393 to write an arbitrary, well-defined value during StructBuilder::AppendNull(), as discussed here. In that context, the value written to the child builder is irrelevant because the parent entry is null.

At that time, RunEndEncodedBuilder did not yet exist; it was implemented about three years later in ARROW-32688. As a result, the current implementation does not appear to consider that the value written by AppendEmptyValue() may later become part of the value stream observed by RunEndEncodedBuilder.

this can be problematic for RunEndEncodedBuilder with floating-point values, as it can produce a zero value, which cannot be considered an empty value (Case 1). Even worse, it can be mistakenly confused with actual floating-point values (see the example below).

Case 1

auto ree_type = run_end_encoded(int32(), float32());
auto int32_builder = std::make_shared<Int32Builder>(pool_);
auto float_builder = std::make_shared<FloatBuilder>(pool_);
RunEndEncodedBuilder builder(pool_, int32_builder, float_builder, ree_type);

ASSERT_OK(builder.AppendEmptyValues(3));
ASSERT_OK(builder.AppendScalar(**MakeScalar(float32(), 3), 3));

ASSERT_OK_AND_ASSIGN(auto array, builder.Finish());
ARROW_LOGGER_INFO("", array->ToString());

Output:

-- run_ends:
  [
    3,
    6
  ]
-- values:
  [
    0,
    3
  ]

Case 2

auto ree_type = run_end_encoded(int32(), float32());
auto int32_builder = std::make_shared<Int32Builder>(pool_);
auto float_builder = std::make_shared<FloatBuilder>(pool_);
RunEndEncodedBuilder builder(pool_, int32_builder, float_builder, ree_type);

ASSERT_OK(builder.AppendEmptyValues(3));
ASSERT_OK(builder.AppendScalar(**MakeScalar(float32(), 0), 3));

ASSERT_OK_AND_ASSIGN(auto array, builder.Finish());
ARROW_LOGGER_INFO("", array->ToString());

Output:

-- run_ends:
  [
    3,
    6
  ]
-- values:
  [
    0,
    0
  ]

One possible solution would be to use NaN as the placeholder value for floating-point builders instead of 0.0f.

Component(s)

C++

Metadata

Metadata

Assignees

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions