dynamic_reference_context.h 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. #pragma once
  2. #include <deque>
  3. #include <map>
  4. #include <optional>
  5. #include <jvalidate/detail/anchor.h>
  6. #include <jvalidate/detail/on_block_exit.h>
  7. #include <jvalidate/detail/reference.h>
  8. #include <jvalidate/uri.h>
  9. namespace jvalidate::detail {
  10. class DynamicReferenceContext {
  11. private:
  12. std::deque<URI> sources_;
  13. std::map<Anchor, std::deque<std::optional<Reference>>> data_;
  14. public:
  15. OnBlockExit scope(URI const & source, std::map<Anchor, Reference> const & frame) {
  16. if (frame.empty() && data_.empty()) {
  17. return nullptr;
  18. }
  19. sources_.push_back(source);
  20. for (auto const & [k, v] : frame) {
  21. data_[k].push_back(data_[k].empty() ? v : data_[k].front());
  22. }
  23. for (auto & [k, stack] : data_) {
  24. if (not frame.contains(k)) {
  25. stack.push_back(std::nullopt);
  26. }
  27. while (stack.size() < sources_.size()) {
  28. stack.push_front(std::nullopt);
  29. }
  30. }
  31. return [this]() {
  32. sources_.pop_back();
  33. for (auto it = data_.begin(); it != data_.end();) {
  34. if (it->second.size() == 1) {
  35. it = data_.erase(it);
  36. } else {
  37. it->second.pop_back();
  38. ++it;
  39. }
  40. }
  41. };
  42. }
  43. bool contains(Anchor const & key) const { return data_.contains(key); }
  44. std::optional<Reference> lookup(URI const & source, Anchor const & key) const {
  45. if (auto it = data_.find(key); it != data_.end()) {
  46. return it->second.at(index_of(source));
  47. }
  48. return std::nullopt;
  49. }
  50. size_t index_of(URI const & source) const {
  51. for (size_t i = sources_.size(); i-- > 0;) {
  52. if (sources_[i] == source) {
  53. return i;
  54. }
  55. }
  56. return sources_.size() - 1;
  57. }
  58. bool empty() const { return data_.empty(); }
  59. };
  60. }