diff --git a/include/simdjson/generic/ondemand/document.h b/include/simdjson/generic/ondemand/document.h index 9abcd738..84e740f0 100644 --- a/include/simdjson/generic/ondemand/document.h +++ b/include/simdjson/generic/ondemand/document.h @@ -311,7 +311,8 @@ public: /** * Reset the iterator inside the document instance so we are pointing back at the - * beginning of the document, as if it had just been created. + * beginning of the document, as if it had just been created. It invalidates all + * values, objects and arrays that you have created so far (including unescaped strings). */ inline void rewind() noexcept; /** @@ -335,7 +336,11 @@ public: * auto doc = parser.iterate(json); * doc.at_pointer("//a/1") == 20 * - * Note that at_pointer() automatically calls rewind between each call. + * Note that at_pointer() automatically calls rewind between each call. Thus + * all values, objects and arrays that you have created so far (including unescaped strings) + * are invalidated. After calling at_pointer, you need to consume the result: string values + * should be stored in your own variables, arrays should be decoded and stored in your own array-like + * structures and so forth. * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching * * @return The value associated with the given JSON pointer, or: diff --git a/tests/ondemand/ondemand_json_pointer_tests.cpp b/tests/ondemand/ondemand_json_pointer_tests.cpp index ac79716a..ea7d430d 100644 --- a/tests/ondemand/ondemand_json_pointer_tests.cpp +++ b/tests/ondemand/ondemand_json_pointer_tests.cpp @@ -124,8 +124,65 @@ namespace json_pointer_tests { TEST_SUCCEED(); } + struct car_type { + std::string make; + std::string model; + uint64_t year; + std::vector tire_pressure; + car_type(std::string_view _make, std::string_view _model, uint64_t _year, + std::vector&& _tire_pressure) : + make{_make}, model{_model}, year(_year), tire_pressure(_tire_pressure) {} + }; + + bool json_pointer_invalidation() { + TEST_START(); + auto cars_json = R"( [ + { "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] }, + { "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] }, + { "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] } + ] )"_padded; + + ondemand::parser parser; + ondemand::document cars; + std::vector measured; + ASSERT_SUCCESS(parser.iterate(cars_json).get(cars)); + std::vector content; + for (int i = 0; i < 3; i++) { + ondemand::object obj; + std::string json_pointer = "/" + std::to_string(i); + // Each successive at_pointer call invalidates + // previously parsed values, strings, objects and array. + ASSERT_SUCCESS(cars.at_pointer(json_pointer).get(obj)); + // We materialize the object. + std::string_view make; + ASSERT_SUCCESS(obj["make"].get(make)); + std::string_view model; + ASSERT_SUCCESS(obj["model"].get(model)); + uint64_t year; + ASSERT_SUCCESS(obj["year"].get(year)); + // We materialize the array. + ondemand::array arr; + ASSERT_SUCCESS(obj["tire_pressure"].get(arr)); + std::vector values; + for(auto x : arr) { + double value_double; + ASSERT_SUCCESS(x.get(value_double)); + values.push_back(value_double); + } + content.emplace_back(make, model, year, std::move(values)); + } + std::string expected[] = {"Toyota", "Kia", "Toyota"}; + int i = 0; + for (car_type c : content) { + std::cout << c.make << " " << c.model << " " << c.year << "\n"; + ASSERT_EQUAL(expected[i++], c.make); + } + TEST_SUCCEED(); + } + bool run() { return + json_pointer_invalidation() && demo_test() && demo_relative_path() && run_success_test(TEST_RFC_JSON,"",R"({"foo":["bar","baz"],"":0,"a/b":1,"c%d":2,"e^f":3,"g|h":4,"i\\j":5,"k\"l":6," ":7,"m~n":8})") &&