summaryrefslogtreecommitdiff
path: root/boost/variant/detail/multivisitors_preprocessor_based.hpp
blob: aa85a55680f69d5b4569c3be23df11c2238f6d29 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
//  Boost.Varaint
//  Contains multivisitors that are implemented via preprocessor magic
//
//  See http://www.boost.org for most recent version, including documentation.
//
//  Copyright Antony Polukhin, 2013-2014.
//
//  Distributed under the Boost
//  Software License, Version 1.0. (See accompanying file
//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt).

#ifndef BOOST_VARIANT_DETAIL_MULTIVISITORS_PREPROCESSOR_BASED_HPP
#define BOOST_VARIANT_DETAIL_MULTIVISITORS_PREPROCESSOR_BASED_HPP

#if defined(_MSC_VER)
# pragma once
#endif

#include <boost/variant.hpp>
#include <boost/bind.hpp>

#include <boost/preprocessor/repetition.hpp>
#include <boost/preprocessor/punctuation/comma_if.hpp>
#include <boost/preprocessor/arithmetic/add.hpp>
#include <boost/preprocessor/arithmetic/sub.hpp>

#ifndef BOOST_VARAINT_MAX_MULTIVIZITOR_PARAMS
#   define BOOST_VARAINT_MAX_MULTIVIZITOR_PARAMS 4
#endif

namespace boost { 

namespace detail { namespace variant {

    template <class VisitorT, class Visitable1T, class Visitable2T>
    struct two_variables_holder {
    private:
        VisitorT&       visitor_;
        Visitable1T&    visitable1_;
        Visitable2T&    visitable2_;

        // required to suppress warnings and ensure that we do not copy
        // this visitor
        two_variables_holder& operator=(const two_variables_holder&);

    public:
        typedef BOOST_DEDUCED_TYPENAME VisitorT::result_type result_type;

        explicit two_variables_holder(VisitorT& visitor, Visitable1T& visitable1, Visitable2T& visitable2) BOOST_NOEXCEPT 
            : visitor_(visitor)
            , visitable1_(visitable1)
            , visitable2_(visitable2)
        {}

#define BOOST_VARIANT_OPERATOR_BEG()                            \
    return ::boost::apply_visitor(                              \
    ::boost::bind<result_type>(boost::ref(visitor_), _1, _2     \
    /**/

#define BOOST_VARIANT_OPERATOR_END()                            \
    ), visitable1_, visitable2_);                               \
    /**/

#define BOOST_VARANT_VISITORS_VARIABLES_PRINTER(z, n, data)     \
    BOOST_PP_COMMA() boost::ref( BOOST_PP_CAT(vis, n) )         \
    /**/

#define BOOST_VARIANT_VISIT(z, n, data)                                                     \
    template <BOOST_PP_ENUM_PARAMS(BOOST_PP_ADD(n, 1), class VisitableUnwrapped)>           \
    result_type operator()(                                                                 \
        BOOST_PP_ENUM_BINARY_PARAMS(BOOST_PP_ADD(n, 1), VisitableUnwrapped, & vis)          \
    ) const                                                                                 \
    {                                                                                       \
        BOOST_VARIANT_OPERATOR_BEG()                                                        \
        BOOST_PP_REPEAT(BOOST_PP_ADD(n, 1), BOOST_VARANT_VISITORS_VARIABLES_PRINTER, ~)     \
        BOOST_VARIANT_OPERATOR_END()                                                        \
    }                                                                                       \
    /**/

BOOST_PP_REPEAT( BOOST_PP_SUB(BOOST_VARAINT_MAX_MULTIVIZITOR_PARAMS, 2), BOOST_VARIANT_VISIT, ~)
#undef BOOST_VARIANT_OPERATOR_BEG
#undef BOOST_VARIANT_OPERATOR_END
#undef BOOST_VARANT_VISITORS_VARIABLES_PRINTER
#undef BOOST_VARIANT_VISIT

    };

    template <class VisitorT, class Visitable1T, class Visitable2T>
    inline two_variables_holder<VisitorT, Visitable1T, Visitable2T> make_two_variables_holder(
            VisitorT& visitor, Visitable1T& visitable1, Visitable2T& visitable2
        ) BOOST_NOEXCEPT
    {
        return two_variables_holder<VisitorT, Visitable1T, Visitable2T>(visitor, visitable1, visitable2);
    }

    template <class VisitorT, class Visitable1T, class Visitable2T>
    inline two_variables_holder<const VisitorT, Visitable1T, Visitable2T> make_two_variables_holder(
            const VisitorT& visitor, Visitable1T& visitable1, Visitable2T& visitable2
        ) BOOST_NOEXCEPT
    {
        return two_variables_holder<const VisitorT, Visitable1T, Visitable2T>(visitor, visitable1, visitable2);
    }

}} // namespace detail::variant

#define BOOST_VARIANT_APPLY_VISITOR_BEG()                                               \
    return ::boost::apply_visitor(                                                      \
            boost::detail::variant::make_two_variables_holder(visitor, var0 , var1),    \
            var2                                                                        \
    /**/

#define BOOST_VARIANT_APPLY_VISITOR_END()                       \
    );                                                          \
    /**/

#define BOOST_VARANT_VISITORS_VARIABLES_PRINTER(z, n, data)     \
    BOOST_PP_COMMA() BOOST_PP_CAT(var, BOOST_PP_ADD(n, 3))      \
    /**/

#define BOOST_VARIANT_VISIT(z, n, data)                                                                 \
    template <class Visitor BOOST_PP_COMMA() BOOST_PP_ENUM_PARAMS(BOOST_PP_ADD(n, 3), class T)>         \
    inline BOOST_DEDUCED_TYPENAME Visitor::result_type apply_visitor(                                   \
        data BOOST_PP_COMMA() BOOST_PP_ENUM_BINARY_PARAMS(BOOST_PP_ADD(n, 3), T, & var)     \
    )                                                                                                   \
    {                                                                                                   \
        BOOST_VARIANT_APPLY_VISITOR_BEG()                                                               \
        BOOST_PP_REPEAT(n, BOOST_VARANT_VISITORS_VARIABLES_PRINTER, ~)                                  \
        BOOST_VARIANT_APPLY_VISITOR_END()                                                               \
    }                                                                                                   \
    /**/

BOOST_PP_REPEAT( BOOST_PP_SUB(BOOST_VARAINT_MAX_MULTIVIZITOR_PARAMS, 2), BOOST_VARIANT_VISIT, const Visitor& visitor)
BOOST_PP_REPEAT( BOOST_PP_SUB(BOOST_VARAINT_MAX_MULTIVIZITOR_PARAMS, 2), BOOST_VARIANT_VISIT, Visitor& visitor)

#undef BOOST_VARIANT_APPLY_VISITOR_BEG
#undef BOOST_VARIANT_APPLY_VISITOR_END
#undef BOOST_VARANT_VISITORS_VARIABLES_PRINTER
#undef BOOST_VARIANT_VISIT
    
} // namespace boost

#endif // BOOST_VARIANT_DETAIL_MULTIVISITORS_PREPROCESSOR_BASED_HPP