1 2 // Copyright (C) 2009-2012 Lorenzo Caminiti 3 // Distributed under the Boost Software License, Version 1.0 4 // (see accompanying file LICENSE_1_0.txt or a copy at 5 // http://www.boost.org/LICENSE_1_0.txt) 6 // Home at http://www.boost.org/libs/local_function 7 8 #ifndef BOOST_LOCAL_FUNCTION_AUX_NAME_HPP_ 9 #define BOOST_LOCAL_FUNCTION_AUX_NAME_HPP_ 10 11 #include <boost/local_function/config.hpp> 12 #include <boost/local_function/aux_/macro/decl.hpp> 13 #include <boost/local_function/aux_/macro/code_/functor.hpp> 14 #include <boost/local_function/detail/preprocessor/keyword/recursive.hpp> 15 #include <boost/local_function/detail/preprocessor/keyword/inline.hpp> 16 #include <boost/local_function/aux_/function.hpp> 17 #include <boost/local_function/aux_/symbol.hpp> 18 #include <boost/preprocessor/control/iif.hpp> 19 #include <boost/preprocessor/control/expr_iif.hpp> 20 #include <boost/preprocessor/logical/bitor.hpp> 21 #include <boost/preprocessor/tuple/eat.hpp> 22 23 // PRIVATE // 24 25 #define BOOST_LOCAL_FUNCTION_AUX_NAME_LOCAL_TYPE_(local_function_name) \ 26 BOOST_LOCAL_FUNCTION_AUX_SYMBOL( (local_type)(local_function_name) ) 27 28 #define BOOST_LOCAL_FUNCTION_AUX_NAME_INIT_RECURSION_FUNC_ \ 29 BOOST_LOCAL_FUNCTION_AUX_SYMBOL( (init_recursion) ) 30 31 #define BOOST_LOCAL_FUNCTION_AUX_NAME_RECURSIVE_FUNC_( \ 32 is_recursive, local_function_name) \ 33 BOOST_PP_IIF(is_recursive, \ 34 local_function_name \ 35 , \ 36 BOOST_LOCAL_FUNCTION_AUX_SYMBOL( (nonrecursive_local_function_name) ) \ 37 ) 38 39 #define BOOST_LOCAL_FUNCTION_AUX_NAME_END_LOCAL_FUNCTOR_(typename01, \ 40 local_function_name, is_recursive, \ 41 local_functor_name, nonlocal_functor_name) \ 42 /* FUNCTION macro expanded to: typedef class functor ## __LINE__ { ... */ \ 43 BOOST_PP_EXPR_IIF(is_recursive, \ 44 /* member var with function name for recursive calls; it cannot be */ \ 45 /* `const` because it is init after construction (because */ \ 46 /* constructor doesn't know local function name) */ \ 47 /* run-time: even when optimizing, recursive calls cannot be */ \ 48 /* optimized (i.e., they must be via the non-local functor) */ \ 49 /* because this cannot be a mem ref because its name is not known */ \ 50 /* by the constructor so it cannot be set by the mem init list */ \ 51 private: \ 52 BOOST_LOCAL_FUNCTION_AUX_CODE_FUNCTOR_TYPE \ 53 BOOST_LOCAL_FUNCTION_AUX_NAME_RECURSIVE_FUNC_(is_recursive, \ 54 local_function_name); \ 55 /* run-time: the `init_recursion()` function cannot be called */ \ 56 /* by the constructor to allow for compiler optimization */ \ 57 /* (inlining) so it must be public to be called (see below) */ \ 58 public: \ 59 inline void BOOST_LOCAL_FUNCTION_AUX_NAME_INIT_RECURSION_FUNC_( \ 60 BOOST_LOCAL_FUNCTION_AUX_CODE_FUNCTOR_TYPE& functor) { \ 61 local_function_name = functor; \ 62 } \ 63 ) \ 64 } BOOST_LOCAL_FUNCTION_AUX_NAME_LOCAL_TYPE_(local_function_name); \ 65 /* local functor can be passed as tparam only on C++11 (faster) */ \ 66 BOOST_LOCAL_FUNCTION_AUX_NAME_LOCAL_TYPE_(local_function_name) \ 67 local_functor_name(BOOST_LOCAL_FUNCTION_AUX_DECL_ARGS_VAR.value); \ 68 /* non-local functor can always be passed as tparam (but slower) */ \ 69 BOOST_PP_EXPR_IIF(typename01, typename) \ 70 BOOST_LOCAL_FUNCTION_AUX_NAME_LOCAL_TYPE_(local_function_name):: \ 71 BOOST_LOCAL_FUNCTION_AUX_CODE_FUNCTOR_TYPE \ 72 nonlocal_functor_name; /* functor variable */ \ 73 /* the order of the following 2 function calls cannot be changed */ \ 74 /* because init_recursion uses the local_functor so the local_functor */ \ 75 /* must be init first */ \ 76 local_functor_name.BOOST_LOCAL_FUNCTION_AUX_FUNCTION_INIT_CALL_FUNC( \ 77 &local_functor_name, nonlocal_functor_name); \ 78 BOOST_PP_EXPR_IIF(is_recursive, \ 79 /* init recursion causes MSVC to not optimize local function not */ \ 80 /* even when local functor is used as template parameter so no */ \ 81 /* recursion unless all inlining optimizations are specified off */ \ 82 local_functor_name.BOOST_LOCAL_FUNCTION_AUX_NAME_INIT_RECURSION_FUNC_( \ 83 nonlocal_functor_name); \ 84 ) 85 86 #define BOOST_LOCAL_FUNCTION_AUX_NAME_FUNCTOR_(local_function_name) \ 87 BOOST_LOCAL_FUNCTION_AUX_SYMBOL( (local_function_name) ) 88 89 // This can always be passed as a template parameters (on all compilers). 90 // However, it is slower because it cannot be inlined. 91 // Passed at tparam: Yes (on all C++). Inlineable: No. Recursive: No. 92 #define BOOST_LOCAL_FUNCTION_AUX_NAME_(typename01, local_function_name) \ 93 BOOST_LOCAL_FUNCTION_AUX_NAME_END_LOCAL_FUNCTOR_(typename01, \ 94 local_function_name, \ 95 /* local function is not recursive (because recursion and its */ \ 96 /* initialization cannot be inlined even on C++11, */ \ 97 /* so this allows optimization at least on C++11) */ \ 98 0 /* not recursive */ , \ 99 /* local functor */ \ 100 BOOST_LOCAL_FUNCTION_AUX_NAME_FUNCTOR_(local_function_name), \ 101 /* local function declared as non-local functor -- but it can */ \ 102 /* be inlined only by C++11 and it cannot be recursive */ \ 103 local_function_name) 104 105 // This is faster on some compilers but not all (e.g., it is faster on GCC 106 // because its optimization inlines it but not on MSVC). However, it cannot be 107 // passed as a template parameter on non C++11 compilers. 108 // Passed at tparam: Only on C++11. Inlineable: Yes. Recursive: No. 109 #define BOOST_LOCAL_FUNCTION_AUX_NAME_INLINE_(typename01, local_function_name) \ 110 BOOST_LOCAL_FUNCTION_AUX_NAME_END_LOCAL_FUNCTOR_(typename01, \ 111 local_function_name, \ 112 /* inlined local function is never recursive (because recursion */ \ 113 /* and its initialization cannot be inlined)*/ \ 114 0 /* not recursive */ , \ 115 /* inlined local function declared as local functor (maybe */ \ 116 /* inlined even by non C++11 -- but it can be passed as */ \ 117 /* template parameter only on C++11 */ \ 118 local_function_name, \ 119 /* non-local functor */ \ 120 BOOST_LOCAL_FUNCTION_AUX_NAME_FUNCTOR_(local_function_name)) 121 122 // This is slower on all compilers (C++11 and non) because recursion and its 123 // initialization can never be inlined. 124 // Passed at tparam: Yes. Inlineable: No. Recursive: Yes. 125 #define BOOST_LOCAL_FUNCTION_AUX_NAME_RECURSIVE_( \ 126 typename01, local_function_name) \ 127 BOOST_LOCAL_FUNCTION_AUX_NAME_END_LOCAL_FUNCTOR_(typename01, \ 128 local_function_name, \ 129 /* recursive local function -- but it cannot be inlined */ \ 130 1 /* recursive */ , \ 131 /* local functor */ \ 132 BOOST_LOCAL_FUNCTION_AUX_NAME_FUNCTOR_(local_function_name), \ 133 /* local function declared as non-local functor -- but it can */ \ 134 /* be inlined only by C++11 */ \ 135 local_function_name) 136 137 // Inlined local functions are specified by `..._NAME(inline name)`. 138 // They have more chances to be inlined for faster run-times by some compilers 139 // (for example by GCC but not by MSVC). C++11 compilers can always inline 140 // local functions even if they are not explicitly specified inline. 141 #define BOOST_LOCAL_FUNCTION_AUX_NAME_PARSE_INLINE_( \ 142 typename01, qualified_name) \ 143 BOOST_PP_IIF(BOOST_PP_BITOR( \ 144 BOOST_LOCAL_FUNCTION_CONFIG_LOCALS_AS_TPARAMS, \ 145 BOOST_LOCAL_FUNCTION_DETAIL_PP_KEYWORD_IS_INLINE_FRONT( \ 146 qualified_name)), \ 147 /* on C++11 always use inlining because compilers might optimize */ \ 148 /* it to be faster and it can also be passed as tparam */ \ 149 BOOST_LOCAL_FUNCTION_AUX_NAME_INLINE_ \ 150 , \ 151 /* on non C++11 don't use liniling unless explicitly specified by */ \ 152 /* programmers `inline name` the inlined local function cannot be */ \ 153 /* passed as tparam */ \ 154 BOOST_LOCAL_FUNCTION_AUX_NAME_ \ 155 )(typename01, BOOST_LOCAL_FUNCTION_DETAIL_PP_KEYWORD_INLINE_REMOVE_FRONT( \ 156 qualified_name)) 157 158 // Expand to 1 iff `recursive name` or `recursive inline name` or 159 // `inline recursive name`. 160 #define BOOST_LOCAL_FUNCTION_AUX_NAME_IS_RECURSIVE_(qualified_name) \ 161 BOOST_LOCAL_FUNCTION_DETAIL_PP_KEYWORD_IS_RECURSIVE_FRONT( \ 162 BOOST_LOCAL_FUNCTION_DETAIL_PP_KEYWORD_INLINE_REMOVE_FRONT( \ 163 qualified_name \ 164 )) 165 166 // Revmoes `recursive`, `inline recursive`, and `recursive inline` from front. 167 #define BOOST_LOCAL_FUNCTION_AUX_NAME_REMOVE_RECURSIVE_AND_INLINE_( \ 168 qualified_name) \ 169 BOOST_LOCAL_FUNCTION_DETAIL_PP_KEYWORD_RECURSIVE_REMOVE_FRONT( \ 170 BOOST_LOCAL_FUNCTION_DETAIL_PP_KEYWORD_INLINE_REMOVE_FRONT( \ 171 BOOST_LOCAL_FUNCTION_DETAIL_PP_KEYWORD_RECURSIVE_REMOVE_FRONT( \ 172 qualified_name \ 173 ))) 174 175 #define BOOST_LOCAL_FUNCTION_AUX_NAME_RECURSIVE_REMOVE_(qualified_name) \ 176 BOOST_PP_IIF(BOOST_LOCAL_FUNCTION_AUX_NAME_IS_RECURSIVE_(qualified_name), \ 177 BOOST_LOCAL_FUNCTION_AUX_NAME_REMOVE_RECURSIVE_AND_INLINE_ \ 178 , \ 179 qualified_name /* might be `name` or `inline name` */ \ 180 BOOST_PP_TUPLE_EAT(1) \ 181 )(qualified_name) 182 183 // Recursive local function are specified by `..._NAME(recursive name)`. 184 // They can never be inlined for faster run-time (not even by C++11 compilers). 185 #define BOOST_LOCAL_FUNCTION_AUX_NAME_PARSE_RECURSIVE_( \ 186 typename01, qualified_name) \ 187 BOOST_PP_IIF(BOOST_LOCAL_FUNCTION_AUX_NAME_IS_RECURSIVE_(qualified_name), \ 188 /* recursion can never be inlined (not even on C++11) */ \ 189 BOOST_LOCAL_FUNCTION_AUX_NAME_RECURSIVE_ \ 190 , \ 191 BOOST_LOCAL_FUNCTION_AUX_NAME_PARSE_INLINE_ \ 192 )(typename01, \ 193 BOOST_LOCAL_FUNCTION_AUX_NAME_RECURSIVE_REMOVE_(qualified_name)) 194 195 // PUBLIC // 196 197 #define BOOST_LOCAL_FUNCTION_AUX_NAME(typename01, qualified_name) \ 198 BOOST_LOCAL_FUNCTION_AUX_NAME_PARSE_RECURSIVE_(typename01, qualified_name) 199 200 #endif // #include guard 201 202