1#include "simdjson/error.h"
2
3namespace simdjson {
4namespace SIMDJSON_IMPLEMENTATION {
5namespace ondemand {
6
7class value;
8class document;
9
10/**
11 * A forward-only JSON array.
12 */
13class array {
14public:
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;
113protected:
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
173namespace simdjson {
174
175template<>
176struct simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array> : public SIMDJSON_IMPLEMENTATION::implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::array> {
177public:
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