context_stack.h 1.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950
  1. #pragma once
  2. #include <deque>
  3. #include <map>
  4. #include <optional>
  5. #include <jvalidate/detail/on_block_exit.h>
  6. namespace jvalidate::detail {
  7. template <typename Key, typename Value> class ContextStack {
  8. private:
  9. std::map<Key, std::deque<std::optional<Value>>> data_;
  10. public:
  11. OnBlockExit scope(std::map<Key, Value> const & frame) {
  12. if (frame.empty() && data_.empty()) {
  13. return nullptr;
  14. }
  15. for (auto const & [k, v] : frame) {
  16. data_[k].push_back(data_[k].empty() ? v : data_[k].front());
  17. }
  18. for (auto & [k, stack] : data_) {
  19. if (not frame.contains(k)) {
  20. stack.push_back(std::nullopt);
  21. }
  22. }
  23. return [this]() {
  24. for (auto it = data_.begin(); it != data_.end();) {
  25. if (it->second.size() == 1) {
  26. it = data_.erase(it);
  27. } else {
  28. it->second.pop_back();
  29. }
  30. }
  31. };
  32. }
  33. std::optional<Value> lookup(Key const & key) const {
  34. if (auto it = data_.find(key); it != data_.end()) {
  35. return it->second.back();
  36. }
  37. return std::nullopt;
  38. }
  39. bool empty() const { return data_.empty(); }
  40. };
  41. }