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 | |
52 | namespace DB |
53 | { |
54 | |
55 | namespace ErrorCodes |
56 | { |
57 | extern const int LOGICAL_ERROR; |
58 | } |
59 | |
60 | template <typename ... Types> |
61 | class Visitor; |
62 | |
63 | template <> |
64 | class Visitor<> |
65 | { |
66 | public: |
67 | using List = TypeList<>; |
68 | |
69 | virtual ~Visitor() = default; |
70 | }; |
71 | |
72 | template <typename Type> |
73 | class Visitor<Type> : public Visitor<> |
74 | { |
75 | public: |
76 | using List = TypeList<Type>; |
77 | |
78 | virtual void visit(Type &) = 0; |
79 | }; |
80 | |
81 | template <typename Type, typename ... Types> |
82 | class Visitor<Type, Types ...> : public Visitor<Types ...> |
83 | { |
84 | public: |
85 | using List = TypeList<Type, Types ...>; |
86 | using Visitor<Types ...>::visit; |
87 | |
88 | virtual void visit(Type &) = 0; |
89 | }; |
90 | |
91 | |
92 | template <typename Derived, typename VisitorBase, typename ... Types> |
93 | class VisitorImplHelper; |
94 | |
95 | template <typename Derived, typename VisitorBase> |
96 | class VisitorImplHelper<Derived, VisitorBase> : public VisitorBase |
97 | { |
98 | }; |
99 | |
100 | template <typename Derived, typename VisitorBase, typename Type> |
101 | class VisitorImplHelper<Derived, VisitorBase, Type> : public VisitorBase |
102 | { |
103 | public: |
104 | using VisitorBase::visit; |
105 | void visit(Type & value) override { static_cast<Derived *>(this)->visitImpl(value); } |
106 | |
107 | protected: |
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 | |
116 | template <typename Derived, typename VisitorBase, typename Type, typename ... Types> |
117 | class VisitorImplHelper<Derived, VisitorBase, Type, Types ...> |
118 | : public VisitorImplHelper<Derived, VisitorBase, Types ...> |
119 | { |
120 | public: |
121 | using VisitorImplHelper<Derived, VisitorBase, Types ...>::visit; |
122 | void visit(Type & value) override { static_cast<Derived *>(this)->visitImpl(value); } |
123 | |
124 | protected: |
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 | |
133 | template <typename Derived, typename VisitorBase> |
134 | class VisitorImpl : public |
135 | ApplyTypeListForClass< |
136 | VisitorImplHelper, |
137 | typename TypeListConcat< |
138 | TypeList<Derived, VisitorBase>, |
139 | typename VisitorBase::List |
140 | >::Type |
141 | >::Type |
142 | { |
143 | }; |
144 | |
145 | template <typename Derived, typename Base, typename Visitor> |
146 | class Visitable : public Base |
147 | { |
148 | public: |
149 | void accept(Visitor & visitor) override { visitor.visit(*static_cast<Derived *>(this)); } |
150 | }; |
151 | |
152 | } |
153 | |