mirror of
				https://github.com/pocketpy/pocketpy
				synced 2025-10-26 14:30:17 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			196 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			196 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /***************************************************************************
 | |
| * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht          *
 | |
| * Copyright (c) QuantStack                                                 *
 | |
| *                                                                          *
 | |
| * Distributed under the terms of the BSD 3-Clause License.                 *
 | |
| *                                                                          *
 | |
| * The full license is in the file LICENSE, distributed with this software. *
 | |
| ****************************************************************************/
 | |
| 
 | |
| #ifndef XTL_VISITOR_HPP
 | |
| #define XTL_VISITOR_HPP
 | |
| 
 | |
| #include <stdexcept>
 | |
| #include "xmeta_utils.hpp"
 | |
| 
 | |
| namespace xtl
 | |
| {
 | |
|     // Loki's visitor ported to C++14
 | |
|     // Original implementation can be found at:
 | |
|     // https://github.com/snaewe/loki-lib/blob/master/include/loki/Visitor.h
 | |
| 
 | |
|     /****************
 | |
|      * base_visitor *
 | |
|      ****************/
 | |
| 
 | |
|     class base_visitor
 | |
|     {
 | |
|     public:
 | |
| 
 | |
|         virtual ~base_visitor() = default;
 | |
|     };
 | |
| 
 | |
|     /***********
 | |
|      * visitor *
 | |
|      ***********/
 | |
| 
 | |
|     template <class T, class R = void, bool is_const = true>
 | |
|     class visitor
 | |
|     {
 | |
|     public:
 | |
| 
 | |
|         using return_type = R;
 | |
|         using param_type = std::conditional_t<is_const, const T, T>;
 | |
| 
 | |
|         virtual ~visitor() = default;
 | |
| 
 | |
|         virtual return_type visit(param_type&) = 0;
 | |
|     };
 | |
| 
 | |
|     template <class R, bool is_const>
 | |
|     class visitor<mpl::vector<>, R, is_const>
 | |
|     {
 | |
|     };
 | |
| 
 | |
|     template <class R, bool is_const, class T, class... U>
 | |
|     class visitor<mpl::vector<T, U...>, R, is_const>
 | |
|         : public visitor<T, R, is_const>
 | |
|         , public visitor<mpl::vector<U...>, R, is_const>
 | |
|     {
 | |
|     };
 | |
| 
 | |
|     /**********************
 | |
|      * catch_all policies *
 | |
|      **********************/
 | |
| 
 | |
|     template <class R, class T>
 | |
|     struct default_catch_all
 | |
|     {
 | |
|         static R on_unknown_visitor(T&, base_visitor&)
 | |
|         {
 | |
|             return R();
 | |
|         }
 | |
|     };
 | |
| 
 | |
|     template <class R, class T>
 | |
|     struct throwing_catch_all
 | |
|     {
 | |
|         static R on_unknown_visitor(T&, base_visitor&)
 | |
|         {
 | |
|             XTL_THROW(std::runtime_error, "Unknown visited type");
 | |
|         }
 | |
|     };
 | |
| 
 | |
|     /******************
 | |
|      * base_visitable *
 | |
|      ******************/
 | |
| 
 | |
|     template
 | |
|     <
 | |
|         class R = void,
 | |
|         bool const_visitable = false,
 | |
|         template <class, class> class catch_all = default_catch_all
 | |
|     >
 | |
|     class base_visitable;
 | |
| 
 | |
|     template <class R, template <class, class> class catch_all>
 | |
|     class base_visitable<R, false, catch_all>
 | |
|     {
 | |
|     public:
 | |
| 
 | |
|         using return_type = R;
 | |
| 
 | |
|         virtual ~base_visitable() = default;
 | |
|         virtual return_type accept(base_visitor&) = 0;
 | |
| 
 | |
|     protected:
 | |
| 
 | |
|         template <class T>
 | |
|         static return_type accept_impl(T& visited, base_visitor& vis)
 | |
|         {
 | |
|             if (auto* p = dynamic_cast<visitor<T, R, false>*>(&vis))
 | |
|             {
 | |
|                 return p->visit(visited);
 | |
|             }
 | |
|             return catch_all<R, T>::on_unknown_visitor(visited, vis);
 | |
|         }
 | |
|     };
 | |
| 
 | |
|     template <class R, template <class, class> class catch_all>
 | |
|     class base_visitable<R, true, catch_all>
 | |
|     {
 | |
|     public:
 | |
| 
 | |
|         using return_type = R;
 | |
| 
 | |
|         virtual ~base_visitable() = default;
 | |
|         virtual return_type accept(base_visitor&) const = 0;
 | |
| 
 | |
|     protected:
 | |
| 
 | |
|         template <class T>
 | |
|         static return_type accept_impl(const T& visited, base_visitor& vis)
 | |
|         {
 | |
|             if (auto* p = dynamic_cast<visitor<T, R, true>*>(&vis))
 | |
|             {
 | |
|                 return p->visit(visited);
 | |
|             }
 | |
|             return catch_all<R, const T>::on_unknown_visitor(visited, vis);
 | |
|         }
 | |
|     };
 | |
| 
 | |
|     /************************
 | |
|      * XTL_DEFINE_VISITABLE *
 | |
|      ************************/
 | |
| 
 | |
| #define XTL_DEFINE_VISITABLE() \
 | |
|     return_type accept(::xtl::base_visitor& vis) override \
 | |
|     { return accept_impl(*this, vis); }
 | |
| 
 | |
| #define XTL_DEFINE_CONST_VISITABLE() \
 | |
|     return_type accept(::xtl::base_visitor& vis) const override \
 | |
|     { return accept_impl(*this, vis); }
 | |
| 
 | |
|     /******************
 | |
|      * cyclic_visitor *
 | |
|      ******************/
 | |
| 
 | |
|     template <class T, class R, bool is_const = true>
 | |
|     class cyclic_visitor;
 | |
| 
 | |
|     template <class R, bool is_const, class... T>
 | |
|     class cyclic_visitor<mpl::vector<T...>, R, is_const>
 | |
|         : public visitor<mpl::vector<T...>, R, is_const>
 | |
|     {
 | |
|     public:
 | |
| 
 | |
|         using return_type = R;
 | |
| 
 | |
|         template <class V>
 | |
|         return_type generic_visit(V& visited)
 | |
|         {
 | |
|             visitor<std::remove_const_t<V>, return_type, is_const>& sub_obj = *this;
 | |
|             return sub_obj.visit(visited);
 | |
|         }
 | |
|     };
 | |
| 
 | |
|     /*******************************
 | |
|      * XTL_DEFINE_CYCLIC_VISITABLE *
 | |
|      *******************************/
 | |
| 
 | |
| #define XTL_DEFINE_CYCLIC_VISITABLE(some_visitor)                     \
 | |
|     virtual some_visitor::return_type accept(some_visitor& vis)       \
 | |
|     {                                                                 \
 | |
|         return vis.generic_visit(*this);                              \
 | |
|     }
 | |
| 
 | |
| #define XTL_DEFINE_CONST_CYCLIC_VISITABLE(some_visitor)               \
 | |
|     virtual some_visitor::return_type accept(some_visitor& vis) const \
 | |
|     {                                                                 \
 | |
|         return vis.generic_visit(*this);                              \
 | |
|     }
 | |
| }
 | |
| 
 | |
| #endif
 | |
| 
 |