diff --git a/cpp/src/arrow/CMakeLists.txt b/cpp/src/arrow/CMakeLists.txt index d7086773a1fd..eead221dbdae 100644 --- a/cpp/src/arrow/CMakeLists.txt +++ b/cpp/src/arrow/CMakeLists.txt @@ -741,8 +741,8 @@ else() endif() set(ARROW_TESTING_SHARED_LINK_LIBS arrow_shared ${ARROW_GTEST_GTEST}) -set(ARROW_TESTING_SHARED_PRIVATE_LINK_LIBS arrow::flatbuffers RapidJSON) -set(ARROW_TESTING_STATIC_LINK_LIBS arrow::flatbuffers RapidJSON arrow_static +set(ARROW_TESTING_SHARED_PRIVATE_LINK_LIBS arrow::flatbuffers arrow::simdjson) +set(ARROW_TESTING_STATIC_LINK_LIBS arrow::flatbuffers arrow::simdjson arrow_static ${ARROW_GTEST_GTEST}) if(ARROW_ENABLE_THREADING) list(APPEND ARROW_TESTING_SHARED_PRIVATE_LINK_LIBS arrow::Boost::process) diff --git a/cpp/src/arrow/json/CMakeLists.txt b/cpp/src/arrow/json/CMakeLists.txt index b930034537d0..de9115497e2b 100644 --- a/cpp/src/arrow/json/CMakeLists.txt +++ b/cpp/src/arrow/json/CMakeLists.txt @@ -33,7 +33,9 @@ add_arrow_benchmark(parser_benchmark PREFIX "arrow-json" EXTRA_LINK_LIBS - RapidJSON) + RapidJSON + simdjson::simdjson) + arrow_install_all_headers("arrow/json") # pkg-config support diff --git a/cpp/src/arrow/json/parser_benchmark.cc b/cpp/src/arrow/json/parser_benchmark.cc index a5a6eb68e67a..f26d6a144316 100644 --- a/cpp/src/arrow/json/parser_benchmark.cc +++ b/cpp/src/arrow/json/parser_benchmark.cc @@ -38,10 +38,14 @@ std::string GenerateTestData(const Input& input, int num_rows, std::default_random_engine engine(kSeed); std::string json; for (int i = 0; i < num_rows; ++i) { - StringBuffer sb; - Writer writer(sb); + Writer writer; ABORT_NOT_OK(Generate(input, engine, &writer, options)); - json += pretty ? PrettyPrint(sb.GetString()) : sb.GetString(); + + auto json_result = writer.GetString(); + ABORT_NOT_OK(json_result.status()); + auto json_view = std::move(json_result).ValueOrDie(); + + json += pretty ? PrettyPrint(json_view) : json_view; json += "\n"; } return json; diff --git a/cpp/src/arrow/json/reader_test.cc b/cpp/src/arrow/json/reader_test.cc index 2aca602ae9ed..ac5bafb5293e 100644 --- a/cpp/src/arrow/json/reader_test.cc +++ b/cpp/src/arrow/json/reader_test.cc @@ -550,10 +550,11 @@ class StreamingReaderTestBase { auto options = GenerateOptions::Defaults(); options.null_probability = 0; for (int i = 0; i < num_rows; ++i) { - StringBuffer string_buffer; - Writer writer(string_buffer); + Writer writer; ABORT_NOT_OK(Generate(data_fields, engine, &writer, options)); - std::string json = string_buffer.GetString(); + + std::string json(writer.GetString().ValueOrDie()); + rows[i] = Join({"{\"i\":", std::to_string(i), ",\"d\":", json, "}\n"}); max_row_size = std::max(max_row_size, rows[i].size()); } diff --git a/cpp/src/arrow/json/test_common.h b/cpp/src/arrow/json/test_common.h index ab2ce9cdc749..241584959e74 100644 --- a/cpp/src/arrow/json/test_common.h +++ b/cpp/src/arrow/json/test_common.h @@ -25,35 +25,30 @@ #include #include +#include + #include "arrow/array.h" #include "arrow/array/builder_binary.h" #include "arrow/io/memory.h" #include "arrow/json/converter.h" #include "arrow/json/options.h" #include "arrow/json/parser.h" -#include "arrow/json/rapidjson_defs.h" +#include "arrow/result.h" #include "arrow/testing/gtest_util.h" #include "arrow/testing/random.h" #include "arrow/type.h" #include "arrow/util/checked_cast.h" +#include "arrow/util/simdjson_internal.h" #include "arrow/visit_type_inline.h" -#include "rapidjson/document.h" -#include "rapidjson/prettywriter.h" -#include "rapidjson/reader.h" -#include "rapidjson/writer.h" - namespace arrow { using internal::checked_cast; namespace json { -namespace rj = arrow::rapidjson; - -using rj::StringBuffer; using std::string_view; -using Writer = rj::Writer; +using Writer = internal::JsonWriter; struct GenerateOptions { // Probability of a field being written @@ -87,35 +82,43 @@ inline static Status Generate( template struct GenerateImpl { - Status Visit(const NullType&) { return OK(writer.Null()); } + Status Visit(const NullType&) { + writer.Null(); + return Status::OK(); + } Status Visit(const BooleanType&) { - return OK(writer.Bool(std::uniform_int_distribution{}(e) & 1)); + writer.Bool(std::uniform_int_distribution{}(e) & 1); + return Status::OK(); } template enable_if_physical_unsigned_integer Visit(const T&) { auto val = std::uniform_int_distribution<>{}(e); - return OK(writer.Uint64(static_cast(val))); + writer.Uint64(static_cast(val)); + return Status::OK(); } template enable_if_physical_signed_integer Visit(const T&) { auto val = std::uniform_int_distribution<>{}(e); - return OK(writer.Int64(static_cast(val))); + writer.Int64(static_cast(val)); + return Status::OK(); } template enable_if_physical_floating_point Visit(const T&) { auto val = std::normal_distribution{0, 1 << 10}(e); - return OK(writer.Double(val)); + writer.Double(val); + return Status::OK(); } Status GenerateUtf8(const DataType&) { auto num_codepoints = std::poisson_distribution<>{4}(e); auto seed = std::uniform_int_distribution{}(e); std::string s = RandomUtf8String(seed, num_codepoints); - return OK(writer.String(s)); + writer.String(s); + return Status::OK(); } template @@ -132,7 +135,8 @@ struct GenerateImpl { for (int i = 0; i < size; ++i) { RETURN_NOT_OK(Generate(t.value_type(), e, &writer, options)); } - return OK(writer.EndArray(size)); + writer.EndArray(); + return Status::OK(); } Status Visit(const ListViewType& t) { return NotImplemented(t); } @@ -162,7 +166,7 @@ struct GenerateImpl { } Engine& e; - rj::Writer& writer; + Writer& writer; const GenerateOptions& options; }; @@ -180,12 +184,9 @@ inline static Status Generate(const std::shared_ptr& type, Engine& e, template inline static Status Generate(const std::vector>& fields, Engine& e, Writer* writer, const GenerateOptions& options) { - RETURN_NOT_OK(OK(writer->StartObject())); - - int num_fields = 0; + writer->StartObject(); auto write_field = [&](const Field& f) { - ++num_fields; - writer->Key(f.name().c_str()); + writer->Key(f.name()); return Generate(f.type(), e, writer, options); }; @@ -210,7 +211,8 @@ inline static Status Generate(const std::vector>& fields, } } - return OK(writer->EndObject(num_fields)); + writer->EndObject(); + return Status::OK(); } inline static Status MakeStream(string_view src_str, @@ -257,15 +259,8 @@ inline static Status ParseFromString(ParseOptions options, string_view src_str, return Status::OK(); } -static inline std::string PrettyPrint(string_view one_line) { - rj::Document document; - - // Must pass size to avoid ASAN issues. - document.Parse(one_line.data(), one_line.size()); - rj::StringBuffer sb; - rj::PrettyWriter writer(sb); - document.Accept(writer); - return sb.GetString(); +static inline std::string PrettyPrint(std::string_view one_line) { + return simdjson::fractured_json_string(one_line); } template diff --git a/cpp/src/arrow/meson.build b/cpp/src/arrow/meson.build index f181321aaab7..fea26ef4e452 100644 --- a/cpp/src/arrow/meson.build +++ b/cpp/src/arrow/meson.build @@ -758,6 +758,7 @@ if needs_testing filesystem_dep, gmock_dep, gtest_dep, + simdjson_dep, ], ) diff --git a/cpp/src/arrow/testing/gtest_util.cc b/cpp/src/arrow/testing/gtest_util.cc index b7d2a963d0de..bbbb1f880af4 100644 --- a/cpp/src/arrow/testing/gtest_util.cc +++ b/cpp/src/arrow/testing/gtest_util.cc @@ -53,7 +53,6 @@ #include "arrow/ipc/reader.h" #include "arrow/ipc/writer.h" #include "arrow/json/from_string.h" -#include "arrow/json/rapidjson_defs.h" // IWYU pragma: keep #include "arrow/pretty_print.h" #include "arrow/record_batch.h" #include "arrow/status.h" @@ -65,13 +64,10 @@ #include "arrow/util/future.h" #include "arrow/util/io_util.h" #include "arrow/util/logging_internal.h" +#include "arrow/util/simdjson_internal.h" #include "arrow/util/thread_pool.h" #include "arrow/util/windows_compatibility.h" -#include - -namespace rj = arrow::rapidjson; - namespace arrow { using internal::checked_cast; @@ -445,24 +441,24 @@ std::shared_ptr TensorFromJSON(const std::shared_ptr& type, std::string_view dim_names) { std::shared_ptr array = arrow::ArrayFromJSON(type, data); - rj::Document json_shape; - json_shape.Parse(shape.data(), shape.length()); - std::vector shape_vector; - for (auto& x : json_shape.GetArray()) { - shape_vector.emplace_back(x.GetInt64()); - } - rj::Document json_strides; - json_strides.Parse(strides.data(), strides.length()); - std::vector strides_vector; - for (auto& x : json_strides.GetArray()) { - strides_vector.emplace_back(x.GetInt64()); - } - rj::Document json_dim_names; - json_dim_names.Parse(dim_names.data(), dim_names.length()); - std::vector dim_names_vector; - for (auto& x : json_dim_names.GetArray()) { - dim_names_vector.emplace_back(x.GetString()); - } + simdjson::dom::parser parser; + + auto json_shape = + internal::ResolveSimdjsonResult(parser.parse(shape), "Failed to parse shape") + .ValueOrDie(); + auto shape_vector = internal::GetJsonIntArray(json_shape, "shape").ValueOrDie(); + + auto json_strides = + internal::ResolveSimdjsonResult(parser.parse(strides), "Failed to parse strides") + .ValueOrDie(); + auto strides_vector = internal::GetJsonIntArray(json_strides, "strides").ValueOrDie(); + + auto json_dim_names = internal::ResolveSimdjsonResult(parser.parse(dim_names), + "Failed to parse dimension names") + .ValueOrDie(); + auto dim_names_vector = + internal::GetJsonStringArray(json_dim_names, "dimension names").ValueOrDie(); + return *Tensor::Make(type, array->data()->buffers[1], shape_vector, strides_vector, dim_names_vector); } diff --git a/cpp/src/arrow/testing/gtest_util_test.cc b/cpp/src/arrow/testing/gtest_util_test.cc index 31b5b9e66285..f8bf694f5c36 100644 --- a/cpp/src/arrow/testing/gtest_util_test.cc +++ b/cpp/src/arrow/testing/gtest_util_test.cc @@ -179,6 +179,23 @@ TEST_F(TestTensorFromJSON, FromJSON) { EXPECT_TRUE(tensor_expected->Equals(*result)); } +TEST_F(TestTensorFromJSON, FromJSONWithStridesAndDimNames) { + std::vector shape = {2, 3}; + std::vector strides = {sizeof(int64_t) * 3, sizeof(int64_t)}; + std::vector dim_names = {"row", "column"}; + std::vector values = {1, 2, 3, 4, 5, 6}; + auto data = Buffer::Wrap(values); + + std::shared_ptr tensor_expected; + ASSERT_OK_AND_ASSIGN(tensor_expected, + Tensor::Make(int64(), data, shape, strides, dim_names)); + + std::shared_ptr result = TensorFromJSON(int64(), "[1, 2, 3, 4, 5, 6]", "[2, 3]", + "[24, 8]", R"(["row", "column"])"); + + EXPECT_TRUE(tensor_expected->Equals(*result)); +} + TEST(AssertTestWithinUlp, Basics) { AssertWithinUlp(123.4567, 123.45670000000015, 11); AssertWithinUlp(123.456f, 123.456085f, 11);