1 //-----------------------------------------------------------------------------
2 // boost variant/detail/visitation_impl.hpp header file
3 // See http://www.boost.org for updates, documentation, and revision history.
4 //-----------------------------------------------------------------------------
5 //
6 // Copyright (c) 2003
7 // Eric Friedman
8 //
9 // Distributed under the Boost Software License, Version 1.0. (See
10 // accompanying file LICENSE_1_0.txt or copy at
11 // http://www.boost.org/LICENSE_1_0.txt)
12 
13 #ifndef BOOST_VARIANT_DETAIL_VISITATION_IMPL_HPP
14 #define BOOST_VARIANT_DETAIL_VISITATION_IMPL_HPP
15 
16 #include <boost/config.hpp>
17 
18 #include <boost/variant/detail/backup_holder.hpp>
19 #include <boost/variant/detail/cast_storage.hpp>
20 #include <boost/variant/detail/forced_return.hpp>
21 #include <boost/variant/detail/generic_result_type.hpp>
22 #include <boost/variant/variant_fwd.hpp> // for BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES
23 
24 #include <boost/mpl/eval_if.hpp>
25 #include <boost/mpl/bool.hpp>
26 #include <boost/mpl/identity.hpp>
27 #include <boost/mpl/int.hpp>
28 #include <boost/mpl/next.hpp>
29 #include <boost/mpl/deref.hpp>
30 #include <boost/mpl/or.hpp>
31 #include <boost/preprocessor/cat.hpp>
32 #include <boost/preprocessor/inc.hpp>
33 #include <boost/preprocessor/repeat.hpp>
34 #include <boost/type_traits/is_same.hpp>
35 #include <boost/type_traits/has_nothrow_copy.hpp>
36 #include <boost/type_traits/is_nothrow_move_constructible.hpp>
37 
38 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
39 # pragma warning (push)
40 # pragma warning (disable : 4702) //unreachable code
41 #endif
42 
43 ///////////////////////////////////////////////////////////////////////////////
44 // BOOST_VARIANT_VISITATION_UNROLLING_LIMIT
45 //
46 // Unrolls variant's visitation mechanism to reduce template instantiation
47 // and potentially increase runtime performance. (TODO: Investigate further.)
48 //
49 #if !defined(BOOST_VARIANT_VISITATION_UNROLLING_LIMIT)
50 
51 #ifndef BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES
52 #   include <boost/mpl/limits/list.hpp>
53 #   define BOOST_VARIANT_VISITATION_UNROLLING_LIMIT   \
54         BOOST_MPL_LIMIT_LIST_SIZE
55 #else
56 #   define BOOST_VARIANT_VISITATION_UNROLLING_LIMIT   \
57         BOOST_VARIANT_LIMIT_TYPES
58 #endif
59 
60 #endif
61 
62 namespace boost {
63 namespace detail { namespace variant {
64 
65 ///////////////////////////////////////////////////////////////////////////////
66 // (detail) class apply_visitor_unrolled
67 //
68 // Tag type indicates when visitation_impl is unrolled.
69 //
70 struct apply_visitor_unrolled {};
71 
72 ///////////////////////////////////////////////////////////////////////////////
73 // (detail) class template visitation_impl_step
74 //
75 // "Never ending" iterator range facilitates visitation_impl unrolling.
76 //
77 
78 
79 template <typename Iter, typename LastIter>
80 struct visitation_impl_step
81 {
82     typedef typename mpl::deref<Iter>::type type;
83 
84     typedef typename mpl::next<Iter>::type next_iter;
85     typedef visitation_impl_step<
86           next_iter, LastIter
87         > next;
88 };
89 
90 template <typename LastIter>
91 struct visitation_impl_step< LastIter,LastIter >
92 {
93     typedef apply_visitor_unrolled type;
94     typedef visitation_impl_step next;
95 };
96 
97 
98 ///////////////////////////////////////////////////////////////////////////////
99 // (detail) function template visitation_impl_invoke
100 //
101 // Invokes the given visitor on the specified type in the given storage.
102 //
103 
104 template <typename Visitor, typename VoidPtrCV, typename T>
105 inline
106     BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(typename Visitor::result_type)
visitation_impl_invoke_impl(int,Visitor & visitor,VoidPtrCV storage,T *,mpl::true_)107 visitation_impl_invoke_impl(
108       int, Visitor& visitor, VoidPtrCV storage, T*
109     , mpl::true_// never_uses_backup
110     )
111 {
112     return visitor.internal_visit(
113           cast_storage<T>(storage), 1L
114         );
115 }
116 
117 template <typename Visitor, typename VoidPtrCV, typename T>
118 inline
119     BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(typename Visitor::result_type)
visitation_impl_invoke_impl(int internal_which,Visitor & visitor,VoidPtrCV storage,T *,mpl::false_)120 visitation_impl_invoke_impl(
121       int internal_which, Visitor& visitor, VoidPtrCV storage, T*
122     , mpl::false_// never_uses_backup
123     )
124 {
125     if (internal_which >= 0)
126     {
127         return visitor.internal_visit(
128               cast_storage<T>(storage), 1L
129             );
130     }
131     else
132     {
133         return visitor.internal_visit(
134               cast_storage< backup_holder<T> >(storage), 1L
135             );
136     }
137 }
138 
139 template <typename Visitor, typename VoidPtrCV, typename T, typename NoBackupFlag>
140 inline
141     BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(typename Visitor::result_type)
visitation_impl_invoke(int internal_which,Visitor & visitor,VoidPtrCV storage,T * t,NoBackupFlag,int)142 visitation_impl_invoke(
143       int internal_which, Visitor& visitor, VoidPtrCV storage, T* t
144     , NoBackupFlag
145     , int
146     )
147 {
148     typedef typename mpl::or_<
149           NoBackupFlag
150         , is_nothrow_move_constructible<T>
151         , has_nothrow_copy<T>
152         >::type never_uses_backup;
153 
154     return (visitation_impl_invoke_impl)(
155           internal_which, visitor, storage, t
156         , never_uses_backup()
157         );
158 }
159 
160 template <typename Visitor, typename VoidPtrCV, typename NBF>
161 inline
162     BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(typename Visitor::result_type)
visitation_impl_invoke(int,Visitor &,VoidPtrCV,apply_visitor_unrolled *,NBF,long)163 visitation_impl_invoke(int, Visitor&, VoidPtrCV, apply_visitor_unrolled*, NBF, long)
164 {
165     // should never be here at runtime!
166     typedef typename Visitor::result_type result_type;
167     return ::boost::detail::variant::forced_return< result_type >();
168 }
169 
170 ///////////////////////////////////////////////////////////////////////////////
171 // (detail) function template visitation_impl
172 //
173 // Invokes the given visitor on the type in the given variant storage.
174 //
175 
176 template <
177       typename W, typename S
178     , typename Visitor, typename VPCV
179     , typename NBF
180     >
181 inline
182     BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(typename Visitor::result_type)
visitation_impl(int,int,Visitor &,VPCV,mpl::true_,NBF,W * =0,S * =0)183 visitation_impl(
184       int, int, Visitor&, VPCV
185     , mpl::true_ // is_apply_visitor_unrolled
186     , NBF, W* = 0, S* = 0
187     )
188 {
189     // should never be here at runtime!
190     typedef typename Visitor::result_type result_type;
191     return ::boost::detail::variant::forced_return< result_type >();
192 }
193 
194 template <
195       typename Which, typename step0
196     , typename Visitor, typename VoidPtrCV
197     , typename NoBackupFlag
198     >
199 inline
200     BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(typename Visitor::result_type)
visitation_impl(const int internal_which,const int logical_which,Visitor & visitor,VoidPtrCV storage,mpl::false_,NoBackupFlag no_backup_flag,Which * =0,step0 * =0)201 visitation_impl(
202       const int internal_which, const int logical_which
203     , Visitor& visitor, VoidPtrCV storage
204     , mpl::false_ // is_apply_visitor_unrolled
205     , NoBackupFlag no_backup_flag
206     , Which* = 0, step0* = 0
207     )
208 {
209     // Typedef apply_visitor_unrolled steps and associated types...
210 #   define BOOST_VARIANT_AUX_APPLY_VISITOR_STEP_TYPEDEF(z, N, _) \
211     typedef typename BOOST_PP_CAT(step,N)::type BOOST_PP_CAT(T,N); \
212     typedef typename BOOST_PP_CAT(step,N)::next \
213         BOOST_PP_CAT(step, BOOST_PP_INC(N)); \
214     /**/
215 
216     BOOST_PP_REPEAT(
217           BOOST_VARIANT_VISITATION_UNROLLING_LIMIT
218         , BOOST_VARIANT_AUX_APPLY_VISITOR_STEP_TYPEDEF
219         , _
220         )
221 
222 #   undef BOOST_VARIANT_AUX_APPLY_VISITOR_STEP_TYPEDEF
223 
224     // ...switch on the target which-index value...
225     switch (logical_which)
226     {
227 
228     // ...applying the appropriate case:
229 #   define BOOST_VARIANT_AUX_APPLY_VISITOR_STEP_CASE(z, N, _) \
230     case (Which::value + (N)): \
231         return (visitation_impl_invoke)( \
232               internal_which, visitor, storage \
233             , static_cast<BOOST_PP_CAT(T,N)*>(0) \
234             , no_backup_flag, 1L \
235             ); \
236     /**/
237 
238     BOOST_PP_REPEAT(
239           BOOST_VARIANT_VISITATION_UNROLLING_LIMIT
240         , BOOST_VARIANT_AUX_APPLY_VISITOR_STEP_CASE
241         , _
242         )
243 
244 #   undef BOOST_VARIANT_AUX_APPLY_VISITOR_STEP_CASE
245 
246     default: break;
247     }
248 
249     // If not handled in this iteration, continue unrolling:
250     typedef mpl::int_<
251           Which::value + (BOOST_VARIANT_VISITATION_UNROLLING_LIMIT)
252         > next_which;
253 
254     typedef BOOST_PP_CAT(step, BOOST_VARIANT_VISITATION_UNROLLING_LIMIT)
255         next_step;
256 
257     typedef typename next_step::type next_type;
258     typedef typename is_same< next_type,apply_visitor_unrolled >::type
259         is_apply_visitor_unrolled;
260 
261     return detail::variant::visitation_impl(
262           internal_which, logical_which
263         , visitor, storage
264         , is_apply_visitor_unrolled()
265         , no_backup_flag
266         , static_cast<next_which*>(0), static_cast<next_step*>(0)
267         );
268 }
269 
270 }} // namespace detail::variant
271 } // namespace boost
272 
273 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
274 # pragma warning(pop)
275 #endif
276 
277 #endif // BOOST_VARIANT_DETAIL_VISITATION_IMPL_HPP
278