diff options
Diffstat (limited to 'boost/contract/base_types.hpp')
-rw-r--r-- | boost/contract/base_types.hpp | 200 |
1 files changed, 200 insertions, 0 deletions
diff --git a/boost/contract/base_types.hpp b/boost/contract/base_types.hpp new file mode 100644 index 0000000000..2ab47d6e8b --- /dev/null +++ b/boost/contract/base_types.hpp @@ -0,0 +1,200 @@ + +#ifndef BOOST_CONTRACT_BASE_TYPES_HPP_ +#define BOOST_CONTRACT_BASE_TYPES_HPP_ + +// Copyright (C) 2008-2018 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +/** @file +Specify inheritance form base classes (for subcontracting). +*/ + +// IMPORTANT: Included by contract_macro.hpp so must #if-guard all its includes. +#include <boost/contract/core/config.hpp> +#include <boost/preprocessor/config/config.hpp> + +#ifdef BOOST_CONTRACT_DETAIL_DOXYGEN + +/** +Used to program a @c typedef listing the bases of a derived class. + +In order to support subcontracting, a derived class that specifies contracts for +one or more overriding public function must declare a @c typedef named +@c base_types (or @RefMacro{BOOST_CONTRACT_BASES_TYPEDEF}) using this macro. + + @code + class u : + #define BASES public b, protected virtual w1, private w2 + BASES + { + friend class boost::contract:access; + + typedef BOOST_CONTRACT_BASES(BASES) base_types; + #undef BASES + + ... + }; + @endcode + +This @c typedef must be @c public if @RefClass{boost::contract::access} is not +used. + +@see @RefSect{tutorial.base_classes__subcontracting_, Base Classes} + +@param ... Comma separated list of base classes. + Each base must explicitly specify its access specifier @c public, + @c protected, or @c private, and also @c virtual when present + (this not always required in C++ instead). + There is a limit of about 20 maximum bases that can be listed + (because of similar limits in Boost.MPL internally used by this + library). + This is a variadic macro parameter, on compilers that do not support + variadic macros, the @c typedef for base classes can be programmed + manually without using this macro. +*/ +#define BOOST_CONTRACT_BASE_TYPES(...) + +#elif !BOOST_PP_VARIADICS + +#define BOOST_CONTRACT_BASE_TYPES \ +BOOST_CONTRACT_ERROR_macro_BASE_TYPES_requires_variadic_macros_otherwise_manually_program_base_types + +#elif !defined(BOOST_CONTRACT_NO_PUBLIC_FUNCTIONS) + +#include <boost/mpl/vector.hpp> +#include <boost/contract/detail/preprocessor/keyword/virtual.hpp> +#include <boost/contract/detail/preprocessor/keyword/public.hpp> +#include <boost/contract/detail/preprocessor/keyword/protected.hpp> +#include <boost/contract/detail/preprocessor/keyword/private.hpp> +#include <boost/preprocessor/variadic/to_seq.hpp> +#include <boost/preprocessor/seq/fold_left.hpp> +#include <boost/preprocessor/seq/enum.hpp> +#include <boost/preprocessor/seq/push_back.hpp> +#include <boost/preprocessor/seq/size.hpp> +#include <boost/preprocessor/seq/seq.hpp> // For HEAD, TAIL, etc. +#include <boost/preprocessor/tuple/elem.hpp> +#include <boost/preprocessor/tuple/rem.hpp> +#include <boost/preprocessor/tuple/eat.hpp> +#include <boost/preprocessor/comparison/equal.hpp> +#include <boost/preprocessor/control/iif.hpp> +#include <boost/preprocessor/facilities/expand.hpp> + +/* PRIVATE */ + +#define BOOST_CONTRACT_BASE_TYPES_REMOVE_VIRTUAL_(base) \ + BOOST_PP_EXPAND( \ + BOOST_PP_IIF(BOOST_CONTRACT_DETAIL_PP_KEYWORD_IS_VIRTUAL(base), \ + BOOST_CONTRACT_DETAIL_PP_KEYWORD_REMOVE_VIRTUAL \ + , \ + BOOST_PP_TUPLE_REM(1) \ + )(base) \ + ) + +#define BOOST_CONTRACT_BASE_TYPES_PUSH_BACK_IF_(is_public, types_nilseq, base) \ + ( \ + is_public, \ + BOOST_PP_IIF(is_public, \ + BOOST_PP_SEQ_PUSH_BACK \ + , \ + types_nilseq BOOST_PP_TUPLE_EAT(2) \ + )(types_nilseq, base) \ + ) + +#define BOOST_CONTRACT_BASE_TYPES_SKIP_NOT_PUBLIC_(is_public, types_nilseq, \ + base) \ + (0, types_nilseq) + +// Precondition: base = `public [virtual] ...`. +#define BOOST_CONTRACT_BASE_TYPES_PUSH_BACK_PUBLIC_(is_public, types_nilseq, \ + base) \ + ( \ + 1, \ + BOOST_PP_SEQ_PUSH_BACK(types_nilseq, \ + BOOST_CONTRACT_BASE_TYPES_REMOVE_VIRTUAL_( \ + BOOST_CONTRACT_DETAIL_PP_KEYWORD_REMOVE_PUBLIC(base)) \ + ) \ + ) + +#define BOOST_CONTRACT_BASE_TYPES_ACCESS_(is_public, types_nilseq, base) \ + BOOST_PP_IIF(BOOST_CONTRACT_DETAIL_PP_KEYWORD_IS_PUBLIC(base), \ + BOOST_CONTRACT_BASE_TYPES_PUSH_BACK_PUBLIC_ \ + , BOOST_PP_IIF(BOOST_CONTRACT_DETAIL_PP_KEYWORD_IS_PROTECTED(base), \ + BOOST_CONTRACT_BASE_TYPES_SKIP_NOT_PUBLIC_ \ + , BOOST_PP_IIF(BOOST_CONTRACT_DETAIL_PP_KEYWORD_IS_PRIVATE(base), \ + BOOST_CONTRACT_BASE_TYPES_SKIP_NOT_PUBLIC_ \ + , \ + BOOST_CONTRACT_BASE_TYPES_PUSH_BACK_IF_ \ + )))(is_public, types_nilseq, base) + +#define BOOST_CONTRACT_BASE_TYPES_(s, public_types, base) \ + BOOST_CONTRACT_BASE_TYPES_ACCESS_( \ + BOOST_PP_TUPLE_ELEM(2, 0, public_types), \ + BOOST_PP_TUPLE_ELEM(2, 1, public_types), \ + BOOST_CONTRACT_BASE_TYPES_REMOVE_VIRTUAL_(base) \ + ) + +#define BOOST_CONTRACT_BASE_TYPES_RETURN_YES_(types_nilseq) \ + BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TAIL(types_nilseq)) + +#define BOOST_CONTRACT_BASE_TYPES_RETURN_(types_nilseq) \ + BOOST_PP_IIF(BOOST_PP_EQUAL(BOOST_PP_SEQ_SIZE(types_nilseq), 1), \ + BOOST_PP_TUPLE_EAT(1) \ + , \ + BOOST_CONTRACT_BASE_TYPES_RETURN_YES_ \ + )(types_nilseq) + +#define BOOST_CONTRACT_BASE_TYPES_OK_(base_tuple, bases_seq) \ + boost::mpl::vector< \ + BOOST_CONTRACT_BASE_TYPES_RETURN_(BOOST_PP_TUPLE_ELEM(2, 1, \ + BOOST_PP_SEQ_FOLD_LEFT( \ + BOOST_CONTRACT_BASE_TYPES_, \ + (0, (BOOST_PP_NIL)), \ + bases_seq \ + ) \ + )) \ + > + +#define BOOST_CONTRACT_BASE_TYPES_ERR_(bases_tuple, bases_seq) \ + BOOST_CONTRACT_ERROR_all_bases_must_explicitly_specify_public_protected_or_private base_tuple + +#define BOOST_CONTRACT_BASE_TYPES_IS_ACCESS_(base) \ + BOOST_PP_IIF(BOOST_CONTRACT_DETAIL_PP_KEYWORD_IS_PUBLIC(base), \ + 1 \ + , BOOST_PP_IIF(BOOST_CONTRACT_DETAIL_PP_KEYWORD_IS_PROTECTED(base), \ + 1 \ + , BOOST_PP_IIF(BOOST_CONTRACT_DETAIL_PP_KEYWORD_IS_PRIVATE(base), \ + 1 \ + , \ + 0 \ + ))) + +// Cannot check that all base types have access specifiers (unless users have to +// specify bases using pp-seq, because user specified base list can have +// unwrapped commas between bases but also within a given base type, when base +// types are templates), but at least check the very first base type explicitly +// specifies access `[virtual] public | protected | private [virtual] ...`. +#define BOOST_CONTRACT_BASE_TYPES_CHECK_(bases_tuple, bases_seq) \ + BOOST_PP_IIF(BOOST_CONTRACT_BASE_TYPES_IS_ACCESS_( \ + BOOST_CONTRACT_BASE_TYPES_REMOVE_VIRTUAL_(BOOST_PP_SEQ_HEAD( \ + bases_seq))), \ + BOOST_CONTRACT_BASE_TYPES_OK_ \ + , \ + BOOST_CONTRACT_BASE_TYPES_ERR_ \ + )(bases_tuple, bases_seq) + +/* PUBLIC */ + +#define BOOST_CONTRACT_BASE_TYPES(...) \ + BOOST_CONTRACT_BASE_TYPES_CHECK_((__VA_ARGS__), \ + BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) + +#else + +#define BOOST_CONTRACT_BASE_TYPES(...) void /* dummy type for typedef */ + +#endif + +#endif // #include guard + |