extension.h 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  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 {
  18. return static_cast<CRTP const *>(this)->dispatch(cons);
  19. }
  20. };
  21. }
  22. template <typename CRTP> struct ConstraintBase : constraint::ExtensionConstraint::Impl {
  23. Status visit(VisitorBase const & visitor) const final {
  24. return dynamic_cast<detail::TypedVisitor<CRTP> const &>(visitor).visit(
  25. static_cast<CRTP const &>(*this));
  26. }
  27. };
  28. template <typename CRTP, typename... Es> class Visitor {
  29. private:
  30. template <Adapter A, typename V> class Impl : public detail::TypedVisitorImpl<Es, Impl<A, V>>... {
  31. public:
  32. Impl(Visitor const * self, A const & document, V const & visitor)
  33. : self_(self), document_(document), visitor_(visitor) {}
  34. using detail::TypedVisitorImpl<Es, Impl>::visit...;
  35. template <Constraint E> Status dispatch(E const & cons) const {
  36. // static_assert(Visitable<CRTP, E, A, V>, "Must implement all visitation functions");
  37. return static_cast<CRTP const *>(self_)->visit(cons, document_, visitor_);
  38. }
  39. private:
  40. Visitor const * self_;
  41. A const & document_;
  42. V const & visitor_;
  43. };
  44. public:
  45. template <Adapter A, typename V>
  46. Status operator()(constraint::ExtensionConstraint const & cons, A const & document,
  47. V const & visitor) const {
  48. return cons.pimpl->visit(Impl<A, V>{this, document, visitor});
  49. }
  50. };
  51. }