reference_cache.h 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. #pragma once
  2. #include <functional>
  3. #include <map>
  4. #include <optional>
  5. #include <jvalidate/detail/pointer.h>
  6. #include <jvalidate/detail/reference.h>
  7. namespace jvalidate::detail {
  8. class ReferenceCache {
  9. private:
  10. std::map<Reference, RootReference, std::greater<>> to_anchor_;
  11. std::map<RootReference, Reference, std::greater<>> to_absolute_;
  12. public:
  13. void emplace(URI const & root) {
  14. to_absolute_.emplace(root, root);
  15. to_anchor_.emplace(root, root);
  16. }
  17. Reference emplace(Reference const & absolute, RootReference const & canonical) {
  18. for (Reference where = absolute; not where.pointer().empty();) {
  19. // Recursively add all possible alternative paths that are equivalent to
  20. // this absolute path as valid mappings to this canonical one.
  21. auto it = to_absolute_.lower_bound(where.root());
  22. if (it == to_absolute_.end() || where.root() == it->second.root()) {
  23. break;
  24. }
  25. if (auto ptr = it->second.pointer(); where.pointer().starts_with(ptr)) {
  26. where = it->second / where.pointer().relative_to(ptr);
  27. to_anchor_.emplace(where, canonical);
  28. } else {
  29. break;
  30. }
  31. }
  32. to_anchor_.emplace(absolute, canonical);
  33. // TODO: Validate uniqueness?
  34. to_absolute_.emplace(canonical, absolute);
  35. return Reference(canonical);
  36. }
  37. Reference relative_to_nearest_anchor(Reference const & ref,
  38. bool for_parent_reference = false) const {
  39. auto it = for_parent_reference ? to_anchor_.upper_bound(ref) : to_anchor_.lower_bound(ref);
  40. if (it == to_anchor_.end()) {
  41. return ref;
  42. }
  43. auto const & [absolute, anchor] = *it;
  44. if (not ref.pointer().starts_with(absolute.pointer())) {
  45. return ref;
  46. }
  47. return Reference(anchor, ref.pointer().relative_to(absolute.pointer()));
  48. }
  49. URI actual_parent_uri(detail::Reference const & parent) const {
  50. // TODO(samjaffe): Think about this some more - there's something awkward here
  51. URI uri = relative_to_nearest_anchor(parent, true).uri();
  52. if (not uri.empty() || not parent.uri().empty()) {
  53. return uri;
  54. }
  55. if (auto it = to_anchor_.find(Reference()); it != to_anchor_.end()) {
  56. return it->second.uri();
  57. }
  58. return uri;
  59. }
  60. };
  61. }