Skip to content

Commit fd69d50

Browse files
committed
GH-35460: Migrate integration RapidJSON writer to JsonWriter
1 parent 2b7f64e commit fd69d50

7 files changed

Lines changed: 57 additions & 46 deletions

File tree

ci/docker/ubuntu-24.04-cpp.dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,4 +221,5 @@ ENV absl_SOURCE=BUNDLED \
221221
PARQUET_BUILD_EXECUTABLES=ON \
222222
PATH=/usr/lib/ccache/:$PATH \
223223
PYTHON=python3 \
224+
simdjson_SOURCE=BUNDLED \
224225
xsimd_SOURCE=BUNDLED

cpp/src/arrow/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -733,7 +733,7 @@ if(ARROW_BUILD_INTEGRATION OR ARROW_BUILD_TESTS)
733733
arrow_add_object_library(ARROW_INTEGRATION integration/json_integration.cc
734734
integration/json_internal.cc)
735735
foreach(ARROW_INTEGRATION_TARGET ${ARROW_INTEGRATION_TARGETS})
736-
target_link_libraries(${ARROW_INTEGRATION_TARGET} PRIVATE RapidJSON)
736+
target_link_libraries(${ARROW_INTEGRATION_TARGET} PRIVATE RapidJSON simdjson::simdjson)
737737
endforeach()
738738
else()
739739
set(ARROW_INTEGRATION_TARGET_SHARED)

cpp/src/arrow/integration/CMakeLists.txt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,17 @@ arrow_install_all_headers("arrow/integration")
2121
# - an executable that can be called to answer integration test requests
2222
# - a self-(unit)test for the C++ side of integration testing
2323
if(ARROW_BUILD_TESTS)
24-
add_arrow_test(json_integration_test EXTRA_LINK_LIBS RapidJSON ${GFLAGS_LIBRARIES})
24+
add_arrow_test(json_integration_test
25+
EXTRA_LINK_LIBS
26+
RapidJSON
27+
simdjson::simdjson
28+
${GFLAGS_LIBRARIES})
2529
add_dependencies(arrow-integration arrow-json-integration-test)
2630
elseif(ARROW_BUILD_INTEGRATION)
2731
add_executable(arrow-json-integration-test json_integration_test.cc)
2832
target_link_libraries(arrow-json-integration-test
2933
RapidJSON
34+
simdjson::simdjson
3035
${ARROW_TEST_LINK_LIBS}
3136
${GFLAGS_LIBRARIES}
3237
${ARROW_GTEST_GTEST})

cpp/src/arrow/integration/json_integration.cc

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "arrow/integration/json_internal.h"
2828
#include "arrow/io/file.h"
2929
#include "arrow/ipc/dictionary.h"
30+
#include "arrow/json/json_writer.h"
3031
#include "arrow/record_batch.h"
3132
#include "arrow/result.h"
3233
#include "arrow/status.h"
@@ -36,6 +37,8 @@
3637
using arrow::ipc::DictionaryFieldMapper;
3738
using arrow::ipc::DictionaryMemo;
3839

40+
using JsonWriter = arrow::json::JsonWriter;
41+
3942
namespace arrow::internal::integration {
4043

4144
// ----------------------------------------------------------------------
@@ -44,13 +47,10 @@ namespace arrow::internal::integration {
4447
class IntegrationJsonWriter::Impl {
4548
public:
4649
explicit Impl(const std::shared_ptr<Schema>& schema)
47-
: schema_(schema), mapper_(*schema), first_batch_written_(false) {
48-
writer_.reset(new RjWriter(string_buffer_));
49-
}
50-
50+
: schema_(schema), mapper_(*schema), first_batch_written_(false) {}
5151
Status Start() {
52-
writer_->StartObject();
53-
RETURN_NOT_OK(json::WriteSchema(*schema_, mapper_, writer_.get()));
52+
writer_.StartObject();
53+
RETURN_NOT_OK(json::WriteSchema(*schema_, mapper_, &writer_));
5454
return Status::OK();
5555
}
5656

@@ -59,26 +59,26 @@ class IntegrationJsonWriter::Impl {
5959

6060
// Write dictionaries, if any
6161
if (!dictionaries.empty()) {
62-
writer_->Key("dictionaries");
63-
writer_->StartArray();
62+
writer_.Key("dictionaries");
63+
writer_.StartArray();
6464
for (const auto& entry : dictionaries) {
65-
RETURN_NOT_OK(json::WriteDictionary(entry.first, entry.second, writer_.get()));
65+
RETURN_NOT_OK(json::WriteDictionary(entry.first, entry.second, &writer_));
6666
}
67-
writer_->EndArray();
67+
writer_.EndArray();
6868
}
6969

7070
// Record batches
71-
writer_->Key("batches");
72-
writer_->StartArray();
71+
writer_.Key("batches");
72+
writer_.StartArray();
7373
first_batch_written_ = true;
7474
return Status::OK();
7575
}
7676

7777
Result<std::string> Finish() {
78-
writer_->EndArray(); // Record batches
79-
writer_->EndObject();
78+
writer_.EndArray(); // Record batches
79+
writer_.EndObject();
8080

81-
return string_buffer_.GetString();
81+
return std::string(writer_.GetString());
8282
}
8383

8484
Status WriteRecordBatch(const RecordBatch& batch) {
@@ -87,7 +87,7 @@ class IntegrationJsonWriter::Impl {
8787
if (!first_batch_written_) {
8888
RETURN_NOT_OK(FirstRecordBatch(batch));
8989
}
90-
return json::WriteRecordBatch(batch, writer_.get());
90+
return json::WriteRecordBatch(batch, &writer_);
9191
}
9292

9393
private:
@@ -96,8 +96,7 @@ class IntegrationJsonWriter::Impl {
9696

9797
bool first_batch_written_;
9898

99-
rj::StringBuffer string_buffer_;
100-
std::unique_ptr<RjWriter> writer_;
99+
JsonWriter writer_;
101100
};
102101

103102
IntegrationJsonWriter::IntegrationJsonWriter(const std::shared_ptr<Schema>& schema) {

cpp/src/arrow/integration/json_integration_test.cc

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include "arrow/ipc/reader.h"
3939
#include "arrow/ipc/test_common.h"
4040
#include "arrow/ipc/writer.h"
41+
#include "arrow/json/json_writer.h"
4142
#include "arrow/pretty_print.h"
4243
#include "arrow/status.h"
4344
#include "arrow/testing/builder.h"
@@ -723,16 +724,15 @@ static const char* json_example6 = R"example(
723724
)example";
724725

725726
void TestSchemaRoundTrip(const std::shared_ptr<Schema>& schema) {
726-
rj::StringBuffer sb;
727-
rj::Writer<rj::StringBuffer> writer(sb);
727+
arrow::json::JsonWriter writer;
728728

729729
DictionaryFieldMapper mapper(*schema);
730730

731731
writer.StartObject();
732732
ASSERT_OK(json::WriteSchema(*schema, mapper, &writer));
733733
writer.EndObject();
734734

735-
std::string json_schema = sb.GetString();
735+
std::string json_schema(writer.GetString());
736736

737737
rj::Document d;
738738
// Pass explicit size to avoid ASAN issues with
@@ -748,12 +748,11 @@ void TestSchemaRoundTrip(const std::shared_ptr<Schema>& schema) {
748748
void TestArrayRoundTrip(const Array& array) {
749749
static std::string name = "dummy";
750750

751-
rj::StringBuffer sb;
752-
rj::Writer<rj::StringBuffer> writer(sb);
751+
arrow::json::JsonWriter writer;
753752

754753
ASSERT_OK(json::WriteArray(name, array, &writer));
755754

756-
std::string array_as_json = sb.GetString();
755+
std::string array_as_json(writer.GetString());
757756

758757
rj::Document d;
759758
// Pass explicit size to avoid ASAN issues with
@@ -768,7 +767,6 @@ void TestArrayRoundTrip(const Array& array) {
768767
json::ReadArray(default_memory_pool(), d, ::arrow::field(name, array.type())));
769768
ASSERT_OK(result_array->ValidateFull());
770769

771-
// std::cout << array_as_json << std::endl;
772770
CompareArraysDetailed(0, *result_array, array);
773771
}
774772

cpp/src/arrow/integration/json_internal.cc

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "arrow/array/builder_time.h"
3737
#include "arrow/extension_type.h"
3838
#include "arrow/ipc/dictionary.h"
39+
#include "arrow/json/json_writer.h"
3940
#include "arrow/record_batch.h"
4041
#include "arrow/result.h"
4142
#include "arrow/scalar.h"
@@ -64,6 +65,8 @@ using arrow::ipc::DictionaryFieldMapper;
6465
using arrow::ipc::DictionaryMemo;
6566
using arrow::ipc::internal::FieldPosition;
6667

68+
using JsonWriter = arrow::json::JsonWriter;
69+
6770
namespace arrow::internal::integration::json {
6871

6972
namespace {
@@ -118,7 +121,7 @@ Result<std::string_view> GetStringView(const rj::Value& str) {
118121
class SchemaWriter {
119122
public:
120123
explicit SchemaWriter(const Schema& schema, const DictionaryFieldMapper& mapper,
121-
RjWriter* writer)
124+
JsonWriter* writer)
122125
: schema_(schema), mapper_(mapper), writer_(writer) {}
123126

124127
Status Write() {
@@ -460,7 +463,7 @@ class SchemaWriter {
460463
private:
461464
const Schema& schema_;
462465
const DictionaryFieldMapper& mapper_;
463-
RjWriter* writer_;
466+
JsonWriter* writer_;
464467
};
465468

466469
Status SchemaWriter::VisitType(const DataType& type) {
@@ -469,7 +472,7 @@ Status SchemaWriter::VisitType(const DataType& type) {
469472

470473
class ArrayWriter {
471474
public:
472-
ArrayWriter(const std::string& name, const Array& array, RjWriter* writer)
475+
ArrayWriter(const std::string& name, const Array& array, JsonWriter* writer)
473476
: name_(name), array_(array), writer_(writer) {}
474477

475478
Status Write() { return VisitArray(name_, array_); }
@@ -493,7 +496,7 @@ class ArrayWriter {
493496
void WriteRawNumber(std::string_view v) {
494497
// Avoid RawNumber() as it misleadingly adds quotes
495498
// (see https://github.com/Tencent/rapidjson/pull/1155)
496-
writer_->RawValue(v.data(), v.size(), rj::kNumberType);
499+
writer_->RawValue(v);
497500
}
498501

499502
template <typename ArrayType, typename TypeClass = typename ArrayType::TypeClass,
@@ -598,7 +601,7 @@ class ArrayWriter {
598601
const Decimal32 value(arr.GetValue(i));
599602
writer_->String(value.ToIntegerString());
600603
} else {
601-
writer_->String(null_string, sizeof(null_string));
604+
writer_->String(std::string_view(null_string));
602605
}
603606
}
604607
}
@@ -610,7 +613,7 @@ class ArrayWriter {
610613
const Decimal64 value(arr.GetValue(i));
611614
writer_->String(value.ToIntegerString());
612615
} else {
613-
writer_->String(null_string, sizeof(null_string));
616+
writer_->String(std::string_view(null_string));
614617
}
615618
}
616619
}
@@ -622,7 +625,7 @@ class ArrayWriter {
622625
const Decimal128 value(arr.GetValue(i));
623626
writer_->String(value.ToIntegerString());
624627
} else {
625-
writer_->String(null_string, sizeof(null_string));
628+
writer_->String(std::string_view(null_string));
626629
}
627630
}
628631
}
@@ -634,7 +637,7 @@ class ArrayWriter {
634637
const Decimal256 value(arr.GetValue(i));
635638
writer_->String(value.ToIntegerString());
636639
} else {
637-
writer_->String(null_string, sizeof(null_string));
640+
writer_->String(std::string_view(null_string));
638641
}
639642
}
640643
}
@@ -863,7 +866,7 @@ class ArrayWriter {
863866
private:
864867
const std::string& name_;
865868
const Array& array_;
866-
RjWriter* writer_;
869+
JsonWriter* writer_;
867870
};
868871

869872
Result<TimeUnit::type> GetUnitFromString(const std::string& unit_str) {
@@ -2035,13 +2038,13 @@ Result<std::shared_ptr<RecordBatch>> ReadRecordBatch(
20352038
}
20362039

20372040
Status WriteSchema(const Schema& schema, const DictionaryFieldMapper& mapper,
2038-
RjWriter* json_writer) {
2041+
JsonWriter* json_writer) {
20392042
SchemaWriter converter(schema, mapper, json_writer);
20402043
return converter.Write();
20412044
}
20422045

20432046
Status WriteDictionary(int64_t id, const std::shared_ptr<Array>& dictionary,
2044-
RjWriter* writer) {
2047+
JsonWriter* writer) {
20452048
writer->StartObject();
20462049
writer->Key("id");
20472050
writer->Int(static_cast<int32_t>(id));
@@ -2055,7 +2058,7 @@ Status WriteDictionary(int64_t id, const std::shared_ptr<Array>& dictionary,
20552058
return Status::OK();
20562059
}
20572060

2058-
Status WriteRecordBatch(const RecordBatch& batch, RjWriter* writer) {
2061+
Status WriteRecordBatch(const RecordBatch& batch, JsonWriter* writer) {
20592062
writer->StartObject();
20602063
writer->Key("count");
20612064
writer->Int(static_cast<int32_t>(batch.num_rows()));
@@ -2076,7 +2079,7 @@ Status WriteRecordBatch(const RecordBatch& batch, RjWriter* writer) {
20762079
return Status::OK();
20772080
}
20782081

2079-
Status WriteArray(const std::string& name, const Array& array, RjWriter* json_writer) {
2082+
Status WriteArray(const std::string& name, const Array& array, JsonWriter* json_writer) {
20802083
ArrayWriter converter(name, array, json_writer);
20812084
return converter.Write();
20822085
}

cpp/src/arrow/integration/json_internal.h

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,14 @@
3636
#include "arrow/util/visibility.h"
3737

3838
namespace rj = arrow::rapidjson;
39-
using RjWriter = rj::Writer<rj::StringBuffer>;
40-
using RjArray = rj::Value::ConstArray;
4139
using RjObject = rj::Value::ConstObject;
40+
using RjArray = rj::Value::ConstArray;
41+
42+
namespace arrow {
43+
namespace json {
44+
class JsonWriter;
45+
} // namespace json
46+
} // namespace arrow
4247

4348
#define RETURN_NOT_FOUND(TOK, NAME, PARENT) \
4449
if (NAME == (PARENT).MemberEnd()) { \
@@ -80,17 +85,17 @@ namespace arrow::internal::integration::json {
8085
/// \brief Append integration test Schema format to rapidjson writer
8186
ARROW_EXPORT
8287
Status WriteSchema(const Schema& schema, const ipc::DictionaryFieldMapper& mapper,
83-
RjWriter* writer);
88+
arrow::json::JsonWriter*);
8489

8590
ARROW_EXPORT
8691
Status WriteDictionary(int64_t id, const std::shared_ptr<Array>& dictionary,
87-
RjWriter* writer);
92+
arrow::json::JsonWriter*);
8893

8994
ARROW_EXPORT
90-
Status WriteRecordBatch(const RecordBatch& batch, RjWriter* writer);
95+
Status WriteRecordBatch(const RecordBatch& batch, arrow::json::JsonWriter*);
9196

9297
ARROW_EXPORT
93-
Status WriteArray(const std::string& name, const Array& array, RjWriter* writer);
98+
Status WriteArray(const std::string& name, const Array& array, arrow::json::JsonWriter*);
9499

95100
ARROW_EXPORT
96101
Result<std::shared_ptr<Schema>> ReadSchema(const rj::Value& json_obj, MemoryPool* pool,

0 commit comments

Comments
 (0)