| 1 | namespace simdjson { |
| 2 | namespace SIMDJSON_IMPLEMENTATION { |
| 3 | namespace ondemand { |
| 4 | |
| 5 | simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) & noexcept { |
| 6 | bool has_value; |
| 7 | SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) ); |
| 8 | if (!has_value) { return NO_SUCH_FIELD; } |
| 9 | return value(iter.child()); |
| 10 | } |
| 11 | simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) && noexcept { |
| 12 | bool has_value; |
| 13 | SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) ); |
| 14 | if (!has_value) { return NO_SUCH_FIELD; } |
| 15 | return value(iter.child()); |
| 16 | } |
| 17 | simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) & noexcept { |
| 18 | return find_field_unordered(key); |
| 19 | } |
| 20 | simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) && noexcept { |
| 21 | return std::forward<object>(t&: *this).find_field_unordered(key); |
| 22 | } |
| 23 | simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) & noexcept { |
| 24 | bool has_value; |
| 25 | SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) ); |
| 26 | if (!has_value) { return NO_SUCH_FIELD; } |
| 27 | return value(iter.child()); |
| 28 | } |
| 29 | simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) && noexcept { |
| 30 | bool has_value; |
| 31 | SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) ); |
| 32 | if (!has_value) { return NO_SUCH_FIELD; } |
| 33 | return value(iter.child()); |
| 34 | } |
| 35 | |
| 36 | simdjson_inline simdjson_result<object> object::start(value_iterator &iter) noexcept { |
| 37 | SIMDJSON_TRY( iter.start_object().error() ); |
| 38 | return object(iter); |
| 39 | } |
| 40 | simdjson_inline simdjson_result<object> object::start_root(value_iterator &iter) noexcept { |
| 41 | SIMDJSON_TRY( iter.start_root_object().error() ); |
| 42 | return object(iter); |
| 43 | } |
| 44 | simdjson_inline error_code object::consume() noexcept { |
| 45 | if(iter.is_at_key()) { |
| 46 | /** |
| 47 | * whenever you are pointing at a key, calling skip_child() is |
| 48 | * unsafe because you will hit a string and you will assume that |
| 49 | * it is string value, and this mistake will lead you to make bad |
| 50 | * depth computation. |
| 51 | */ |
| 52 | /** |
| 53 | * We want to 'consume' the key. We could really |
| 54 | * just do _json_iter->return_current_and_advance(); at this |
| 55 | * point, but, for clarity, we will use the high-level API to |
| 56 | * eat the key. We assume that the compiler optimizes away |
| 57 | * most of the work. |
| 58 | */ |
| 59 | simdjson_unused raw_json_string actual_key; |
| 60 | auto error = iter.field_key().get(value&: actual_key); |
| 61 | if (error) { iter.abandon(); return error; }; |
| 62 | // Let us move to the value while we are at it. |
| 63 | if ((error = iter.field_value())) { iter.abandon(); return error; } |
| 64 | } |
| 65 | auto error_skip = iter.json_iter().skip_child(parent_depth: iter.depth()-1); |
| 66 | if(error_skip) { iter.abandon(); } |
| 67 | return error_skip; |
| 68 | } |
| 69 | |
| 70 | simdjson_inline simdjson_result<std::string_view> object::raw_json() noexcept { |
| 71 | const uint8_t * starting_point{iter.peek_start()}; |
| 72 | auto error = consume(); |
| 73 | if(error) { return error; } |
| 74 | const uint8_t * final_point{iter._json_iter->peek(delta: 0)}; |
| 75 | return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point)); |
| 76 | } |
| 77 | |
| 78 | simdjson_inline simdjson_result<object> object::started(value_iterator &iter) noexcept { |
| 79 | SIMDJSON_TRY( iter.started_object().error() ); |
| 80 | return object(iter); |
| 81 | } |
| 82 | |
| 83 | simdjson_inline object object::resume(const value_iterator &iter) noexcept { |
| 84 | return iter; |
| 85 | } |
| 86 | |
| 87 | simdjson_inline object::object(const value_iterator &_iter) noexcept |
| 88 | : iter{_iter} |
| 89 | { |
| 90 | } |
| 91 | |
| 92 | simdjson_inline simdjson_result<object_iterator> object::begin() noexcept { |
| 93 | #if SIMDJSON_DEVELOPMENT_CHECKS |
| 94 | if (!iter.is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; } |
| 95 | #endif |
| 96 | return object_iterator(iter); |
| 97 | } |
| 98 | simdjson_inline simdjson_result<object_iterator> object::end() noexcept { |
| 99 | return object_iterator(iter); |
| 100 | } |
| 101 | |
| 102 | inline simdjson_result<value> object::at_pointer(std::string_view json_pointer) noexcept { |
| 103 | if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; } |
| 104 | json_pointer = json_pointer.substr(pos: 1); |
| 105 | size_t slash = json_pointer.find(c: '/'); |
| 106 | std::string_view key = json_pointer.substr(pos: 0, n: slash); |
| 107 | // Grab the child with the given key |
| 108 | simdjson_result<value> child; |
| 109 | |
| 110 | // If there is an escape character in the key, unescape it and then get the child. |
| 111 | size_t escape = key.find(c: '~'); |
| 112 | if (escape != std::string_view::npos) { |
| 113 | // Unescape the key |
| 114 | std::string unescaped(key); |
| 115 | do { |
| 116 | switch (unescaped[escape+1]) { |
| 117 | case '0': |
| 118 | unescaped.replace(pos: escape, n1: 2, s: "~" ); |
| 119 | break; |
| 120 | case '1': |
| 121 | unescaped.replace(pos: escape, n1: 2, s: "/" ); |
| 122 | break; |
| 123 | default: |
| 124 | return INVALID_JSON_POINTER; // "Unexpected ~ escape character in JSON pointer"); |
| 125 | } |
| 126 | escape = unescaped.find(c: '~', pos: escape+1); |
| 127 | } while (escape != std::string::npos); |
| 128 | child = find_field(key: unescaped); // Take note find_field does not unescape keys when matching |
| 129 | } else { |
| 130 | child = find_field(key); |
| 131 | } |
| 132 | if(child.error()) { |
| 133 | return child; // we do not continue if there was an error |
| 134 | } |
| 135 | // If there is a /, we have to recurse and look up more of the path |
| 136 | if (slash != std::string_view::npos) { |
| 137 | child = child.at_pointer(json_pointer: json_pointer.substr(pos: slash)); |
| 138 | } |
| 139 | return child; |
| 140 | } |
| 141 | |
| 142 | simdjson_inline simdjson_result<size_t> object::count_fields() & noexcept { |
| 143 | size_t count{0}; |
| 144 | // Important: we do not consume any of the values. |
| 145 | for(simdjson_unused auto v : *this) { count++; } |
| 146 | // The above loop will always succeed, but we want to report errors. |
| 147 | if(iter.error()) { return iter.error(); } |
| 148 | // We need to move back at the start because we expect users to iterate through |
| 149 | // the object after counting the number of elements. |
| 150 | iter.reset_object(); |
| 151 | return count; |
| 152 | } |
| 153 | |
| 154 | simdjson_inline simdjson_result<bool> object::is_empty() & noexcept { |
| 155 | bool is_not_empty; |
| 156 | auto error = iter.reset_object().get(value&: is_not_empty); |
| 157 | if(error) { return error; } |
| 158 | return !is_not_empty; |
| 159 | } |
| 160 | |
| 161 | simdjson_inline simdjson_result<bool> object::reset() & noexcept { |
| 162 | return iter.reset_object(); |
| 163 | } |
| 164 | |
| 165 | } // namespace ondemand |
| 166 | } // namespace SIMDJSON_IMPLEMENTATION |
| 167 | } // namespace simdjson |
| 168 | |
| 169 | namespace simdjson { |
| 170 | |
| 171 | simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::simdjson_result(SIMDJSON_IMPLEMENTATION::ondemand::object &&value) noexcept |
| 172 | : implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::object>(std::forward<SIMDJSON_IMPLEMENTATION::ondemand::object>(t&: value)) {} |
| 173 | simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::simdjson_result(error_code error) noexcept |
| 174 | : implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::object>(error) {} |
| 175 | |
| 176 | simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::begin() noexcept { |
| 177 | if (error()) { return error(); } |
| 178 | return first.begin(); |
| 179 | } |
| 180 | simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::end() noexcept { |
| 181 | if (error()) { return error(); } |
| 182 | return first.end(); |
| 183 | } |
| 184 | simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::find_field_unordered(std::string_view key) & noexcept { |
| 185 | if (error()) { return error(); } |
| 186 | return first.find_field_unordered(key); |
| 187 | } |
| 188 | simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::find_field_unordered(std::string_view key) && noexcept { |
| 189 | if (error()) { return error(); } |
| 190 | return std::forward<SIMDJSON_IMPLEMENTATION::ondemand::object>(t&: first).find_field_unordered(key); |
| 191 | } |
| 192 | simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::operator[](std::string_view key) & noexcept { |
| 193 | if (error()) { return error(); } |
| 194 | return first[key]; |
| 195 | } |
| 196 | simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::operator[](std::string_view key) && noexcept { |
| 197 | if (error()) { return error(); } |
| 198 | return std::forward<SIMDJSON_IMPLEMENTATION::ondemand::object>(t&: first)[key]; |
| 199 | } |
| 200 | simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::find_field(std::string_view key) & noexcept { |
| 201 | if (error()) { return error(); } |
| 202 | return first.find_field(key); |
| 203 | } |
| 204 | simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::find_field(std::string_view key) && noexcept { |
| 205 | if (error()) { return error(); } |
| 206 | return std::forward<SIMDJSON_IMPLEMENTATION::ondemand::object>(t&: first).find_field(key); |
| 207 | } |
| 208 | |
| 209 | simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::at_pointer(std::string_view json_pointer) noexcept { |
| 210 | if (error()) { return error(); } |
| 211 | return first.at_pointer(json_pointer); |
| 212 | } |
| 213 | |
| 214 | inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::reset() noexcept { |
| 215 | if (error()) { return error(); } |
| 216 | return first.reset(); |
| 217 | } |
| 218 | |
| 219 | inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::is_empty() noexcept { |
| 220 | if (error()) { return error(); } |
| 221 | return first.is_empty(); |
| 222 | } |
| 223 | |
| 224 | simdjson_inline simdjson_result<size_t> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::count_fields() & noexcept { |
| 225 | if (error()) { return error(); } |
| 226 | return first.count_fields(); |
| 227 | } |
| 228 | |
| 229 | } // namespace simdjson |
| 230 | |