extension.h 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. #pragma once
  2. #include <type_traits>
  3. #include <jvalidate/constraint/extension_constraint.h>
  4. #include <jvalidate/forward.h>
  5. #include <jvalidate/status.h>
  6. namespace jvalidate::extension {
  7. struct VisitorBase {
  8. virtual ~VisitorBase() = default;
  9. };
  10. template <typename E>
  11. concept Constraint = std::is_base_of_v<constraint::ExtensionConstraint::Impl, E>;
  12. namespace detail {
  13. template <Constraint E> struct TypedVisitor : VisitorBase {
  14. virtual Status visit(E const & cons) const = 0;
  15. };
  16. template <Constraint E, typename CRTP> struct TypedVisitorImpl : TypedVisitor<E> {
  17. Status visit(E const & cons) const final { static_cast<CRTP const *>(this)->dispatch(cons); }
  18. };
  19. }
  20. template <typename CRTP> struct ConstraintBase : constraint::ExtensionConstraint::Impl {
  21. Status visit(VisitorBase const & visitor) const final {
  22. return dynamic_cast<detail::TypedVisitor<CRTP> const &>(visitor).visit(
  23. static_cast<CRTP const &>(*this));
  24. }
  25. };
  26. template <typename CRTP, typename... Es> class Visitor {
  27. private:
  28. template <Adapter A, typename V> class Impl : public detail::TypedVisitorImpl<Es, Impl<A, V>>... {
  29. public:
  30. Impl(Visitor const * self, A const & document, V const & visitor)
  31. : self_(self), document_(document), visitor_(visitor) {}
  32. using detail::TypedVisitorImpl<Es, Impl>::visit...;
  33. template <Constraint E> Status dispatch(E const & cons) const {
  34. // static_assert(Visitable<CRTP, E, A, V>, "Must implement all visitation functions");
  35. static_cast<CRTP const *>(self_)->visit(cons, document_, visitor_);
  36. }
  37. private:
  38. Visitor const * self_;
  39. A const & document_;
  40. V const & visitor_;
  41. };
  42. public:
  43. template <Adapter A, typename V>
  44. Status operator()(constraint::ExtensionConstraint const & cons, A const & document,
  45. V const & visitor) const {
  46. return cons.pimpl->visit(Impl<A, V>{this, document, visitor});
  47. }
  48. };
  49. }