1#pragma once
2
3#include <common/demangle.h>
4#include <Common/TypeList.h>
5#include <Common/Exception.h>
6
7/* Generic utils which are intended for visitor pattern implementation.
8 * The original purpose is to provide possibility to get concrete template specialisation for type in list.
9 *
10 * Usage:
11 * 1. Declare visitor interface base class for types T_1, ..., T_N:
12 * class MyVisitor : public Visitor<T_1, ..., T_N> {};
13 * 2. Declare visitor implementation base class using VisitorImpl:
14 * template <typename Derived>
15 * class MyVisitorImpl : public VisitorImpl<Derived, MyVisitor> {};
16 * 3. Add virtual function 'accept' to common base of T_1, ..., T_N:
17 * class T_Base
18 * {
19 * ...
20 * public:
21 * virtual void accept(MyVisitor &) { throw Exception("Accept not implemented"); }
22 * };
23 * 4. Declare base class for T_1, ..., T_N implementation:
24 * template <typename Derived>
25 * class T_Impl : public Visitable<Derived, T_Base, MyVisitor> {};
26 * 5. Implement 'accept' for each T_i:
27 * a) inherit from T_Impl:
28 * class T_i : public T_Impl<T_i> { ... };
29 * b) or in order to avoid ambiguity:
30 * class T_i
31 * {
32 * ...
33 * public:
34 * void accept(MyVisitor & visitor) override { visitor.visit(*this); }
35 * };
36 * 6. Implement concrete visitor with visitImpl template function:
37 * class MyConcreteVisitor : public MyVisitorImpl<MyConcreteVisitor>
38 * {
39 * ...
40 * public:
41 * template <typename T>
42 * void visitImpl(T & t) { ... }
43 * };
44 * 7. Now you can call concrete implementation for MyConcreteVisitor:
45 * MyConcreteVisitor visitor;
46 * T_Base * base;
47 * base->accept(visitor); /// call MyConcreteVisitor::visitImpl(T & t)
48 *
49 * TODO: Add ConstVisitor with 'visit(const Type &)' function in order to implement 'accept(...) const'.
50 */
51
52namespace DB
53{
54
55namespace ErrorCodes
56{
57 extern const int LOGICAL_ERROR;
58}
59
60template <typename ... Types>
61class Visitor;
62
63template <>
64class Visitor<>
65{
66public:
67 using List = TypeList<>;
68
69 virtual ~Visitor() = default;
70};
71
72template <typename Type>
73class Visitor<Type> : public Visitor<>
74{
75public:
76 using List = TypeList<Type>;
77
78 virtual void visit(Type &) = 0;
79};
80
81template <typename Type, typename ... Types>
82class Visitor<Type, Types ...> : public Visitor<Types ...>
83{
84public:
85 using List = TypeList<Type, Types ...>;
86 using Visitor<Types ...>::visit;
87
88 virtual void visit(Type &) = 0;
89};
90
91
92template <typename Derived, typename VisitorBase, typename ... Types>
93class VisitorImplHelper;
94
95template <typename Derived, typename VisitorBase>
96class VisitorImplHelper<Derived, VisitorBase> : public VisitorBase
97{
98};
99
100template <typename Derived, typename VisitorBase, typename Type>
101class VisitorImplHelper<Derived, VisitorBase, Type> : public VisitorBase
102{
103public:
104 using VisitorBase::visit;
105 void visit(Type & value) override { static_cast<Derived *>(this)->visitImpl(value); }
106
107protected:
108 template <typename T>
109 void visitImpl(Type &)
110 {
111 throw Exception("visitImpl(" + demangle(typeid(T).name()) + " &)" + " is not implemented for class"
112 + demangle(typeid(Derived).name()), ErrorCodes::LOGICAL_ERROR);
113 }
114};
115
116template <typename Derived, typename VisitorBase, typename Type, typename ... Types>
117class VisitorImplHelper<Derived, VisitorBase, Type, Types ...>
118 : public VisitorImplHelper<Derived, VisitorBase, Types ...>
119{
120public:
121 using VisitorImplHelper<Derived, VisitorBase, Types ...>::visit;
122 void visit(Type & value) override { static_cast<Derived *>(this)->visitImpl(value); }
123
124protected:
125 template <typename T>
126 void visitImpl(Type &)
127 {
128 throw Exception("visitImpl(" + demangle(typeid(T).name()) + " &)" + " is not implemented for class"
129 + demangle(typeid(Derived).name()), ErrorCodes::LOGICAL_ERROR);
130 }
131};
132
133template <typename Derived, typename VisitorBase>
134class VisitorImpl : public
135 ApplyTypeListForClass<
136 VisitorImplHelper,
137 typename TypeListConcat<
138 TypeList<Derived, VisitorBase>,
139 typename VisitorBase::List
140 >::Type
141 >::Type
142{
143};
144
145template <typename Derived, typename Base, typename Visitor>
146class Visitable : public Base
147{
148public:
149 void accept(Visitor & visitor) override { visitor.visit(*static_cast<Derived *>(this)); }
150};
151
152}
153