1 //  Boost.Varaint
2 //  Contains multivisitors that are implemented via preprocessor magic
3 //
4 //  See http://www.boost.org for most recent version, including documentation.
5 //
6 //  Copyright Antony Polukhin, 2013-2014.
7 //
8 //  Distributed under the Boost
9 //  Software License, Version 1.0. (See accompanying file
10 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt).
11 
12 #ifndef BOOST_VARIANT_DETAIL_MULTIVISITORS_PREPROCESSOR_BASED_HPP
13 #define BOOST_VARIANT_DETAIL_MULTIVISITORS_PREPROCESSOR_BASED_HPP
14 
15 #if defined(_MSC_VER)
16 # pragma once
17 #endif
18 
19 #include <boost/variant.hpp>
20 #include <boost/bind.hpp>
21 
22 #include <boost/preprocessor/repetition.hpp>
23 #include <boost/preprocessor/punctuation/comma_if.hpp>
24 #include <boost/preprocessor/arithmetic/add.hpp>
25 #include <boost/preprocessor/arithmetic/sub.hpp>
26 
27 #ifndef BOOST_VARAINT_MAX_MULTIVIZITOR_PARAMS
28 #   define BOOST_VARAINT_MAX_MULTIVIZITOR_PARAMS 4
29 #endif
30 
31 namespace boost {
32 
33 namespace detail { namespace variant {
34 
35     template <class VisitorT, class Visitable1T, class Visitable2T>
36     struct two_variables_holder {
37     private:
38         VisitorT&       visitor_;
39         Visitable1T&    visitable1_;
40         Visitable2T&    visitable2_;
41 
42         // required to suppress warnings and ensure that we do not copy
43         // this visitor
44         two_variables_holder& operator=(const two_variables_holder&);
45 
46     public:
47         typedef BOOST_DEDUCED_TYPENAME VisitorT::result_type result_type;
48 
two_variables_holderboost::detail::variant::two_variables_holder49         explicit two_variables_holder(VisitorT& visitor, Visitable1T& visitable1, Visitable2T& visitable2) BOOST_NOEXCEPT
50             : visitor_(visitor)
51             , visitable1_(visitable1)
52             , visitable2_(visitable2)
53         {}
54 
55 #define BOOST_VARIANT_OPERATOR_BEG()                            \
56     return ::boost::apply_visitor(                              \
57     ::boost::bind<result_type>(boost::ref(visitor_), _1, _2     \
58     /**/
59 
60 #define BOOST_VARIANT_OPERATOR_END()                            \
61     ), visitable1_, visitable2_);                               \
62     /**/
63 
64 #define BOOST_VARANT_VISITORS_VARIABLES_PRINTER(z, n, data)     \
65     BOOST_PP_COMMA() boost::ref( BOOST_PP_CAT(vis, n) )         \
66     /**/
67 
68 #define BOOST_VARIANT_VISIT(z, n, data)                                                     \
69     template <BOOST_PP_ENUM_PARAMS(BOOST_PP_ADD(n, 1), class VisitableUnwrapped)>           \
70     result_type operator()(                                                                 \
71         BOOST_PP_ENUM_BINARY_PARAMS(BOOST_PP_ADD(n, 1), VisitableUnwrapped, & vis)          \
72     ) const                                                                                 \
73     {                                                                                       \
74         BOOST_VARIANT_OPERATOR_BEG()                                                        \
75         BOOST_PP_REPEAT(BOOST_PP_ADD(n, 1), BOOST_VARANT_VISITORS_VARIABLES_PRINTER, ~)     \
76         BOOST_VARIANT_OPERATOR_END()                                                        \
77     }                                                                                       \
78     /**/
79 
80 BOOST_PP_REPEAT( BOOST_PP_SUB(BOOST_VARAINT_MAX_MULTIVIZITOR_PARAMS, 2), BOOST_VARIANT_VISIT, ~)
81 #undef BOOST_VARIANT_OPERATOR_BEG
82 #undef BOOST_VARIANT_OPERATOR_END
83 #undef BOOST_VARANT_VISITORS_VARIABLES_PRINTER
84 #undef BOOST_VARIANT_VISIT
85 
86     };
87 
88     template <class VisitorT, class Visitable1T, class Visitable2T>
make_two_variables_holder(VisitorT & visitor,Visitable1T & visitable1,Visitable2T & visitable2)89     inline two_variables_holder<VisitorT, Visitable1T, Visitable2T> make_two_variables_holder(
90             VisitorT& visitor, Visitable1T& visitable1, Visitable2T& visitable2
91         ) BOOST_NOEXCEPT
92     {
93         return two_variables_holder<VisitorT, Visitable1T, Visitable2T>(visitor, visitable1, visitable2);
94     }
95 
96     template <class VisitorT, class Visitable1T, class Visitable2T>
make_two_variables_holder(const VisitorT & visitor,Visitable1T & visitable1,Visitable2T & visitable2)97     inline two_variables_holder<const VisitorT, Visitable1T, Visitable2T> make_two_variables_holder(
98             const VisitorT& visitor, Visitable1T& visitable1, Visitable2T& visitable2
99         ) BOOST_NOEXCEPT
100     {
101         return two_variables_holder<const VisitorT, Visitable1T, Visitable2T>(visitor, visitable1, visitable2);
102     }
103 
104 }} // namespace detail::variant
105 
106 #define BOOST_VARIANT_APPLY_VISITOR_BEG()                                               \
107     return ::boost::apply_visitor(                                                      \
108             boost::detail::variant::make_two_variables_holder(visitor, var0 , var1),    \
109             var2                                                                        \
110     /**/
111 
112 #define BOOST_VARIANT_APPLY_VISITOR_END()                       \
113     );                                                          \
114     /**/
115 
116 #define BOOST_VARANT_VISITORS_VARIABLES_PRINTER(z, n, data)     \
117     BOOST_PP_COMMA() BOOST_PP_CAT(var, BOOST_PP_ADD(n, 3))      \
118     /**/
119 
120 #define BOOST_VARIANT_VISIT(z, n, data)                                                                 \
121     template <class Visitor BOOST_PP_COMMA() BOOST_PP_ENUM_PARAMS(BOOST_PP_ADD(n, 3), class T)>         \
122     inline BOOST_DEDUCED_TYPENAME Visitor::result_type apply_visitor(                                   \
123         data BOOST_PP_COMMA() BOOST_PP_ENUM_BINARY_PARAMS(BOOST_PP_ADD(n, 3), T, & var)     \
124     )                                                                                                   \
125     {                                                                                                   \
126         BOOST_VARIANT_APPLY_VISITOR_BEG()                                                               \
127         BOOST_PP_REPEAT(n, BOOST_VARANT_VISITORS_VARIABLES_PRINTER, ~)                                  \
128         BOOST_VARIANT_APPLY_VISITOR_END()                                                               \
129     }                                                                                                   \
130     /**/
131 
132 BOOST_PP_REPEAT( BOOST_PP_SUB(BOOST_VARAINT_MAX_MULTIVIZITOR_PARAMS, 2), BOOST_VARIANT_VISIT, const Visitor& visitor)
133 BOOST_PP_REPEAT( BOOST_PP_SUB(BOOST_VARAINT_MAX_MULTIVIZITOR_PARAMS, 2), BOOST_VARIANT_VISIT, Visitor& visitor)
134 
135 #undef BOOST_VARIANT_APPLY_VISITOR_BEG
136 #undef BOOST_VARIANT_APPLY_VISITOR_END
137 #undef BOOST_VARANT_VISITORS_VARIABLES_PRINTER
138 #undef BOOST_VARIANT_VISIT
139 
140 } // namespace boost
141 
142 #endif // BOOST_VARIANT_DETAIL_MULTIVISITORS_PREPROCESSOR_BASED_HPP
143 
144