Sourcemeta Core 0.0.0
Loading...
Searching...
No Matches
jsonpointer_walker.h
1#ifndef SOURCEMETA_CORE_JSONPOINTER_WALKER_H_
2#define SOURCEMETA_CORE_JSONPOINTER_WALKER_H_
3
4#include <sourcemeta/core/json.h>
5
6#include <algorithm> // std::reverse
7#include <cstddef> // std::size_t, std::ptrdiff_t
8#include <utility> // std::pair, std::move
9#include <vector> // std::vector
10
11namespace sourcemeta::core {
12
16template <typename PointerT> class GenericPointerWalker {
17private:
18 using internal = typename std::vector<PointerT>;
19
20public:
22 GenericPointerWalker(const JSON &document) {
23 PointerT accumulator;
24 this->walk(document, accumulator);
25 }
26
27 using const_iterator = typename internal::const_iterator;
28 [[nodiscard]] auto begin() const -> const_iterator {
29 return this->pointers.begin();
30 };
31 [[nodiscard]] auto end() const -> const_iterator {
32 return this->pointers.end();
33 };
34 [[nodiscard]] auto cbegin() const -> const_iterator {
35 return this->pointers.cbegin();
36 };
37 [[nodiscard]] auto cend() const -> const_iterator {
38 return this->pointers.cend();
39 };
40
41private:
42 auto walk(const JSON &document, PointerT &pointer) -> void {
43 // Traversal is iterative with an explicit stack so that a deeply nested
44 // document cannot overflow the call stack. The output ordering is
45 // unspecified either way
46 std::vector<std::pair<const JSON *, PointerT>> pending;
47 pending.emplace_back(&document, pointer);
48 while (!pending.empty()) {
49 auto entry{std::move(pending.back())};
50 pending.pop_back();
51 const JSON &node{*entry.first};
52 // Children are queued then reversed so that they are popped in their
53 // natural order, preserving the pre-order traversal of the recursive form
54 const auto start{pending.size()};
55 if (node.is_array()) {
56 for (std::size_t index = 0; index < node.size(); index++) {
57 PointerT child{entry.second};
58 child.emplace_back(index);
59 pending.emplace_back(&node.at(index), std::move(child));
60 }
61 } else if (node.is_object()) {
62 for (const auto &pair : node.as_object()) {
63 PointerT child{entry.second};
64 child.emplace_back(pair.first);
65 pending.emplace_back(&pair.second, std::move(child));
66 }
67 }
68
69 std::reverse(pending.begin() + static_cast<std::ptrdiff_t>(start),
70 pending.end());
71 this->pointers.push_back(std::move(entry.second));
72 }
73 }
74
75// Exporting symbols that depends on the standard C++ library is considered
76// safe.
77// https://learn.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-2-c4275?view=msvc-170&redirectedfrom=MSDN
78#if defined(_MSC_VER)
79#pragma warning(disable : 4251)
80#endif
81 internal pointers;
82#if defined(_MSC_VER)
83#pragma warning(default : 4251)
84#endif
85};
86
87} // namespace sourcemeta::core
88
89#endif
Definition json_value.h:39
GenericPointerWalker(const JSON &document)
Construct a walker over every location in a JSON document.
Definition jsonpointer_walker.h:22