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