base_types.hpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. #ifndef BOOST_CONTRACT_BASE_TYPES_HPP_
  2. #define BOOST_CONTRACT_BASE_TYPES_HPP_
  3. // Copyright (C) 2008-2018 Lorenzo Caminiti
  4. // Distributed under the Boost Software License, Version 1.0 (see accompanying
  5. // file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt).
  6. // See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html
  7. /** @file
  8. Specify inheritance form base classes (for subcontracting).
  9. */
  10. // IMPORTANT: Included by contract_macro.hpp so must #if-guard all its includes.
  11. #include <boost/contract/core/config.hpp>
  12. #include <boost/preprocessor/config/config.hpp>
  13. #ifdef BOOST_CONTRACT_DETAIL_DOXYGEN
  14. /**
  15. Used to program the @c typedef that lists the bases of a derived class.
  16. In order to support subcontracting, a derived class that specifies contracts for
  17. one or more overriding public functions must declare a @c typedef named
  18. @c base_types (or @RefMacro{BOOST_CONTRACT_BASES_TYPEDEF}) using this macro:
  19. @code
  20. class u
  21. #define BASES public b, protected virtual w1, private w2
  22. : BASES
  23. {
  24. friend class boost::contract:access;
  25. typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types;
  26. #undef BASES
  27. ...
  28. };
  29. @endcode
  30. This @c typedef must be @c public unless @RefClass{boost::contract::access} is
  31. used.
  32. @see @RefSect{tutorial.base_classes__subcontracting_, Base Classes}
  33. @param ... Comma separated list of base classes.
  34. Each base must explicitly specify its access specifier @c public,
  35. @c protected, or @c private, and also @c virtual when present
  36. (this not always required in C++ instead).
  37. There is a limit of about 20 maximum bases that can be listed
  38. (because of similar limits in Boost.MPL internally used by this
  39. library).
  40. This is a variadic macro parameter, on compilers that do not support
  41. variadic macros, the @c typedef for base classes can be programmed
  42. manually without using this macro (see
  43. @RefSect{extras.no_macros__and_no_variadic_macros_, No Macros}).
  44. */
  45. #define BOOST_CONTRACT_BASE_TYPES(...)
  46. #elif !BOOST_PP_VARIADICS
  47. #define BOOST_CONTRACT_BASE_TYPES \
  48. BOOST_CONTRACT_ERROR_macro_BASE_TYPES_requires_variadic_macros_otherwise_manually_program_base_types
  49. #elif !defined(BOOST_CONTRACT_NO_PUBLIC_FUNCTIONS)
  50. #include <boost/mpl/vector.hpp>
  51. #include <boost/contract/detail/preprocessor/keyword/virtual.hpp>
  52. #include <boost/contract/detail/preprocessor/keyword/public.hpp>
  53. #include <boost/contract/detail/preprocessor/keyword/protected.hpp>
  54. #include <boost/contract/detail/preprocessor/keyword/private.hpp>
  55. #include <boost/preprocessor/variadic/to_seq.hpp>
  56. #include <boost/preprocessor/seq/fold_left.hpp>
  57. #include <boost/preprocessor/seq/enum.hpp>
  58. #include <boost/preprocessor/seq/push_back.hpp>
  59. #include <boost/preprocessor/seq/size.hpp>
  60. #include <boost/preprocessor/seq/seq.hpp> // For HEAD, TAIL, etc.
  61. #include <boost/preprocessor/tuple/elem.hpp>
  62. #include <boost/preprocessor/tuple/rem.hpp>
  63. #include <boost/preprocessor/tuple/eat.hpp>
  64. #include <boost/preprocessor/comparison/equal.hpp>
  65. #include <boost/preprocessor/control/iif.hpp>
  66. #include <boost/preprocessor/facilities/expand.hpp>
  67. /* PRIVATE */
  68. #define BOOST_CONTRACT_BASE_TYPES_REMOVE_VIRTUAL_(base) \
  69. BOOST_PP_EXPAND( \
  70. BOOST_PP_IIF(BOOST_CONTRACT_DETAIL_PP_KEYWORD_IS_VIRTUAL(base), \
  71. BOOST_CONTRACT_DETAIL_PP_KEYWORD_REMOVE_VIRTUAL \
  72. , \
  73. BOOST_PP_TUPLE_REM(1) \
  74. )(base) \
  75. )
  76. #define BOOST_CONTRACT_BASE_TYPES_PUSH_BACK_IF_(is_public, types_nilseq, base) \
  77. ( \
  78. is_public, \
  79. BOOST_PP_IIF(is_public, \
  80. BOOST_PP_SEQ_PUSH_BACK \
  81. , \
  82. types_nilseq BOOST_PP_TUPLE_EAT(2) \
  83. )(types_nilseq, base) \
  84. )
  85. #define BOOST_CONTRACT_BASE_TYPES_SKIP_NOT_PUBLIC_(is_public, types_nilseq, \
  86. base) \
  87. (0, types_nilseq)
  88. // Precondition: base = `public [virtual] ...`.
  89. #define BOOST_CONTRACT_BASE_TYPES_PUSH_BACK_PUBLIC_(is_public, types_nilseq, \
  90. base) \
  91. ( \
  92. 1, \
  93. BOOST_PP_SEQ_PUSH_BACK(types_nilseq, \
  94. BOOST_CONTRACT_BASE_TYPES_REMOVE_VIRTUAL_( \
  95. BOOST_CONTRACT_DETAIL_PP_KEYWORD_REMOVE_PUBLIC(base)) \
  96. ) \
  97. )
  98. #define BOOST_CONTRACT_BASE_TYPES_ACCESS_(is_public, types_nilseq, base) \
  99. BOOST_PP_IIF(BOOST_CONTRACT_DETAIL_PP_KEYWORD_IS_PUBLIC(base), \
  100. BOOST_CONTRACT_BASE_TYPES_PUSH_BACK_PUBLIC_ \
  101. , BOOST_PP_IIF(BOOST_CONTRACT_DETAIL_PP_KEYWORD_IS_PROTECTED(base), \
  102. BOOST_CONTRACT_BASE_TYPES_SKIP_NOT_PUBLIC_ \
  103. , BOOST_PP_IIF(BOOST_CONTRACT_DETAIL_PP_KEYWORD_IS_PRIVATE(base), \
  104. BOOST_CONTRACT_BASE_TYPES_SKIP_NOT_PUBLIC_ \
  105. , \
  106. BOOST_CONTRACT_BASE_TYPES_PUSH_BACK_IF_ \
  107. )))(is_public, types_nilseq, base)
  108. #define BOOST_CONTRACT_BASE_TYPES_(s, public_types, base) \
  109. BOOST_CONTRACT_BASE_TYPES_ACCESS_( \
  110. BOOST_PP_TUPLE_ELEM(2, 0, public_types), \
  111. BOOST_PP_TUPLE_ELEM(2, 1, public_types), \
  112. BOOST_CONTRACT_BASE_TYPES_REMOVE_VIRTUAL_(base) \
  113. )
  114. #define BOOST_CONTRACT_BASE_TYPES_RETURN_YES_(types_nilseq) \
  115. BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TAIL(types_nilseq))
  116. #define BOOST_CONTRACT_BASE_TYPES_RETURN_(types_nilseq) \
  117. BOOST_PP_IIF(BOOST_PP_EQUAL(BOOST_PP_SEQ_SIZE(types_nilseq), 1), \
  118. BOOST_PP_TUPLE_EAT(1) \
  119. , \
  120. BOOST_CONTRACT_BASE_TYPES_RETURN_YES_ \
  121. )(types_nilseq)
  122. #define BOOST_CONTRACT_BASE_TYPES_OK_(base_tuple, bases_seq) \
  123. boost::mpl::vector< \
  124. BOOST_CONTRACT_BASE_TYPES_RETURN_(BOOST_PP_TUPLE_ELEM(2, 1, \
  125. BOOST_PP_SEQ_FOLD_LEFT( \
  126. BOOST_CONTRACT_BASE_TYPES_, \
  127. (0, (BOOST_PP_NIL)), \
  128. bases_seq \
  129. ) \
  130. )) \
  131. >
  132. #define BOOST_CONTRACT_BASE_TYPES_ERR_(bases_tuple, bases_seq) \
  133. BOOST_CONTRACT_ERROR_all_bases_must_explicitly_specify_public_protected_or_private base_tuple
  134. #define BOOST_CONTRACT_BASE_TYPES_IS_ACCESS_(base) \
  135. BOOST_PP_IIF(BOOST_CONTRACT_DETAIL_PP_KEYWORD_IS_PUBLIC(base), \
  136. 1 \
  137. , BOOST_PP_IIF(BOOST_CONTRACT_DETAIL_PP_KEYWORD_IS_PROTECTED(base), \
  138. 1 \
  139. , BOOST_PP_IIF(BOOST_CONTRACT_DETAIL_PP_KEYWORD_IS_PRIVATE(base), \
  140. 1 \
  141. , \
  142. 0 \
  143. )))
  144. // Cannot check that all base types have access specifiers (unless users have to
  145. // specify bases using pp-seq, because user specified base list can have
  146. // unwrapped commas between bases but also within a given base type, when base
  147. // types are templates), but at least check the very first base type explicitly
  148. // specifies access `[virtual] public | protected | private [virtual] ...`.
  149. #define BOOST_CONTRACT_BASE_TYPES_CHECK_(bases_tuple, bases_seq) \
  150. BOOST_PP_IIF(BOOST_CONTRACT_BASE_TYPES_IS_ACCESS_( \
  151. BOOST_CONTRACT_BASE_TYPES_REMOVE_VIRTUAL_(BOOST_PP_SEQ_HEAD( \
  152. bases_seq))), \
  153. BOOST_CONTRACT_BASE_TYPES_OK_ \
  154. , \
  155. BOOST_CONTRACT_BASE_TYPES_ERR_ \
  156. )(bases_tuple, bases_seq)
  157. /* PUBLIC */
  158. #define BOOST_CONTRACT_BASE_TYPES(...) \
  159. BOOST_CONTRACT_BASE_TYPES_CHECK_((__VA_ARGS__), \
  160. BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))
  161. #else
  162. #define BOOST_CONTRACT_BASE_TYPES(...) void /* dummy type for typedef */
  163. #endif
  164. #endif // #include guard