Skip to content

Commit a1d23e5

Browse files
authored
GH-50936: [C++][Integration] Replace RapidJSON with simdjson (#50937)
### Rationale for this change This PR continues the simdjson migration by replacing the RapidJSON usage in the C++ JSON integration implementation with **simdjson's DOM API** and Arrow's existing `JsonWriter`. ### Changes - Replace RapidJSON DOM parsing with simdjson's DOM API. - Update the integration JSON reader and internal parsing helpers to use `simdjson::dom` types. - Replace RapidJSON JSON serialization with Arrow's existing `JsonWriter`. - Handle optional JSON array members without creating an invalid simdjson array. - Remove the unused RapidJSON dependencies from the CMake and Meson integration test targets. - Update remaining RapidJSON-specific implementation references. Fixes: #50936 * GitHub Issue: #50936 Authored-by: Aaditya Srinivasan <aadityasri03@gmail.com> Signed-off-by: Antoine Pitrou <antoine@python.org>
1 parent c8240bd commit a1d23e5

7 files changed

Lines changed: 334 additions & 326 deletions

File tree

cpp/src/arrow/integration/CMakeLists.txt

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,12 @@ 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
25-
EXTRA_LINK_LIBS
26-
RapidJSON
27-
simdjson::simdjson
24+
add_arrow_test(json_integration_test EXTRA_LINK_LIBS simdjson::simdjson
2825
${GFLAGS_LIBRARIES})
2926
add_dependencies(arrow-integration arrow-json-integration-test)
3027
elseif(ARROW_BUILD_INTEGRATION)
3128
add_executable(arrow-json-integration-test json_integration_test.cc)
3229
target_link_libraries(arrow-json-integration-test
33-
RapidJSON
3430
simdjson::simdjson
3531
${ARROW_TEST_LINK_LIBS}
3632
${GFLAGS_LIBRARIES}

cpp/src/arrow/integration/json_integration.cc

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@
2121
#include <cstdint>
2222
#include <memory>
2323
#include <string>
24+
#include <string_view>
2425
#include <utility>
26+
#include <vector>
2527

2628
#include "arrow/buffer.h"
2729
#include "arrow/integration/json_internal.h"
@@ -33,6 +35,7 @@
3335
#include "arrow/status.h"
3436
#include "arrow/type.h"
3537
#include "arrow/util/logging_internal.h"
38+
#include "arrow/util/simdjson_internal.h"
3639

3740
using arrow::ipc::DictionaryFieldMapper;
3841
using arrow::ipc::DictionaryMemo;
@@ -125,44 +128,46 @@ Status IntegrationJsonWriter::WriteRecordBatch(const RecordBatch& batch) {
125128
class IntegrationJsonReader::Impl {
126129
public:
127130
Impl(MemoryPool* pool, const std::shared_ptr<Buffer>& data)
128-
: pool_(pool), data_(data), record_batches_(nullptr) {}
131+
: pool_(pool), data_(data) {}
129132

130133
Status ParseAndReadSchema() {
131-
doc_.Parse(reinterpret_cast<const rj::Document::Ch*>(data_->data()),
132-
static_cast<size_t>(data_->size()));
133-
if (doc_.HasParseError()) {
134-
return Status::IOError("JSON parsing failed");
135-
}
134+
ARROW_ASSIGN_OR_RAISE(doc_,
135+
internal::ResolveSimdjsonResult(
136+
parser_.parse(reinterpret_cast<const char*>(data_->data()),
137+
static_cast<size_t>(data_->size())),
138+
"Failed to parse JSON"));
136139

137140
ARROW_ASSIGN_OR_RAISE(schema_, json::ReadSchema(doc_, pool_, &dictionary_memo_));
138141

139-
auto it = std::as_const(doc_).FindMember("batches");
140-
RETURN_NOT_ARRAY("batches", it, doc_);
141-
record_batches_ = &it->value;
142+
ARROW_ASSIGN_OR_RAISE(auto batches,
143+
internal::ResolveSimdjsonResult(doc_["batches"].get_array(),
144+
"Failed to get batches"));
145+
146+
batches.get_values(record_batches_);
142147

143148
return Status::OK();
144149
}
145150

146151
Result<std::shared_ptr<RecordBatch>> ReadRecordBatch(int i) {
147-
if (i < 0 || i >= static_cast<int>(record_batches_->GetArray().Size())) {
152+
if (i < 0 || i >= static_cast<int>(record_batches_.size())) {
148153
return Status::IndexError("record batch index ", i, " out of bounds");
149154
}
150-
return json::ReadRecordBatch(record_batches_->GetArray()[i], schema_,
151-
&dictionary_memo_, pool_);
155+
156+
return json::ReadRecordBatch(record_batches_[i], schema_, &dictionary_memo_, pool_);
152157
}
153158

154159
std::shared_ptr<Schema> schema() const { return schema_; }
155160

156-
int num_record_batches() const {
157-
return static_cast<int>(record_batches_->GetArray().Size());
158-
}
161+
int num_record_batches() const { return static_cast<int>(record_batches_.size()); }
159162

160163
private:
161164
MemoryPool* pool_;
162165
std::shared_ptr<Buffer> data_;
163-
rj::Document doc_;
164166

165-
const rj::Value* record_batches_;
167+
simdjson::dom::parser parser_;
168+
JsonValue doc_;
169+
std::vector<JsonValue> record_batches_;
170+
166171
std::shared_ptr<Schema> schema_;
167172
DictionaryMemo dictionary_memo_;
168173
};

cpp/src/arrow/integration/json_integration.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ class ARROW_EXPORT IntegrationJsonWriter {
5555
private:
5656
explicit IntegrationJsonWriter(const std::shared_ptr<Schema>& schema);
5757

58-
// Hide RapidJSON details from public API
58+
// Hide JSON implementation details from public API
5959
class Impl;
6060
std::unique_ptr<Impl> impl_;
6161
};
@@ -106,7 +106,7 @@ class ARROW_EXPORT IntegrationJsonReader {
106106
private:
107107
IntegrationJsonReader(MemoryPool* pool, std::shared_ptr<Buffer> data);
108108

109-
// Hide RapidJSON details from public API
109+
// Hide JSON implementation details from public API
110110
class Impl;
111111
std::unique_ptr<Impl> impl_;
112112
};

cpp/src/arrow/integration/json_integration_test.cc

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
#include "arrow/type.h"
5050
#include "arrow/type_fwd.h"
5151
#include "arrow/util/io_util.h"
52+
#include "arrow/util/simdjson_internal.h"
5253

5354
DEFINE_string(arrow, "", "Arrow file name");
5455
DEFINE_string(json, "", "JSON file name");
@@ -734,10 +735,10 @@ void TestSchemaRoundTrip(const std::shared_ptr<Schema>& schema) {
734735

735736
ASSERT_OK_AND_ASSIGN(std::string_view json_schema, writer.GetString());
736737

737-
rj::Document d;
738-
// Pass explicit size to avoid ASAN issues with
739-
// SIMD loads in RapidJson.
740-
d.Parse(json_schema.data(), json_schema.size());
738+
simdjson::dom::parser parser;
739+
ASSERT_OK_AND_ASSIGN(auto d, internal::ResolveSimdjsonResult(
740+
parser.parse(json_schema.data(), json_schema.size()),
741+
"Failed to parse JSON"));
741742

742743
DictionaryMemo in_memo;
743744
ASSERT_OK_AND_ASSIGN(auto result_schema,
@@ -754,14 +755,11 @@ void TestArrayRoundTrip(const Array& array) {
754755

755756
ASSERT_OK_AND_ASSIGN(std::string_view array_as_json, writer.GetString());
756757

757-
rj::Document d;
758-
// Pass explicit size to avoid ASAN issues with
759-
// SIMD loads in RapidJson.
760-
d.Parse(array_as_json.data(), array_as_json.size());
761-
if (d.HasParseError()) {
762-
FAIL() << "JSON parsing failed";
763-
}
764-
758+
simdjson::dom::parser parser;
759+
ASSERT_OK_AND_ASSIGN(auto d,
760+
internal::ResolveSimdjsonResult(
761+
parser.parse(array_as_json.data(), array_as_json.size()),
762+
"Failed to parse JSON"));
765763
ASSERT_OK_AND_ASSIGN(
766764
auto result_array,
767765
json::ReadArray(default_memory_pool(), d, ::arrow::field(name, array.type())));
@@ -1111,10 +1109,10 @@ TEST(TestJsonFileReadWrite, JsonExample6) {
11111109
}
11121110

11131111
static void AssertInvalidBinaryViewJson(const std::string& json_array) {
1114-
rj::Document d;
1115-
// Pass explicit size to avoid ASAN issues with SIMD loads in RapidJson.
1116-
d.Parse(json_array.data(), json_array.size());
1117-
ASSERT_FALSE(d.HasParseError());
1112+
simdjson::dom::parser parser;
1113+
ASSERT_OK_AND_ASSIGN(auto d, internal::ResolveSimdjsonResult(
1114+
parser.parse(json_array.data(), json_array.size()),
1115+
"Failed to parse JSON"));
11181116

11191117
ASSERT_RAISES(Invalid,
11201118
json::ReadArray(default_memory_pool(), d, field("f", binary_view())));

0 commit comments

Comments
 (0)