Skip to content

Commit 81645cf

Browse files
committed
GH-35460: Migrate ObjectParser to simdjson
1 parent 68c300e commit 81645cf

1 file changed

Lines changed: 71 additions & 27 deletions

File tree

cpp/src/arrow/json/object_parser.cc

Lines changed: 71 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -16,72 +16,116 @@
1616
// under the License.
1717

1818
#include "arrow/json/object_parser.h"
19-
#include "arrow/json/rapidjson_defs.h" // IWYU pragma: keep
2019

21-
#include <rapidjson/document.h>
20+
#include <simdjson.h>
2221

2322
namespace arrow {
2423
namespace json {
2524
namespace internal {
2625

27-
namespace rj = arrow::rapidjson;
28-
2926
class ObjectParser::Impl {
3027
public:
3128
Status Parse(std::string_view json) {
32-
document_.Parse(reinterpret_cast<const rj::Document::Ch*>(json.data()),
33-
static_cast<size_t>(json.size()));
29+
// Copy into padded buffer
30+
padded_json_ = simdjson::padded_string(json);
31+
32+
// Parse
33+
auto result = parser_.parse(padded_json_);
3434

35-
if (document_.HasParseError()) {
36-
return Status::Invalid("Json parse error (offset ", document_.GetErrorOffset(),
37-
"): ", document_.GetParseError());
35+
// Handle parse errors
36+
if (result.error()) {
37+
return Status::Invalid("Json parse error: ",
38+
simdjson::error_message(result.error()));
3839
}
39-
if (!document_.IsObject()) {
40+
41+
// Store parsed document
42+
document_ = std::move(result).value();
43+
44+
// Validate root is an object
45+
if (!document_.is_object()) {
4046
return Status::TypeError("Not a json object");
4147
}
48+
4249
return Status::OK();
4350
}
4451

4552
Result<std::string> GetString(const char* key) const {
46-
if (!document_.HasMember(key)) {
53+
auto field = document_[key];
54+
if (field.error() == simdjson::NO_SUCH_FIELD) {
4755
return Status::KeyError("Key '", key, "' does not exist");
4856
}
49-
if (!document_[key].IsString()) {
57+
if (field.error()) {
58+
return Status::Invalid("Error accessing key '", key,
59+
"': ", simdjson::error_message(field.error()));
60+
}
61+
62+
auto str_result = field.get_string();
63+
if (str_result.error() == simdjson::INCORRECT_TYPE) {
5064
return Status::TypeError("Key '", key, "' is not a string");
5165
}
52-
return document_[key].GetString();
66+
if (str_result.error()) {
67+
return Status::Invalid("Error getting string for key '", key,
68+
"': ", simdjson::error_message(str_result.error()));
69+
}
70+
71+
return std::string(str_result.value());
5372
}
5473

5574
Result<std::unordered_map<std::string, std::string>> GetStringMap() const {
5675
std::unordered_map<std::string, std::string> map;
57-
for (auto itr = document_.MemberBegin(); itr != document_.MemberEnd(); ++itr) {
58-
const auto& json_name = itr->name;
59-
const auto& json_value = itr->value;
60-
if (!json_name.IsString()) {
61-
return Status::TypeError("Key is not a string");
76+
77+
auto obj_result = document_.get_object();
78+
if (obj_result.error()) {
79+
return Status::TypeError("Document is not an object");
80+
}
81+
82+
simdjson::dom::object obj = obj_result.value();
83+
84+
for (auto [key, value] : obj) {
85+
auto str_result = value.get_string();
86+
87+
if (str_result.error() == simdjson::INCORRECT_TYPE) {
88+
return Status::TypeError("Key '", std::string(key),
89+
"' does not have a string value");
6290
}
63-
std::string name = json_name.GetString();
64-
if (!json_value.IsString()) {
65-
return Status::TypeError("Key '", name, "' does not have a string value");
91+
if (str_result.error()) {
92+
return Status::Invalid("Error getting value for key '",
93+
std::string(key), "': ",
94+
simdjson::error_message(str_result.error()));
6695
}
67-
std::string value = json_value.GetString();
68-
map.insert({std::move(name), std::move(value)});
96+
97+
map.emplace(std::string(key), std::string(str_result.value()));
6998
}
99+
70100
return map;
71101
}
72102

73103
Result<bool> GetBool(const char* key) const {
74-
if (!document_.HasMember(key)) {
104+
auto field = document_[key];
105+
if (field.error() == simdjson::NO_SUCH_FIELD) {
75106
return Status::KeyError("Key '", key, "' does not exist");
76107
}
77-
if (!document_[key].IsBool()) {
108+
if (field.error()) {
109+
return Status::Invalid("Error accessing key '", key,
110+
"': ", simdjson::error_message(field.error()));
111+
}
112+
113+
auto bool_result = field.get_bool();
114+
if (bool_result.error() == simdjson::INCORRECT_TYPE) {
78115
return Status::TypeError("Key '", key, "' is not a boolean");
79116
}
80-
return document_[key].GetBool();
117+
if (bool_result.error()) {
118+
return Status::Invalid("Error getting bool for key '", key,
119+
"': ", simdjson::error_message(bool_result.error()));
120+
}
121+
122+
return bool_result.value();
81123
}
82124

83125
private:
84-
rj::Document document_;
126+
simdjson::dom::parser parser_;
127+
simdjson::padded_string padded_json_;
128+
simdjson::dom::element document_;
85129
};
86130

87131
ObjectParser::ObjectParser() : impl_(new ObjectParser::Impl()) {}

0 commit comments

Comments
 (0)