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/variant_fwd.hpp> // for BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES
22 
23 #include <boost/mpl/eval_if.hpp>
24 #include <boost/mpl/bool.hpp>
25 #include <boost/mpl/identity.hpp>
26 #include <boost/mpl/int.hpp>
27 #include <boost/mpl/next.hpp>
28 #include <boost/mpl/deref.hpp>
29 #include <boost/mpl/or.hpp>
30 #include <boost/preprocessor/cat.hpp>
31 #include <boost/preprocessor/inc.hpp>
32 #include <boost/preprocessor/repeat.hpp>
33 #include <boost/type_traits/is_same.hpp>
34 #include <boost/type_traits/has_nothrow_copy.hpp>
35 #include <boost/type_traits/is_nothrow_move_constructible.hpp>
36 
37 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
38 # pragma warning (push)
39 # pragma warning (disable : 4702) //unreachable code
40 #endif
41 
42 ///////////////////////////////////////////////////////////////////////////////
43 // BOOST_VARIANT_VISITATION_UNROLLING_LIMIT
44 //
45 // Unrolls variant's visitation mechanism to reduce template instantiation
46 // and potentially increase runtime performance. (TODO: Investigate further.)
47 //
48 #if !defined(BOOST_VARIANT_VISITATION_UNROLLING_LIMIT)
49 
50 #ifndef BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES
51 #   include <boost/mpl/limits/list.hpp>
52 #   define BOOST_VARIANT_VISITATION_UNROLLING_LIMIT   \
53         BOOST_MPL_LIMIT_LIST_SIZE
54 #else
55 #   define BOOST_VARIANT_VISITATION_UNROLLING_LIMIT   \
56         BOOST_VARIANT_LIMIT_TYPES
57 #endif
58 
59 #endif
60 
61 // Define a compiler generic null pointer value
62 #if defined(BOOST_NO_NULLPTR)
63 #define BOOST_VARIANT_NULL 0
64 #else
65 #define BOOST_VARIANT_NULL nullptr
66 #endif
67 
68 namespace boost {
69 namespace detail { namespace variant {
70 
71 ///////////////////////////////////////////////////////////////////////////////
72 // (detail) class apply_visitor_unrolled
73 //
74 // Tag type indicates when visitation_impl is unrolled.
75 //
76 struct apply_visitor_unrolled {};
77 
78 ///////////////////////////////////////////////////////////////////////////////
79 // (detail) class template visitation_impl_step
80 //
81 // "Never ending" iterator range facilitates visitation_impl unrolling.
82 //
83 
84 
85 template <typename Iter, typename LastIter>
86 struct visitation_impl_step
87 {
88     typedef typename mpl::deref<Iter>::type type;
89 
90     typedef typename mpl::next<Iter>::type next_iter;
91     typedef visitation_impl_step<
92           next_iter, LastIter
93         > next;
94 };
95 
96 template <typename LastIter>
97 struct visitation_impl_step< LastIter,LastIter >
98 {
99     typedef apply_visitor_unrolled type;
100     typedef visitation_impl_step next;
101 };
102 
103 
104 ///////////////////////////////////////////////////////////////////////////////
105 // (detail) function template visitation_impl_invoke
106 //
107 // Invokes the given visitor on the specified type in the given storage.
108 //
109 
110 template <typename Visitor, typename VoidPtrCV, typename T>
111 inline typename Visitor::result_type
visitation_impl_invoke_impl(int,Visitor & visitor,VoidPtrCV storage,T *,mpl::true_)112 visitation_impl_invoke_impl(
113       int, Visitor& visitor, VoidPtrCV storage, T*
114     , mpl::true_// never_uses_backup
115     )
116 {
117     return visitor.internal_visit(
118           cast_storage<T>(storage), 1L
119         );
120 }
121 
122 template <typename Visitor, typename VoidPtrCV, typename T>
123 inline typename Visitor::result_type
visitation_impl_invoke_impl(int internal_which,Visitor & visitor,VoidPtrCV storage,T *,mpl::false_)124 visitation_impl_invoke_impl(
125       int internal_which, Visitor& visitor, VoidPtrCV storage, T*
126     , mpl::false_// never_uses_backup
127     )
128 {
129     if (internal_which >= 0)
130     {
131         return visitor.internal_visit(
132               cast_storage<T>(storage), 1L
133             );
134     }
135     else
136     {
137         return visitor.internal_visit(
138               cast_storage< backup_holder<T> >(storage), 1L
139             );
140     }
141 }
142 
143 template <typename Visitor, typename VoidPtrCV, typename T, typename NoBackupFlag>
144 inline typename Visitor::result_type
visitation_impl_invoke(int internal_which,Visitor & visitor,VoidPtrCV storage,T * t,NoBackupFlag,int)145 visitation_impl_invoke(
146       int internal_which, Visitor& visitor, VoidPtrCV storage, T* t
147     , NoBackupFlag
148     , int
149     )
150 {
151     typedef typename mpl::or_<
152           NoBackupFlag
153         , is_nothrow_move_constructible<T>
154         , has_nothrow_copy<T>
155         >::type never_uses_backup;
156 
157     return (visitation_impl_invoke_impl)(
158           internal_which, visitor, storage, t
159         , never_uses_backup()
160         );
161 }
162 
163 template <typename Visitor, typename VoidPtrCV, typename NBF>
164 inline typename Visitor::result_type
visitation_impl_invoke(int,Visitor &,VoidPtrCV,apply_visitor_unrolled *,NBF,long)165 visitation_impl_invoke(int, Visitor&, VoidPtrCV, apply_visitor_unrolled*, NBF, long)
166 {
167     // should never be here at runtime!
168     typedef typename Visitor::result_type result_type;
169     return ::boost::detail::variant::forced_return< result_type >();
170 }
171 
172 ///////////////////////////////////////////////////////////////////////////////
173 // (detail) function template visitation_impl
174 //
175 // Invokes the given visitor on the type in the given variant storage.
176 //
177 
178 template <
179       typename W, typename S
180     , typename Visitor, typename VPCV
181     , typename NBF
182     >
183 inline typename Visitor::result_type
visitation_impl(int,int,Visitor &,VPCV,mpl::true_,NBF,W * =BOOST_VARIANT_NULL,S * =BOOST_VARIANT_NULL)184 visitation_impl(
185       int, int, Visitor&, VPCV
186     , mpl::true_ // is_apply_visitor_unrolled
187     , NBF, W* = BOOST_VARIANT_NULL, S* = BOOST_VARIANT_NULL
188     )
189 {
190     // should never be here at runtime!
191     typedef typename Visitor::result_type result_type;
192     return ::boost::detail::variant::forced_return< result_type >();
193 }
194 
195 template <
196       typename Which, typename step0
197     , typename Visitor, typename VoidPtrCV
198     , typename NoBackupFlag
199     >
200 BOOST_FORCEINLINE 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 * =BOOST_VARIANT_NULL,step0 * =BOOST_VARIANT_NULL)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* = BOOST_VARIANT_NULL, step0* = BOOST_VARIANT_NULL
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