Skip to content

Commit 8ed2513

Browse files
committed
Replace in test_commons
1 parent 51345b8 commit 8ed2513

5 files changed

Lines changed: 180 additions & 35 deletions

File tree

cpp/src/arrow/CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -732,8 +732,8 @@ else()
732732
endif()
733733

734734
set(ARROW_TESTING_SHARED_LINK_LIBS arrow_shared ${ARROW_GTEST_GTEST})
735-
set(ARROW_TESTING_SHARED_PRIVATE_LINK_LIBS arrow::flatbuffers RapidJSON arrow::simdjson)
736-
set(ARROW_TESTING_STATIC_LINK_LIBS arrow::flatbuffers RapidJSON arrow::simdjson arrow_static
735+
set(ARROW_TESTING_SHARED_PRIVATE_LINK_LIBS arrow::flatbuffers arrow::simdjson)
736+
set(ARROW_TESTING_STATIC_LINK_LIBS arrow::flatbuffers arrow::simdjson arrow_static
737737
${ARROW_GTEST_GTEST})
738738
if(ARROW_ENABLE_THREADING)
739739
list(APPEND ARROW_TESTING_SHARED_PRIVATE_LINK_LIBS arrow::Boost::process)

cpp/src/arrow/json/parser_test.cc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,5 +321,17 @@ TEST(BlockParser, AdHoc) {
321321
R"([{"c":true, "d": "1991-02-03"}, {"c":false, "d":"2019-04-01"}])"});
322322
}
323323

324+
TEST(JsonTest, PrettyPrintEscapesObjectKeys) {
325+
const std::string input = R"({"a\"b":1,"a\\b":2})";
326+
327+
const std::string expected =
328+
"{\n"
329+
" \"a\\\"b\": 1,\n"
330+
" \"a\\\\b\": 2\n"
331+
"}";
332+
333+
EXPECT_EQ(PrettyPrint(input), expected);
334+
}
335+
324336
} // namespace json
325337
} // namespace arrow

cpp/src/arrow/json/reader_test.cc

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
#include "arrow/io/interfaces.h"
2626
#include "arrow/io/slow.h"
27+
#include "arrow/json/json_writer_internal.h"
2728
#include "arrow/json/options.h"
2829
#include "arrow/json/reader.h"
2930
#include "arrow/json/test_common.h"
@@ -550,10 +551,14 @@ class StreamingReaderTestBase {
550551
auto options = GenerateOptions::Defaults();
551552
options.null_probability = 0;
552553
for (int i = 0; i < num_rows; ++i) {
553-
StringBuffer string_buffer;
554-
Writer writer(string_buffer);
554+
Writer writer;
555555
ABORT_NOT_OK(Generate(data_fields, engine, &writer, options));
556-
std::string json = string_buffer.GetString();
556+
557+
auto json_result = writer.GetString();
558+
ABORT_NOT_OK(json_result.status());
559+
auto json_view = std::move(json_result).ValueOrDie();
560+
std::string json(json_view);
561+
557562
rows[i] = Join({"{\"i\":", std::to_string(i), ",\"d\":", json, "}\n"});
558563
max_row_size = std::max(max_row_size, rows[i].size());
559564
}

cpp/src/arrow/json/test_common.h

Lines changed: 45 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -25,35 +25,31 @@
2525
#include <utility>
2626
#include <vector>
2727

28+
#include <simdjson.h>
29+
2830
#include "arrow/array.h"
2931
#include "arrow/array/builder_binary.h"
3032
#include "arrow/io/memory.h"
3133
#include "arrow/json/converter.h"
34+
#include "arrow/json/json_writer_internal.h"
3235
#include "arrow/json/options.h"
3336
#include "arrow/json/parser.h"
34-
#include "arrow/json/rapidjson_defs.h"
37+
#include "arrow/result.h"
3538
#include "arrow/testing/gtest_util.h"
3639
#include "arrow/testing/random.h"
3740
#include "arrow/type.h"
3841
#include "arrow/util/checked_cast.h"
42+
#include "arrow/util/simdjson_internal.h"
3943
#include "arrow/visit_type_inline.h"
4044

41-
#include "rapidjson/document.h"
42-
#include "rapidjson/prettywriter.h"
43-
#include "rapidjson/reader.h"
44-
#include "rapidjson/writer.h"
45-
4645
namespace arrow {
4746

4847
using internal::checked_cast;
4948

5049
namespace json {
5150

52-
namespace rj = arrow::rapidjson;
53-
54-
using rj::StringBuffer;
5551
using std::string_view;
56-
using Writer = rj::Writer<StringBuffer>;
52+
using Writer = JsonWriter;
5753

5854
struct GenerateOptions {
5955
// Probability of a field being written
@@ -87,35 +83,43 @@ inline static Status Generate(
8783

8884
template <typename Engine>
8985
struct GenerateImpl {
90-
Status Visit(const NullType&) { return OK(writer.Null()); }
86+
Status Visit(const NullType&) {
87+
writer.Null();
88+
return Status::OK();
89+
}
9190

9291
Status Visit(const BooleanType&) {
93-
return OK(writer.Bool(std::uniform_int_distribution<uint16_t>{}(e) & 1));
92+
writer.Bool(std::uniform_int_distribution<uint16_t>{}(e) & 1);
93+
return Status::OK();
9494
}
9595

9696
template <typename T>
9797
enable_if_physical_unsigned_integer<T, Status> Visit(const T&) {
9898
auto val = std::uniform_int_distribution<>{}(e);
99-
return OK(writer.Uint64(static_cast<typename T::c_type>(val)));
99+
writer.Uint64(static_cast<typename T::c_type>(val));
100+
return Status::OK();
100101
}
101102

102103
template <typename T>
103104
enable_if_physical_signed_integer<T, Status> Visit(const T&) {
104105
auto val = std::uniform_int_distribution<>{}(e);
105-
return OK(writer.Int64(static_cast<typename T::c_type>(val)));
106+
writer.Int64(static_cast<typename T::c_type>(val));
107+
return Status::OK();
106108
}
107109

108110
template <typename T>
109111
enable_if_physical_floating_point<T, Status> Visit(const T&) {
110112
auto val = std::normal_distribution<typename T::c_type>{0, 1 << 10}(e);
111-
return OK(writer.Double(val));
113+
writer.Double(val);
114+
return Status::OK();
112115
}
113116

114117
Status GenerateUtf8(const DataType&) {
115118
auto num_codepoints = std::poisson_distribution<>{4}(e);
116119
auto seed = std::uniform_int_distribution<uint32_t>{}(e);
117120
std::string s = RandomUtf8String(seed, num_codepoints);
118-
return OK(writer.String(s));
121+
writer.String(s);
122+
return Status::OK();
119123
}
120124

121125
template <typename T>
@@ -132,7 +136,8 @@ struct GenerateImpl {
132136
for (int i = 0; i < size; ++i) {
133137
RETURN_NOT_OK(Generate(t.value_type(), e, &writer, options));
134138
}
135-
return OK(writer.EndArray(size));
139+
writer.EndArray();
140+
return Status::OK();
136141
}
137142

138143
Status Visit(const ListViewType& t) { return NotImplemented(t); }
@@ -162,7 +167,7 @@ struct GenerateImpl {
162167
}
163168

164169
Engine& e;
165-
rj::Writer<rj::StringBuffer>& writer;
170+
Writer& writer;
166171
const GenerateOptions& options;
167172
};
168173

@@ -180,12 +185,9 @@ inline static Status Generate(const std::shared_ptr<DataType>& type, Engine& e,
180185
template <typename Engine>
181186
inline static Status Generate(const std::vector<std::shared_ptr<Field>>& fields,
182187
Engine& e, Writer* writer, const GenerateOptions& options) {
183-
RETURN_NOT_OK(OK(writer->StartObject()));
184-
185-
int num_fields = 0;
188+
writer->StartObject();
186189
auto write_field = [&](const Field& f) {
187-
++num_fields;
188-
writer->Key(f.name().c_str());
190+
writer->Key(f.name());
189191
return Generate(f.type(), e, writer, options);
190192
};
191193

@@ -210,7 +212,8 @@ inline static Status Generate(const std::vector<std::shared_ptr<Field>>& fields,
210212
}
211213
}
212214

213-
return OK(writer->EndObject(num_fields));
215+
writer->EndObject();
216+
return Status::OK();
214217
}
215218

216219
inline static Status MakeStream(string_view src_str,
@@ -258,14 +261,26 @@ inline static Status ParseFromString(ParseOptions options, string_view src_str,
258261
}
259262

260263
static inline std::string PrettyPrint(string_view one_line) {
261-
rj::Document document;
264+
simdjson::ondemand::parser parser;
262265

263266
// Must pass size to avoid ASAN issues.
264-
document.Parse(one_line.data(), one_line.size());
265-
rj::StringBuffer sb;
266-
rj::PrettyWriter<rj::StringBuffer> writer(sb);
267-
document.Accept(writer);
268-
return sb.GetString();
267+
simdjson::padded_string json(one_line.data(), one_line.size());
268+
269+
auto document_result =
270+
internal::ResolveSimdjsonResult(parser.iterate(json), "Failed to parse JSON");
271+
ABORT_NOT_OK(document_result.status());
272+
auto document = std::move(document_result).ValueOrDie();
273+
274+
auto value_result =
275+
internal::ResolveSimdjsonResult(document.get_value(), "Failed to get JSON value");
276+
ABORT_NOT_OK(value_result.status());
277+
auto value = std::move(value_result).ValueOrDie();
278+
279+
std::string result;
280+
result.reserve(one_line.size());
281+
282+
ABORT_NOT_OK(internal::PrettyPrintJsonValue(value, &result));
283+
return result;
269284
}
270285

271286
template <typename T>

cpp/src/arrow/util/simdjson_internal.h

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
#include <simdjson.h>
2929

30+
#include "arrow/json/json_writer_internal.h"
3031
#include "arrow/result.h"
3132
#include "arrow/status.h"
3233

@@ -294,6 +295,118 @@ Status VisitJsonValue(simdjson::ondemand::value value, ObjectFn&& object_fn,
294295
return Status::Invalid("Unreachable");
295296
}
296297

298+
inline Status PrettyPrintJsonValue(simdjson::ondemand::value value, std::string* out,
299+
int indent = 0) {
300+
constexpr int kIndentSize = 4;
301+
302+
auto append_indent = [&](int level) {
303+
out->append(static_cast<size_t>(level * kIndentSize), ' ');
304+
};
305+
306+
ARROW_ASSIGN_OR_RAISE(
307+
auto type, ResolveSimdjsonResult(value.type(), "Failed to determine JSON type"));
308+
309+
switch (type) {
310+
case simdjson::ondemand::json_type::object: {
311+
ARROW_ASSIGN_OR_RAISE(
312+
auto object,
313+
ResolveSimdjsonResult(value.get_object(), "Failed to get JSON object"));
314+
315+
out->append("{");
316+
317+
bool first = true;
318+
for (auto field_result : object) {
319+
ARROW_ASSIGN_OR_RAISE(
320+
auto field,
321+
ResolveSimdjsonResult(field_result, "Failed to iterate JSON object"));
322+
323+
ARROW_ASSIGN_OR_RAISE(auto key,
324+
ResolveSimdjsonResult(field.unescaped_key(),
325+
"Failed to get JSON object key"));
326+
327+
auto field_value = field.value();
328+
329+
if (first) {
330+
out->append("\n");
331+
first = false;
332+
} else {
333+
out->append(",\n");
334+
}
335+
336+
append_indent(indent + 1);
337+
338+
json::JsonWriter writer;
339+
writer.String(key);
340+
341+
ARROW_ASSIGN_OR_RAISE(auto escaped_key, writer.GetString());
342+
out->append(escaped_key);
343+
out->append(": ");
344+
345+
RETURN_NOT_OK(PrettyPrintJsonValue(field_value, out, indent + 1));
346+
}
347+
348+
if (!first) {
349+
out->append("\n");
350+
append_indent(indent);
351+
}
352+
353+
out->append("}");
354+
return Status::OK();
355+
}
356+
357+
case simdjson::ondemand::json_type::array: {
358+
ARROW_ASSIGN_OR_RAISE(
359+
auto array,
360+
ResolveSimdjsonResult(value.get_array(), "Failed to get JSON array"));
361+
362+
out->append("[");
363+
364+
bool first = true;
365+
for (auto element_result : array) {
366+
ARROW_ASSIGN_OR_RAISE(
367+
auto element,
368+
ResolveSimdjsonResult(element_result, "Failed to iterate JSON array"));
369+
370+
if (first) {
371+
out->append("\n");
372+
first = false;
373+
} else {
374+
out->append(",\n");
375+
}
376+
377+
append_indent(indent + 1);
378+
379+
RETURN_NOT_OK(PrettyPrintJsonValue(element, out, indent + 1));
380+
}
381+
382+
if (!first) {
383+
out->append("\n");
384+
append_indent(indent);
385+
}
386+
387+
out->append("]");
388+
return Status::OK();
389+
}
390+
391+
case simdjson::ondemand::json_type::string:
392+
case simdjson::ondemand::json_type::boolean:
393+
case simdjson::ondemand::json_type::null:
394+
case simdjson::ondemand::json_type::number: {
395+
ARROW_ASSIGN_OR_RAISE(auto serialized,
396+
ResolveSimdjsonResult(simdjson::to_json_string(value),
397+
"Failed to serialize JSON value"));
398+
399+
out->append(serialized);
400+
return Status::OK();
401+
}
402+
403+
case simdjson::ondemand::json_type::unknown:
404+
return Status::Invalid("Unknown JSON type");
405+
}
406+
407+
return Status::Invalid("Unreachable");
408+
}
409+
297410
inline const char* JsonTypeName(simdjson::ondemand::json_type type) {
298411
switch (type) {
299412
case simdjson::ondemand::json_type::array:

0 commit comments

Comments
 (0)