| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071 |
- #pragma once
- #include <deque>
- #include <map>
- #include <optional>
- #include <jvalidate/detail/anchor.h>
- #include <jvalidate/detail/on_block_exit.h>
- #include <jvalidate/detail/reference.h>
- #include <jvalidate/uri.h>
- namespace jvalidate::detail {
- class DynamicReferenceContext {
- private:
- std::deque<URI> sources_;
- std::map<Anchor, std::deque<std::optional<Reference>>> data_;
- public:
- OnBlockExit scope(URI const & source, std::map<Anchor, Reference> const & frame) {
- if (frame.empty() && data_.empty()) {
- return nullptr;
- }
- sources_.push_back(source);
- for (auto const & [k, v] : frame) {
- data_[k].push_back(data_[k].empty() ? v : data_[k].front());
- }
- for (auto & [k, stack] : data_) {
- if (not frame.contains(k)) {
- stack.push_back(std::nullopt);
- }
- while (stack.size() < sources_.size()) {
- stack.push_front(std::nullopt);
- }
- }
- return [this]() {
- sources_.pop_back();
- for (auto it = data_.begin(); it != data_.end();) {
- if (it->second.size() == 1) {
- it = data_.erase(it);
- } else {
- it->second.pop_back();
- ++it;
- }
- }
- };
- }
- bool contains(Anchor const & key) const { return data_.contains(key); }
- std::optional<Reference> lookup(URI const & source, Anchor const & key) const {
- if (auto it = data_.find(key); it != data_.end()) {
- return it->second.at(index_of(source));
- }
- return std::nullopt;
- }
- size_t index_of(URI const & source) const {
- for (size_t i = sources_.size(); i-- > 0;) {
- if (sources_[i] == source) {
- return i;
- }
- }
- return sources_.size() - 1;
- }
- bool empty() const { return data_.empty(); }
- };
- }
|