Chris@16: Chris@16: // Copyright (C) 2009-2012 Lorenzo Caminiti Chris@16: // Distributed under the Boost Software License, Version 1.0 Chris@16: // (see accompanying file LICENSE_1_0.txt or a copy at Chris@16: // http://www.boost.org/LICENSE_1_0.txt) Chris@16: // Home at http://www.boost.org/libs/local_function Chris@16: Chris@16: #ifndef BOOST_LOCAL_FUNCTION_AUX_NAME_HPP_ Chris@16: #define BOOST_LOCAL_FUNCTION_AUX_NAME_HPP_ Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: // PRIVATE // Chris@16: Chris@16: #define BOOST_LOCAL_FUNCTION_AUX_NAME_LOCAL_TYPE_(local_function_name) \ Chris@16: BOOST_LOCAL_FUNCTION_AUX_SYMBOL( (local_type)(local_function_name) ) Chris@16: Chris@16: #define BOOST_LOCAL_FUNCTION_AUX_NAME_INIT_RECURSION_FUNC_ \ Chris@16: BOOST_LOCAL_FUNCTION_AUX_SYMBOL( (init_recursion) ) Chris@16: Chris@16: #define BOOST_LOCAL_FUNCTION_AUX_NAME_RECURSIVE_FUNC_( \ Chris@16: is_recursive, local_function_name) \ Chris@16: BOOST_PP_IIF(is_recursive, \ Chris@16: local_function_name \ Chris@16: , \ Chris@16: BOOST_LOCAL_FUNCTION_AUX_SYMBOL( (nonrecursive_local_function_name) ) \ Chris@16: ) Chris@16: Chris@16: #define BOOST_LOCAL_FUNCTION_AUX_NAME_END_LOCAL_FUNCTOR_(typename01, \ Chris@16: local_function_name, is_recursive, \ Chris@16: local_functor_name, nonlocal_functor_name) \ Chris@16: /* FUNCTION macro expanded to: typedef class functor ## __LINE__ { ... */ \ Chris@16: BOOST_PP_EXPR_IIF(is_recursive, \ Chris@16: /* member var with function name for recursive calls; it cannot be */ \ Chris@16: /* `const` because it is init after construction (because */ \ Chris@16: /* constructor doesn't know local function name) */ \ Chris@16: /* run-time: even when optimizing, recursive calls cannot be */ \ Chris@16: /* optimized (i.e., they must be via the non-local functor) */ \ Chris@16: /* because this cannot be a mem ref because its name is not known */ \ Chris@16: /* by the constructor so it cannot be set by the mem init list */ \ Chris@16: private: \ Chris@16: BOOST_LOCAL_FUNCTION_AUX_CODE_FUNCTOR_TYPE \ Chris@16: BOOST_LOCAL_FUNCTION_AUX_NAME_RECURSIVE_FUNC_(is_recursive, \ Chris@16: local_function_name); \ Chris@16: /* run-time: the `init_recursion()` function cannot be called */ \ Chris@16: /* by the constructor to allow for compiler optimization */ \ Chris@16: /* (inlining) so it must be public to be called (see below) */ \ Chris@16: public: \ Chris@16: inline void BOOST_LOCAL_FUNCTION_AUX_NAME_INIT_RECURSION_FUNC_( \ Chris@16: BOOST_LOCAL_FUNCTION_AUX_CODE_FUNCTOR_TYPE& functor) { \ Chris@16: local_function_name = functor; \ Chris@16: } \ Chris@16: ) \ Chris@16: } BOOST_LOCAL_FUNCTION_AUX_NAME_LOCAL_TYPE_(local_function_name); \ Chris@16: /* local functor can be passed as tparam only on C++11 (faster) */ \ Chris@16: BOOST_LOCAL_FUNCTION_AUX_NAME_LOCAL_TYPE_(local_function_name) \ Chris@16: local_functor_name(BOOST_LOCAL_FUNCTION_AUX_DECL_ARGS_VAR.value); \ Chris@16: /* non-local functor can always be passed as tparam (but slower) */ \ Chris@16: BOOST_PP_EXPR_IIF(typename01, typename) \ Chris@16: BOOST_LOCAL_FUNCTION_AUX_NAME_LOCAL_TYPE_(local_function_name):: \ Chris@16: BOOST_LOCAL_FUNCTION_AUX_CODE_FUNCTOR_TYPE \ Chris@16: nonlocal_functor_name; /* functor variable */ \ Chris@16: /* the order of the following 2 function calls cannot be changed */ \ Chris@16: /* because init_recursion uses the local_functor so the local_functor */ \ Chris@16: /* must be init first */ \ Chris@16: local_functor_name.BOOST_LOCAL_FUNCTION_AUX_FUNCTION_INIT_CALL_FUNC( \ Chris@16: &local_functor_name, nonlocal_functor_name); \ Chris@16: BOOST_PP_EXPR_IIF(is_recursive, \ Chris@16: /* init recursion causes MSVC to not optimize local function not */ \ Chris@16: /* even when local functor is used as template parameter so no */ \ Chris@16: /* recursion unless all inlining optimizations are specified off */ \ Chris@16: local_functor_name.BOOST_LOCAL_FUNCTION_AUX_NAME_INIT_RECURSION_FUNC_( \ Chris@16: nonlocal_functor_name); \ Chris@16: ) Chris@16: Chris@16: #define BOOST_LOCAL_FUNCTION_AUX_NAME_FUNCTOR_(local_function_name) \ Chris@16: BOOST_LOCAL_FUNCTION_AUX_SYMBOL( (local_function_name) ) Chris@16: Chris@16: // This can always be passed as a template parameters (on all compilers). Chris@16: // However, it is slower because it cannot be inlined. Chris@16: // Passed at tparam: Yes (on all C++). Inlineable: No. Recursive: No. Chris@16: #define BOOST_LOCAL_FUNCTION_AUX_NAME_(typename01, local_function_name) \ Chris@16: BOOST_LOCAL_FUNCTION_AUX_NAME_END_LOCAL_FUNCTOR_(typename01, \ Chris@16: local_function_name, \ Chris@16: /* local function is not recursive (because recursion and its */ \ Chris@16: /* initialization cannot be inlined even on C++11, */ \ Chris@16: /* so this allows optimization at least on C++11) */ \ Chris@16: 0 /* not recursive */ , \ Chris@16: /* local functor */ \ Chris@16: BOOST_LOCAL_FUNCTION_AUX_NAME_FUNCTOR_(local_function_name), \ Chris@16: /* local function declared as non-local functor -- but it can */ \ Chris@16: /* be inlined only by C++11 and it cannot be recursive */ \ Chris@16: local_function_name) Chris@16: Chris@16: // This is faster on some compilers but not all (e.g., it is faster on GCC Chris@16: // because its optimization inlines it but not on MSVC). However, it cannot be Chris@16: // passed as a template parameter on non C++11 compilers. Chris@16: // Passed at tparam: Only on C++11. Inlineable: Yes. Recursive: No. Chris@16: #define BOOST_LOCAL_FUNCTION_AUX_NAME_INLINE_(typename01, local_function_name) \ Chris@16: BOOST_LOCAL_FUNCTION_AUX_NAME_END_LOCAL_FUNCTOR_(typename01, \ Chris@16: local_function_name, \ Chris@16: /* inlined local function is never recursive (because recursion */ \ Chris@16: /* and its initialization cannot be inlined)*/ \ Chris@16: 0 /* not recursive */ , \ Chris@16: /* inlined local function declared as local functor (maybe */ \ Chris@16: /* inlined even by non C++11 -- but it can be passed as */ \ Chris@16: /* template parameter only on C++11 */ \ Chris@16: local_function_name, \ Chris@16: /* non-local functor */ \ Chris@16: BOOST_LOCAL_FUNCTION_AUX_NAME_FUNCTOR_(local_function_name)) Chris@16: Chris@16: // This is slower on all compilers (C++11 and non) because recursion and its Chris@16: // initialization can never be inlined. Chris@16: // Passed at tparam: Yes. Inlineable: No. Recursive: Yes. Chris@16: #define BOOST_LOCAL_FUNCTION_AUX_NAME_RECURSIVE_( \ Chris@16: typename01, local_function_name) \ Chris@16: BOOST_LOCAL_FUNCTION_AUX_NAME_END_LOCAL_FUNCTOR_(typename01, \ Chris@16: local_function_name, \ Chris@16: /* recursive local function -- but it cannot be inlined */ \ Chris@16: 1 /* recursive */ , \ Chris@16: /* local functor */ \ Chris@16: BOOST_LOCAL_FUNCTION_AUX_NAME_FUNCTOR_(local_function_name), \ Chris@16: /* local function declared as non-local functor -- but it can */ \ Chris@16: /* be inlined only by C++11 */ \ Chris@16: local_function_name) Chris@16: Chris@16: // Inlined local functions are specified by `..._NAME(inline name)`. Chris@16: // They have more chances to be inlined for faster run-times by some compilers Chris@16: // (for example by GCC but not by MSVC). C++11 compilers can always inline Chris@16: // local functions even if they are not explicitly specified inline. Chris@16: #define BOOST_LOCAL_FUNCTION_AUX_NAME_PARSE_INLINE_( \ Chris@16: typename01, qualified_name) \ Chris@16: BOOST_PP_IIF(BOOST_PP_BITOR( \ Chris@16: BOOST_LOCAL_FUNCTION_CONFIG_LOCALS_AS_TPARAMS, \ Chris@16: BOOST_LOCAL_FUNCTION_DETAIL_PP_KEYWORD_IS_INLINE_FRONT( \ Chris@16: qualified_name)), \ Chris@16: /* on C++11 always use inlining because compilers might optimize */ \ Chris@16: /* it to be faster and it can also be passed as tparam */ \ Chris@16: BOOST_LOCAL_FUNCTION_AUX_NAME_INLINE_ \ Chris@16: , \ Chris@16: /* on non C++11 don't use liniling unless explicitly specified by */ \ Chris@16: /* programmers `inline name` the inlined local function cannot be */ \ Chris@16: /* passed as tparam */ \ Chris@16: BOOST_LOCAL_FUNCTION_AUX_NAME_ \ Chris@16: )(typename01, BOOST_LOCAL_FUNCTION_DETAIL_PP_KEYWORD_INLINE_REMOVE_FRONT( \ Chris@16: qualified_name)) Chris@16: Chris@16: // Expand to 1 iff `recursive name` or `recursive inline name` or Chris@16: // `inline recursive name`. Chris@16: #define BOOST_LOCAL_FUNCTION_AUX_NAME_IS_RECURSIVE_(qualified_name) \ Chris@16: BOOST_LOCAL_FUNCTION_DETAIL_PP_KEYWORD_IS_RECURSIVE_FRONT( \ Chris@16: BOOST_LOCAL_FUNCTION_DETAIL_PP_KEYWORD_INLINE_REMOVE_FRONT( \ Chris@16: qualified_name \ Chris@16: )) Chris@16: Chris@16: // Revmoes `recursive`, `inline recursive`, and `recursive inline` from front. Chris@16: #define BOOST_LOCAL_FUNCTION_AUX_NAME_REMOVE_RECURSIVE_AND_INLINE_( \ Chris@16: qualified_name) \ Chris@16: BOOST_LOCAL_FUNCTION_DETAIL_PP_KEYWORD_RECURSIVE_REMOVE_FRONT( \ Chris@16: BOOST_LOCAL_FUNCTION_DETAIL_PP_KEYWORD_INLINE_REMOVE_FRONT( \ Chris@16: BOOST_LOCAL_FUNCTION_DETAIL_PP_KEYWORD_RECURSIVE_REMOVE_FRONT( \ Chris@16: qualified_name \ Chris@16: ))) Chris@16: Chris@16: #define BOOST_LOCAL_FUNCTION_AUX_NAME_RECURSIVE_REMOVE_(qualified_name) \ Chris@16: BOOST_PP_IIF(BOOST_LOCAL_FUNCTION_AUX_NAME_IS_RECURSIVE_(qualified_name), \ Chris@16: BOOST_LOCAL_FUNCTION_AUX_NAME_REMOVE_RECURSIVE_AND_INLINE_ \ Chris@16: , \ Chris@16: qualified_name /* might be `name` or `inline name` */ \ Chris@16: BOOST_PP_TUPLE_EAT(1) \ Chris@16: )(qualified_name) Chris@16: Chris@16: // Recursive local function are specified by `..._NAME(recursive name)`. Chris@16: // They can never be inlined for faster run-time (not even by C++11 compilers). Chris@16: #define BOOST_LOCAL_FUNCTION_AUX_NAME_PARSE_RECURSIVE_( \ Chris@16: typename01, qualified_name) \ Chris@16: BOOST_PP_IIF(BOOST_LOCAL_FUNCTION_AUX_NAME_IS_RECURSIVE_(qualified_name), \ Chris@16: /* recursion can never be inlined (not even on C++11) */ \ Chris@16: BOOST_LOCAL_FUNCTION_AUX_NAME_RECURSIVE_ \ Chris@16: , \ Chris@16: BOOST_LOCAL_FUNCTION_AUX_NAME_PARSE_INLINE_ \ Chris@16: )(typename01, \ Chris@16: BOOST_LOCAL_FUNCTION_AUX_NAME_RECURSIVE_REMOVE_(qualified_name)) Chris@16: Chris@16: // PUBLIC // Chris@16: Chris@16: #define BOOST_LOCAL_FUNCTION_AUX_NAME(typename01, qualified_name) \ Chris@16: BOOST_LOCAL_FUNCTION_AUX_NAME_PARSE_RECURSIVE_(typename01, qualified_name) Chris@16: Chris@16: #endif // #include guard Chris@16: