| 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_CXX11_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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 | |