ClickHouse/src/Common/Visitor.h
Alexander Tokmakov 70d1adfe4b
Better formatting for exception messages (#45449)
* save format string for NetException

* format exceptions

* format exceptions 2

* format exceptions 3

* format exceptions 4

* format exceptions 5

* format exceptions 6

* fix

* format exceptions 7

* format exceptions 8

* Update MergeTreeIndexGin.cpp

* Update AggregateFunctionMap.cpp

* Update AggregateFunctionMap.cpp

* fix
2023-01-24 00:13:58 +03:00

169 lines
4.5 KiB
C++

#pragma once
#include <base/demangle.h>
#include <base/TypeList.h>
#include <Common/Exception.h>
#include <typeinfo>
/* Generic utils which are intended for visitor pattern implementation.
* The original purpose is to provide possibility to get concrete template specialisation for type in list.
*
* Usage:
* 1. Declare visitor interface base class for types T_1, ..., T_N:
* class MyVisitor : public Visitor<T_1, ..., T_N> {};
* 2. Declare visitor implementation base class using VisitorImpl:
* template <typename Derived>
* class MyVisitorImpl : public VisitorImpl<Derived, MyVisitor> {};
* 3. Add virtual function 'accept' to common base of T_1, ..., T_N:
* class T_Base
* {
* ...
* public:
* virtual void accept(MyVisitor &) { throw Exception("Accept not implemented"); }
* };
* 4. Declare base class for T_1, ..., T_N implementation:
* template <typename Derived>
* class T_Impl : public Visitable<Derived, T_Base, MyVisitor> {};
* 5. Implement 'accept' for each T_i:
* a) inherit from T_Impl:
* class T_i : public T_Impl<T_i> { ... };
* b) or in order to avoid ambiguity:
* class T_i
* {
* ...
* public:
* void accept(MyVisitor & visitor) override { visitor.visit(*this); }
* };
* 6. Implement concrete visitor with visitImpl template function:
* class MyConcreteVisitor : public MyVisitorImpl<MyConcreteVisitor>
* {
* ...
* public:
* template <typename T>
* void visitImpl(T & t) { ... }
* };
* 7. Now you can call concrete implementation for MyConcreteVisitor:
* MyConcreteVisitor visitor;
* T_Base * base;
* base->accept(visitor); /// call MyConcreteVisitor::visitImpl(T & t)
*
* TODO: Add ConstVisitor with 'visit(const Type &)' function in order to implement 'accept(...) const'.
*/
namespace DB
{
namespace ErrorCodes
{
extern const int LOGICAL_ERROR;
}
template <typename ... Types>
class Visitor;
template <>
class Visitor<>
{
public:
using List = TypeList<>;
protected:
~Visitor() = default;
};
template <typename Type>
class Visitor<Type> : public Visitor<>
{
public:
using List = TypeList<Type>;
virtual void visit(Type &) = 0;
protected:
~Visitor() = default;
};
template <typename Type, typename ... Types>
class Visitor<Type, Types ...> : public Visitor<Types ...>
{
public:
using List = TypeList<Type, Types ...>;
using Visitor<Types ...>::visit;
virtual void visit(Type &) = 0;
protected:
~Visitor() = default;
};
template <typename Derived, typename VisitorBase, typename ... Types>
class VisitorImplHelper;
template <typename Derived, typename VisitorBase>
class VisitorImplHelper<Derived, VisitorBase> : public VisitorBase
{
protected:
~VisitorImplHelper() = default;
};
template <typename Derived, typename VisitorBase, typename Type>
class VisitorImplHelper<Derived, VisitorBase, Type> : public VisitorBase
{
public:
using VisitorBase::visit;
void visit(Type & value) override { static_cast<Derived *>(this)->visitImpl(value); }
protected:
template <typename T>
void visitImpl(Type &)
{
throw Exception(ErrorCodes::LOGICAL_ERROR, "visitImpl({} &) is not implemented for class{}",
demangle(typeid(T).name()), demangle(typeid(Derived).name()));
}
~VisitorImplHelper() = default;
};
template <typename Derived, typename VisitorBase, typename Type, typename ... Types>
class VisitorImplHelper<Derived, VisitorBase, Type, Types ...>
: public VisitorImplHelper<Derived, VisitorBase, Types ...>
{
public:
using VisitorImplHelper<Derived, VisitorBase, Types ...>::visit;
void visit(Type & value) override { static_cast<Derived *>(this)->visitImpl(value); }
protected:
template <typename T>
void visitImpl(Type &)
{
throw Exception(ErrorCodes::LOGICAL_ERROR, "visitImpl({} &) is not implemented for class{}",
demangle(typeid(T).name()), demangle(typeid(Derived).name()));
}
~VisitorImplHelper() = default;
};
template <typename Derived, typename VisitorBase>
class VisitorImpl : public
TypeListChangeRoot<
VisitorImplHelper,
TypeListConcat<
TypeList<Derived, VisitorBase>,
typename VisitorBase::List
>
>
{
protected:
~VisitorImpl() = default;
};
template <typename Derived, typename Base, typename Visitor>
class Visitable : public Base
{
public:
void accept(Visitor & visitor) override { visitor.visit(*static_cast<Derived *>(this)); }
};
}