| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475 |
- #pragma once
- #include <functional>
- #include <map>
- #include <optional>
- #include <jvalidate/detail/pointer.h>
- #include <jvalidate/detail/reference.h>
- namespace jvalidate::detail {
- class ReferenceCache {
- private:
- std::map<Reference, RootReference, std::greater<>> to_anchor_;
- std::map<RootReference, Reference, std::greater<>> to_absolute_;
- public:
- void emplace(URI const & root) {
- to_absolute_.emplace(root, root);
- to_anchor_.emplace(root, root);
- }
- Reference emplace(Reference const & absolute, RootReference const & canonical) {
- for (Reference where = absolute; not where.pointer().empty();) {
- // Recursively add all possible alternative paths that are equivalent to
- // this absolute path as valid mappings to this canonical one.
- auto it = to_absolute_.lower_bound(where.root());
- if (it == to_absolute_.end() || where.root() == it->second.root()) {
- break;
- }
- if (auto ptr = it->second.pointer(); where.pointer().starts_with(ptr)) {
- where = it->second / where.pointer().relative_to(ptr);
- to_anchor_.emplace(where, canonical);
- } else {
- break;
- }
- }
- to_anchor_.emplace(absolute, canonical);
- to_absolute_.emplace(canonical, absolute);
- return Reference(canonical);
- }
- Reference relative_to_nearest_anchor(Reference const & ref,
- bool for_parent_reference = false) const {
- auto it = for_parent_reference ? to_anchor_.upper_bound(ref) : to_anchor_.lower_bound(ref);
- if (it == to_anchor_.end()) {
- return ref;
- }
- auto const & [absolute, anchor] = *it;
- if (not ref.pointer().starts_with(absolute.pointer())) {
- return ref;
- }
- return Reference(anchor, ref.pointer().relative_to(absolute.pointer()));
- }
- URI actual_parent_uri(detail::Reference const & parent) const {
- // TODO(samjaffe): Think about this some more - there's something awkward here
- URI uri = relative_to_nearest_anchor(parent, true).uri();
- if (not uri.empty() || not parent.uri().empty()) {
- return uri;
- }
- if (auto it = to_anchor_.find(Reference()); it != to_anchor_.end()) {
- return it->second.uri();
- }
- return uri;
- }
- };
- }
|