boost/contract/base_types.hpp
#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 the @c typedef that lists the bases of a derived class.
In order to support subcontracting, a derived class that specifies contracts for
one or more overriding public functions 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_BASE_TYPES(BASES) base_types;
#undef BASES
...
};
@endcode
This @c typedef must be @c public unless @RefClass{boost::contract::access} is
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 (see
@RefSect{extras.no_macros__and_no_variadic_macros_, No Macros}).
*/
#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