| 1 | #include "simdjson/error.h" |
| 2 | |
| 3 | namespace simdjson { |
| 4 | namespace SIMDJSON_IMPLEMENTATION { |
| 5 | namespace ondemand { |
| 6 | |
| 7 | class value; |
| 8 | class document; |
| 9 | |
| 10 | /** |
| 11 | * A forward-only JSON array. |
| 12 | */ |
| 13 | class array { |
| 14 | public: |
| 15 | /** |
| 16 | * Create a new invalid array. |
| 17 | * |
| 18 | * Exists so you can declare a variable and later assign to it before use. |
| 19 | */ |
| 20 | simdjson_inline array() noexcept = default; |
| 21 | |
| 22 | /** |
| 23 | * Begin array iteration. |
| 24 | * |
| 25 | * Part of the std::iterable interface. |
| 26 | */ |
| 27 | simdjson_inline simdjson_result<array_iterator> begin() noexcept; |
| 28 | /** |
| 29 | * Sentinel representing the end of the array. |
| 30 | * |
| 31 | * Part of the std::iterable interface. |
| 32 | */ |
| 33 | simdjson_inline simdjson_result<array_iterator> end() noexcept; |
| 34 | /** |
| 35 | * This method scans the array and counts the number of elements. |
| 36 | * The count_elements method should always be called before you have begun |
| 37 | * iterating through the array: it is expected that you are pointing at |
| 38 | * the beginning of the array. |
| 39 | * The runtime complexity is linear in the size of the array. After |
| 40 | * calling this function, if successful, the array is 'rewinded' at its |
| 41 | * beginning as if it had never been accessed. If the JSON is malformed (e.g., |
| 42 | * there is a missing comma), then an error is returned and it is no longer |
| 43 | * safe to continue. |
| 44 | * |
| 45 | * To check that an array is empty, it is more performant to use |
| 46 | * the is_empty() method. |
| 47 | */ |
| 48 | simdjson_inline simdjson_result<size_t> count_elements() & noexcept; |
| 49 | /** |
| 50 | * This method scans the beginning of the array and checks whether the |
| 51 | * array is empty. |
| 52 | * The runtime complexity is constant time. After |
| 53 | * calling this function, if successful, the array is 'rewinded' at its |
| 54 | * beginning as if it had never been accessed. If the JSON is malformed (e.g., |
| 55 | * there is a missing comma), then an error is returned and it is no longer |
| 56 | * safe to continue. |
| 57 | */ |
| 58 | simdjson_inline simdjson_result<bool> is_empty() & noexcept; |
| 59 | /** |
| 60 | * Reset the iterator so that we are pointing back at the |
| 61 | * beginning of the array. You should still consume values only once even if you |
| 62 | * can iterate through the array more than once. If you unescape a string |
| 63 | * within the array more than once, you have unsafe code. Note that rewinding |
| 64 | * an array means that you may need to reparse it anew: it is not a free |
| 65 | * operation. |
| 66 | * |
| 67 | * @returns true if the array contains some elements (not empty) |
| 68 | */ |
| 69 | inline simdjson_result<bool> reset() & noexcept; |
| 70 | /** |
| 71 | * Get the value associated with the given JSON pointer. We use the RFC 6901 |
| 72 | * https://tools.ietf.org/html/rfc6901 standard, interpreting the current node |
| 73 | * as the root of its own JSON document. |
| 74 | * |
| 75 | * ondemand::parser parser; |
| 76 | * auto json = R"([ { "foo": { "a": [ 10, 20, 30 ] }} ])"_padded; |
| 77 | * auto doc = parser.iterate(json); |
| 78 | * doc.at_pointer("/0/foo/a/1") == 20 |
| 79 | * |
| 80 | * Note that at_pointer() called on the document automatically calls the document's rewind |
| 81 | * method between each call. It invalidates all previously accessed arrays, objects and values |
| 82 | * that have not been consumed. Yet it is not the case when calling at_pointer on an array |
| 83 | * instance: there is no rewind and no invalidation. |
| 84 | * |
| 85 | * You may only call at_pointer on an array after it has been created, but before it has |
| 86 | * been first accessed. When calling at_pointer on an array, the pointer is advanced to |
| 87 | * the location indicated by the JSON pointer (in case of success). It is no longer possible |
| 88 | * to call at_pointer on the same array. |
| 89 | * |
| 90 | * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching. |
| 91 | * |
| 92 | * @return The value associated with the given JSON pointer, or: |
| 93 | * - NO_SUCH_FIELD if a field does not exist in an object |
| 94 | * - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length |
| 95 | * - INCORRECT_TYPE if a non-integer is used to access an array |
| 96 | * - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed |
| 97 | */ |
| 98 | inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept; |
| 99 | /** |
| 100 | * Consumes the array and returns a string_view instance corresponding to the |
| 101 | * array as represented in JSON. It points inside the original document. |
| 102 | */ |
| 103 | simdjson_inline simdjson_result<std::string_view> raw_json() noexcept; |
| 104 | |
| 105 | /** |
| 106 | * Get the value at the given index. This function has linear-time complexity. |
| 107 | * This function should only be called once on an array instance since the array iterator is not reset between each call. |
| 108 | * |
| 109 | * @return The value at the given index, or: |
| 110 | * - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length |
| 111 | */ |
| 112 | simdjson_inline simdjson_result<value> at(size_t index) noexcept; |
| 113 | protected: |
| 114 | /** |
| 115 | * Go to the end of the array, no matter where you are right now. |
| 116 | */ |
| 117 | simdjson_inline error_code consume() noexcept; |
| 118 | |
| 119 | /** |
| 120 | * Begin array iteration. |
| 121 | * |
| 122 | * @param iter The iterator. Must be where the initial [ is expected. Will be *moved* into the |
| 123 | * resulting array. |
| 124 | * @error INCORRECT_TYPE if the iterator is not at [. |
| 125 | */ |
| 126 | static simdjson_inline simdjson_result<array> start(value_iterator &iter) noexcept; |
| 127 | /** |
| 128 | * Begin array iteration from the root. |
| 129 | * |
| 130 | * @param iter The iterator. Must be where the initial [ is expected. Will be *moved* into the |
| 131 | * resulting array. |
| 132 | * @error INCORRECT_TYPE if the iterator is not at [. |
| 133 | * @error TAPE_ERROR if there is no closing ] at the end of the document. |
| 134 | */ |
| 135 | static simdjson_inline simdjson_result<array> start_root(value_iterator &iter) noexcept; |
| 136 | /** |
| 137 | * Begin array iteration. |
| 138 | * |
| 139 | * This version of the method should be called after the initial [ has been verified, and is |
| 140 | * intended for use by switch statements that check the type of a value. |
| 141 | * |
| 142 | * @param iter The iterator. Must be after the initial [. Will be *moved* into the resulting array. |
| 143 | */ |
| 144 | static simdjson_inline simdjson_result<array> started(value_iterator &iter) noexcept; |
| 145 | |
| 146 | /** |
| 147 | * Create an array at the given Internal array creation. Call array::start() or array::started() instead of this. |
| 148 | * |
| 149 | * @param iter The iterator. Must either be at the start of the first element with iter.is_alive() |
| 150 | * == true, or past the [] with is_alive() == false if the array is empty. Will be *moved* |
| 151 | * into the resulting array. |
| 152 | */ |
| 153 | simdjson_inline array(const value_iterator &iter) noexcept; |
| 154 | |
| 155 | /** |
| 156 | * Iterator marking current position. |
| 157 | * |
| 158 | * iter.is_alive() == false indicates iteration is complete. |
| 159 | */ |
| 160 | value_iterator iter{}; |
| 161 | |
| 162 | friend class value; |
| 163 | friend class document; |
| 164 | friend struct simdjson_result<value>; |
| 165 | friend struct simdjson_result<array>; |
| 166 | friend class array_iterator; |
| 167 | }; |
| 168 | |
| 169 | } // namespace ondemand |
| 170 | } // namespace SIMDJSON_IMPLEMENTATION |
| 171 | } // namespace simdjson |
| 172 | |
| 173 | namespace simdjson { |
| 174 | |
| 175 | template<> |
| 176 | struct simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array> : public SIMDJSON_IMPLEMENTATION::implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::array> { |
| 177 | public: |
| 178 | simdjson_inline simdjson_result(SIMDJSON_IMPLEMENTATION::ondemand::array &&value) noexcept; ///< @private |
| 179 | simdjson_inline simdjson_result(error_code error) noexcept; ///< @private |
| 180 | simdjson_inline simdjson_result() noexcept = default; |
| 181 | |
| 182 | simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> begin() noexcept; |
| 183 | simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> end() noexcept; |
| 184 | inline simdjson_result<size_t> count_elements() & noexcept; |
| 185 | inline simdjson_result<bool> is_empty() & noexcept; |
| 186 | inline simdjson_result<bool> reset() & noexcept; |
| 187 | simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> at(size_t index) noexcept; |
| 188 | simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> at_pointer(std::string_view json_pointer) noexcept; |
| 189 | }; |
| 190 | |
| 191 | } // namespace simdjson |
| 192 | |