#pragma once /*! * \file preprocessor.h * \brief Preprocessor metaprogramming macros */ #if !defined(_MSC_VER) && !defined(__GNUC__) # error Your compiler is not currently supported. #endif /*! * \defgroup yt_pp Preprocessor metaprogramming macros * \ingroup yt_commons * * This is collection of macro definitions for various metaprogramming tasks * with the preprocessor. * * \{ * * \page yt_pp_sequences Sequences * Everything revolves around the concept of a \em sequence. A typical * sequence is encoded like (1)(2)(3).... Internally this allows * to apply some macro to the every element in the sequence (see #PP_FOR_EACH). * * Note that sequences can be nested, i. e. ((1)(2)(3))(a)(b)(c) * * \page yt_pp_examples Examples * Please refer to the unit test for an actual example of usage * (unittests/preprocessor_ut.cpp). * */ //! Concatenates two tokens. #define PP_CONCAT(x, y) PP_CONCAT_A(x, y) //! \cond Implementation #define PP_CONCAT_A(x, y) PP_CONCAT_B(x, y) #define PP_CONCAT_B(x, y) x ## y //! \endcond //! Transforms token into the string forcing argument expansion. #define PP_STRINGIZE(x) PP_STRINGIZE_A(x) //! \cond Implementation #define PP_STRINGIZE_A(x) PP_STRINGIZE_B(x) #define PP_STRINGIZE_B(x) #x //! \endcond //! \cond Implementation #define PP_LEFT_PARENTHESIS ( #define PP_RIGHT_PARENTHESIS ) #define PP_COMMA() , #define PP_EMPTY() //! \endcond //! Removes the enclosing parens, if any. #define PP_DEPAREN(...) PP_DEPAREN_A(PP_DEPAREN_C __VA_ARGS__) //! \cond Implementation #define PP_DEPAREN_C(...) PP_DEPAREN_C __VA_ARGS__ #define PP_DEPAREN_A(...) PP_DEPAREN_B(__VA_ARGS__) #define PP_DEPAREN_B(...) PP_DEPAREN_D_ ## __VA_ARGS__ #define PP_DEPAREN_D_PP_DEPAREN_C //! \endcond //! Performs (non-lazy) conditional expansion. /*! * \param cond Condition; should expands to either \c PP_TRUE or \c PP_FALSE. * \param _then Expansion result in case when \c cond holds. * \param _else Expansion result in case when \c cond does not hold. */ #define PP_IF(cond, _then, _else) PP_CONCAT(PP_IF_, cond)(_then, _else) //! \cond Implementation #define PP_IF_PP_TRUE(x, y) x #define PP_IF_PP_FALSE(x, y) y //! \endcond //! Tests whether supplied argument can be treated as a sequence //! (i. e. ()()()...) #define PP_IS_SEQUENCE(arg) PP_CONCAT(PP_IS_SEQUENCE_B_, PP_COUNT((PP_NIL PP_IS_SEQUENCE_A arg PP_NIL))) //! \cond Implementation #define PP_IS_SEQUENCE_A(_) PP_RIGHT_PARENTHESIS PP_LEFT_PARENTHESIS #define PP_IS_SEQUENCE_B_1 PP_FALSE #define PP_IS_SEQUENCE_B_2 PP_TRUE //! \endcond //! Computes the number of elements in the sequence. #define PP_COUNT(...) PP_COUNT_IMPL(__VA_ARGS__) //! Removes first \c n elements from the sequence. #define PP_KILL(seq, n) PP_KILL_IMPL(seq, n) //! Extracts the head of the sequence. /*! For example, \code PP_HEAD((0)(1)(2)(3)) == 0 \endcode */ #define PP_HEAD(...) PP_HEAD_IMPL(__VA_ARGS__) //! Extracts the tail of the sequence. /*! For example, \code PP_TAIL((0)(1)(2)(3)) == (1)(2)(3) \endcode */ #define PP_TAIL(...) PP_TAIL_IMPL(__VA_ARGS__) //! Extracts the element with the specified index from the sequence. /*! For example, \code PP_ELEMENT((0)(1)(2)(3), 1) == 1 \endcode */ #define PP_ELEMENT(seq, index) PP_ELEMENT_IMPL(seq, index) //! Applies the macro to every member of the sequence. /*! For example, * \code * #define MyFunctor(x) +x+ * PP_FOR_EACH(MyFunctor, (0)(1)(2)(3)) == +0+ +1+ +2+ +3+ * \encode */ #define PP_FOR_EACH(what, seq) PP_FOR_EACH_IMPL(what, seq) //! Declares an anonymous variable. #ifdef __COUNTER__ #define PP_ANONYMOUS_VARIABLE(str) PP_CONCAT(str, __COUNTER__) #else #define PP_ANONYMOUS_VARIABLE(str) PP_CONCAT(str, __LINE__) #endif //! Insert prefix based on presence of additional arguments. #define PP_ONE_OR_NONE(a, ...) PP_THIRD(a, ## __VA_ARGS__, a) #define PP_THIRD(a, b, ...) __VA_ARGS__ //! \cond Implementation #define PREPROCESSOR_GEN_H_ #include "preprocessor-gen.h" #undef PREPROCESSOR_GEN_H_ //! \endcond /*! \} */