|
16 | 16 | // under the License. |
17 | 17 |
|
18 | 18 | #include "arrow/json/object_parser.h" |
19 | | -#include "arrow/json/rapidjson_defs.h" // IWYU pragma: keep |
20 | 19 |
|
21 | | -#include <rapidjson/document.h> |
| 20 | +#include <simdjson.h> |
22 | 21 |
|
23 | 22 | namespace arrow { |
24 | 23 | namespace json { |
25 | 24 | namespace internal { |
26 | 25 |
|
27 | | -namespace rj = arrow::rapidjson; |
28 | | - |
29 | 26 | class ObjectParser::Impl { |
30 | 27 | public: |
31 | 28 | 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_); |
34 | 34 |
|
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())); |
38 | 39 | } |
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()) { |
40 | 46 | return Status::TypeError("Not a json object"); |
41 | 47 | } |
| 48 | + |
42 | 49 | return Status::OK(); |
43 | 50 | } |
44 | 51 |
|
45 | 52 | 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) { |
47 | 55 | return Status::KeyError("Key '", key, "' does not exist"); |
48 | 56 | } |
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) { |
50 | 64 | return Status::TypeError("Key '", key, "' is not a string"); |
51 | 65 | } |
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()); |
53 | 72 | } |
54 | 73 |
|
55 | 74 | Result<std::unordered_map<std::string, std::string>> GetStringMap() const { |
56 | 75 | 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"); |
62 | 90 | } |
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())); |
66 | 95 | } |
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())); |
69 | 98 | } |
| 99 | + |
70 | 100 | return map; |
71 | 101 | } |
72 | 102 |
|
73 | 103 | 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) { |
75 | 106 | return Status::KeyError("Key '", key, "' does not exist"); |
76 | 107 | } |
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) { |
78 | 115 | return Status::TypeError("Key '", key, "' is not a boolean"); |
79 | 116 | } |
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(); |
81 | 123 | } |
82 | 124 |
|
83 | 125 | private: |
84 | | - rj::Document document_; |
| 126 | + simdjson::dom::parser parser_; |
| 127 | + simdjson::padded_string padded_json_; |
| 128 | + simdjson::dom::element document_; |
85 | 129 | }; |
86 | 130 |
|
87 | 131 | ObjectParser::ObjectParser() : impl_(new ObjectParser::Impl()) {} |
|
0 commit comments