Skip to content

Commit 17c3b07

Browse files
committed
feat(cpp): Add UnsafeAppend methods to StructBuilder
1 parent a0fcb50 commit 17c3b07

File tree

2 files changed

+123
-1
lines changed

2 files changed

+123
-1
lines changed

cpp/src/arrow/array/array_struct_test.cc

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -748,4 +748,92 @@ TEST(TestFieldRef, GetChildren) {
748748
AssertArraysEqual(*a, *expected_a);
749749
}
750750

751-
} // namespace arrow
751+
TEST(TestStructBuilder, UnsafeAppend) {
752+
753+
auto int_type = int32();
754+
auto str_type = utf8();
755+
auto struct_type = struct_({field("a", int_type), field("b", str_type)});
756+
auto pool = default_memory_pool();
757+
std::shared_ptr<Array> final_array;
758+
auto int_builder = std::make_shared<Int32Builder>(pool);
759+
auto str_builder = std::make_shared<StringBuilder>(pool);
760+
StructBuilder builder(struct_type, pool, {int_builder, str_builder});
761+
762+
builder.UnsafeAppend();
763+
ASSERT_OK(int_builder->Append(1));
764+
ASSERT_OK(str_builder->Append("hello"));
765+
766+
builder.UnsafeAppend();
767+
ASSERT_OK(int_builder->Append(2));
768+
ASSERT_OK(str_builder->Append("arrow"));
769+
770+
ASSERT_OK(builder.Finish(&final_array));
771+
ASSERT_EQ(2, final_array->length());
772+
ASSERT_EQ(0, final_array->null_count());
773+
auto expected_json = R"([{"a": 1, "b": "hello"}, {"a": 2, "b": "arrow"}])";
774+
auto expected_array = ArrayFromJSON(struct_type, expected_json);
775+
ASSERT_TRUE(final_array->Equals(expected_array));
776+
}
777+
778+
TEST(TestStructBuilder, UnsafeAppendNull) {
779+
780+
auto int_type = int32();
781+
auto str_type = utf8();
782+
auto struct_type = struct_({field("a", int_type), field("b", str_type)});
783+
auto pool = default_memory_pool();
784+
std::shared_ptr<Array> final_array;
785+
auto int_builder = std::make_shared<Int32Builder>(pool);
786+
auto str_builder = std::make_shared<StringBuilder>(pool);
787+
StructBuilder builder(struct_type, pool, {int_builder, str_builder});
788+
789+
builder.UnsafeAppend();
790+
ASSERT_OK(int_builder->Append(1));
791+
ASSERT_OK(str_builder->Append("hello"));
792+
793+
ASSERT_OK(builder.UnsafeAppendNull());
794+
795+
builder.UnsafeAppend();
796+
ASSERT_OK(int_builder->Append(2));
797+
ASSERT_OK(str_builder->Append("arrow"));
798+
799+
ASSERT_OK(builder.Finish(&final_array));
800+
ASSERT_EQ(3, final_array->length());
801+
ASSERT_EQ(1, final_array->null_count());
802+
ASSERT_TRUE(final_array->IsNull(1));
803+
auto expected_json = R"([{"a": 1, "b": "hello"}, null, {"a": 2, "b": "arrow"}])";
804+
auto expected_array = ArrayFromJSON(struct_type, expected_json);
805+
ASSERT_TRUE(final_array->Equals(expected_array));
806+
}
807+
808+
TEST(TestStructBuilder, UnsafeAppendNulls) {
809+
810+
auto int_type = int32();
811+
auto str_type = utf8();
812+
auto struct_type = struct_({field("a", int_type), field("b", str_type)});
813+
auto pool = default_memory_pool();
814+
std::shared_ptr<Array> final_array;
815+
auto int_builder = std::make_shared<Int32Builder>(pool);
816+
auto str_builder = std::make_shared<StringBuilder>(pool);
817+
StructBuilder builder(struct_type, pool, {int_builder, str_builder});
818+
819+
builder.UnsafeAppend();
820+
ASSERT_OK(int_builder->Append(1));
821+
ASSERT_OK(str_builder->Append("hello"));
822+
823+
ASSERT_OK(builder.UnsafeAppendNulls(2));
824+
825+
builder.UnsafeAppend();
826+
ASSERT_OK(int_builder->Append(2));
827+
ASSERT_OK(str_builder->Append("arrow"));
828+
829+
ASSERT_OK(builder.Finish(&final_array));
830+
ASSERT_EQ(4, final_array->length());
831+
ASSERT_EQ(2, final_array->null_count());
832+
ASSERT_TRUE(final_array->IsNull(1));
833+
ASSERT_TRUE(final_array->IsNull(2));
834+
auto expected_json = R"([{"a": 1, "b": "hello"}, null, null, {"a": 2, "b": "arrow"}])";
835+
auto expected_array = ArrayFromJSON(struct_type, expected_json);
836+
ASSERT_TRUE(final_array->Equals(expected_array));
837+
}
838+
839+
} // namespace arrow

cpp/src/arrow/array/builder_nested.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -771,6 +771,13 @@ class ARROW_EXPORT StructBuilder : public ArrayBuilder {
771771
return Status::OK();
772772
}
773773

774+
/// This method is "unsafe" because it does not update the null bitmap
775+
/// It doesn't check the capacity. Caller is responsible for calling Reserve()
776+
/// beforehand.
777+
void UnsafeAppend(){
778+
++length_;
779+
}
780+
774781
/// \brief Append a null value. Automatically appends an empty value to each child
775782
/// builder.
776783
Status AppendNull() final {
@@ -780,6 +787,19 @@ class ARROW_EXPORT StructBuilder : public ArrayBuilder {
780787
return Append(false);
781788
}
782789

790+
/// This method is "unsafe" because it does not check for capacity.
791+
/// The caller is responsible for calling Reserve() beforehand to ensure
792+
/// there is enough space. This method will append nulls to all child
793+
/// builders to maintain a consistent state.
794+
Status UnsafeAppendNull(){
795+
null_bitmap_builder_.UnsafeAppend(false);
796+
for(const auto& child: children_){
797+
ARROW_RETURN_NOT_OK(child->AppendNull());
798+
}
799+
length_++;
800+
return Status::OK();
801+
}
802+
783803
/// \brief Append multiple null values. Automatically appends empty values to each
784804
/// child builder.
785805
Status AppendNulls(int64_t length) final {
@@ -791,6 +811,20 @@ class ARROW_EXPORT StructBuilder : public ArrayBuilder {
791811
return Status::OK();
792812
}
793813

814+
/// This method is "unsafe" because it does not check for capacity.
815+
/// The caller is responsible for calling Reserve() beforehand to ensure
816+
/// there is enough space. This method will append nulls to all child
817+
/// builders to maintain a consistent state.
818+
/// param length The number of null slots to append.
819+
Status UnsafeAppendNulls(int64_t length){
820+
null_bitmap_builder_.UnsafeAppend(length, false);
821+
for(const auto& child:children_){
822+
ARROW_RETURN_NOT_OK(child->AppendNulls(length));
823+
}
824+
++length_;
825+
return Status::OK();
826+
}
827+
794828
Status AppendEmptyValue() final {
795829
for (const auto& field : children_) {
796830
ARROW_RETURN_NOT_OK(field->AppendEmptyValue());

0 commit comments

Comments
 (0)