From 4a871dc233e6f4af53333f4ef6769b814686654a Mon Sep 17 00:00:00 2001 From: Lorenzo Caminiti Date: Sat, 28 Mar 2015 16:45:01 -0700 Subject: [PATCH] started to program macros to expand constrated class and function code --- include/boost/contract.hpp | 10 ++ include/boost/contract/aux_/code/class.hpp | 123 ++++++++++++++++++ include/boost/contract/aux_/code/func.hpp | 123 ++++++++++++++++++ .../contract/aux_/code/invoke_or_error.hpp | 44 +++++++ include/boost/contract/aux_/code/params.hpp | 115 ++++++++++++++++ include/boost/contract/aux_/eval.hpp | 24 ++++ include/boost/contract/aux_/name.hpp | 23 ++++ include/boost/contract/class.hpp | 22 ++++ include/boost/contract/class_invariant.hpp | 16 +++ .../ext_/preprocessor/keyword/utility/is.hpp | 5 +- .../contract/ext_/preprocessor/paren/has.hpp | 3 +- .../ext_/preprocessor/parenthesize.hpp | 10 ++ .../ext_/preprocessor/traits/base/type.hpp | 2 +- .../traits/class/specialization.hpp | 2 +- .../preprocessor/traits/class/verbatim.hpp | 2 +- .../ext_/preprocessor/traits/func/ref.hpp | 13 ++ .../ext_/preprocessor/traits/func/return.hpp | 6 +- .../preprocessor/traits/param/default.hpp | 2 +- .../ext_/preprocessor/variadic/wrap_iif.hpp | 16 +++ include/boost/contract/function.hpp | 25 ++++ include/boost/contract/oldof.hpp | 2 + test/Jamfile.v2 | 2 + test/code/class.cpp | 30 +++++ 23 files changed, 610 insertions(+), 10 deletions(-) create mode 100644 include/boost/contract.hpp create mode 100644 include/boost/contract/aux_/code/class.hpp create mode 100644 include/boost/contract/aux_/code/func.hpp create mode 100644 include/boost/contract/aux_/code/invoke_or_error.hpp create mode 100644 include/boost/contract/aux_/code/params.hpp create mode 100644 include/boost/contract/aux_/eval.hpp create mode 100644 include/boost/contract/aux_/name.hpp create mode 100644 include/boost/contract/class.hpp create mode 100644 include/boost/contract/class_invariant.hpp create mode 100644 include/boost/contract/ext_/preprocessor/variadic/wrap_iif.hpp create mode 100644 include/boost/contract/function.hpp create mode 100644 test/code/class.cpp diff --git a/include/boost/contract.hpp b/include/boost/contract.hpp new file mode 100644 index 0000000..9615fb9 --- /dev/null +++ b/include/boost/contract.hpp @@ -0,0 +1,10 @@ + +#ifndef BOOST_CONTRACT_HPP_ +#define BOOST_CONTRACT_HPP_ + +#include +#include +#include + +#endif // #include guard + diff --git a/include/boost/contract/aux_/code/class.hpp b/include/boost/contract/aux_/code/class.hpp new file mode 100644 index 0000000..5569d59 --- /dev/null +++ b/include/boost/contract/aux_/code/class.hpp @@ -0,0 +1,123 @@ + +#ifndef BOOST_CONTRACT_AUX_CLASS_HPP_ +#define BOOST_CONTRACT_AUX_CLASS_HPP_ + +#include +#include +#include +#include // c +#include // b +#include +#include +#include +#include +#include +#include +#include +#include + +/* PUBLIC */ + +// Type of class being declared. +#define BOOST_CONTRACT_AUX_CLASS_TYPE \ + BOOST_CONTRACT_AUX_NAME1(class_type) + +// Type of extra evaluation base. +#define BOOST_CONTRACT_AUX_CLASS_EVAL_BASE_TYPE \ + BOOST_CONTRACT_AUX_NAME1(eval_base_type) + +// Type of i-th base class, i in [0, number of base classes for this class). +#define BOOST_CONTRACT_AUX_CLASS_BASE_TYPE(i) \ + BOOST_CONTRACT_AUX_NAME2(base_type, i) + +#define BOOST_CONTRACT_AUX_CLASS_D_R(d, r, id, tpl, c) \ + BOOST_CONTRACT_EXT_PP_CLASS_TRAITS_EXPORT(c) \ + BOOST_CONTRACT_EXT_PP_CLASS_TRAITS_TEMPLATE(c) \ + BOOST_CONTRACT_EXT_PP_VARIADIC_WRAP_IIF( \ + BOOST_PP_COMPL(BOOST_CONTRACT_EXT_PP_IS_EMPTY( \ + BOOST_CONTRACT_EXT_PP_CLASS_TRAITS_TEMPLATE(c))) \ + , \ + <, >, \ + BOOST_CONTRACT_AUX_TEMPLATE_PARAMS_WITH_DEFAULTS_D_R(d, r, id, tpl, \ + BOOST_CONTRACT_EXT_PP_CLASS_TRAITS_TEMPLATE_PARAMS(c), \ + BOOST_PP_EMPTY() \ + ) \ + ) \ + BOOST_CONTRACT_EXT_PP_CLASS_TRAITS_FRIEND(c) \ + BOOST_CONTRACT_EXT_PP_CLASS_TRAITS_KEY(c) \ + BOOST_CONTRACT_EXT_PP_UNPARENTHESIZE( \ + BOOST_CONTRACT_EXT_PP_CLASS_TRAITS_VERBATIM(c)) \ + BOOST_CONTRACT_EXT_PP_CLASS_TRAITS_NAME(c) \ + BOOST_CONTRACT_EXT_PP_VARIADIC_WRAP_IIF( \ + BOOST_PP_COMPL(BOOST_CONTRACT_EXT_PP_IS_EMPTY( \ + BOOST_CONTRACT_EXT_PP_CLASS_TRAITS_SPECIALIZATION(c))) \ + , \ + <, >, \ + BOOST_CONTRACT_EXT_PP_CLASS_TRAITS_SPECIALIZATION(c) \ + ) \ + BOOST_CONTRACT_EXT_PP_CLASS_TRAITS_FINAL(c) \ + BOOST_PP_IIF(BOOST_CONTRACT_AUX_CLASS_HAS_EVAL_BASE_(c), \ + : private BOOST_CONTRACT_AUX_CLASS_EVAL_BASE_ \ + , \ + BOOST_PP_TUPLE_EAT(1) \ + )(c) \ + BOOST_PP_IIF(BOOST_CONTRACT_EXT_PP_IS_EMPTY( \ + BOOST_CONTRACT_EXT_PP_CLASS_TRAITS_BASES(c)), \ + BOOST_PP_TUPLE_EAT(4) \ + , \ + BOOST_PP_SEQ_FOR_EACH_I_R \ + )(r, \ + BOOST_CONTRACT_AUX_CLASS_BASE_, \ + BOOST_CONTRACT_AUX_CLASS_HAS_EVAL_BASE_(c), \ + BOOST_CONTRACT_EXT_PP_CLASS_TRAITS_BASES(c) \ + ) \ + BOOST_PP_IIF(BOOST_CONTRACT_AUX_CLASS_HAS_TYPEDEFS_(c), \ + BOOST_CONTRACT_AUX_CLASS_TYPEDEFS_ \ + , \ + BOOST_PP_TUPLE_EAT(5) \ + )(d, r, id, tpl, c) + +/* PRIVATE */ + +// TODO: Expand 0 if contracts disabled... +#define BOOST_CONTRACT_AUX_CLASS_HAS_EVAL_BASE_(c) 1 + +// TODO: Expand 0 if contracts disabled... +#define BOOST_CONTRACT_AUX_CLASS_HAS_TYPEDEFS_(c) 1 + +#define BOOST_CONTRACT_AUX_CLASS_EVAL_BASE_(c) \ + boost::contract::aux::eval + +#define BOOST_CONTRACT_AUX_CLASS_BASE_(r, has_extra_bases, i, b) \ + BOOST_PP_IIF(has_extra_bases, \ + BOOST_PP_COMMA \ + , BOOST_PP_IF(i, \ + BOOST_PP_COMMA \ + , \ + : BOOST_PP_EMPTY \ + ))() \ + BOOST_CONTRACT_EXT_PP_BASE_TRAITS_ACCESS(b) \ + BOOST_CONTRACT_EXT_PP_BASE_TRAITS_VIRTUAL(b) \ + BOOST_PP_TUPLE_REM_CTOR(BOOST_CONTRACT_EXT_PP_BASE_TRAITS_TYPE(b)) + +#define BOOST_CONTRACT_AUX_CLASS_BASE_TYPEDEF_(r, unused, i, b) \ + typedef BOOST_PP_TUPLE_REM_CTOR(BOOST_CONTRACT_EXT_PP_BASE_TRAITS_TYPE(b)) \ + BOOST_CONTRACT_AUX_CLASS_BASE_TYPE(i); + +#define BOOST_CONTRACT_AUX_CLASS_TYPEDEFS_(d, r, id, tpl, c) \ + { \ + typedef BOOST_CONTRACT_EXT_PP_CLASS_TRAITS_NAME(c) \ + BOOST_CONTRACT_AUX_CLASS_TYPE; \ + typedef BOOST_CONTRACT_AUX_CLASS_EVAL_BASE_(c) \ + BOOST_CONTRACT_AUX_CLASS_EVAL_BASE_TYPE; \ + BOOST_PP_IIF(BOOST_CONTRACT_EXT_PP_IS_EMPTY( \ + BOOST_CONTRACT_EXT_PP_CLASS_TRAITS_BASES(c)), \ + BOOST_PP_TUPLE_EAT(2) \ + , \ + BOOST_PP_SEQ_FOR_EACH_I_R \ + )(r, BOOST_CONTRACT_AUX_CLASS_BASE_TYPEDEF_, ~, \ + BOOST_CONTRACT_EXT_PP_CLASS_TRAITS_BASES(c)) \ + class BOOST_CONTRACT_AUX_NAME1(ERROR_missing_class_invariant) + +#endif // #include guard + diff --git a/include/boost/contract/aux_/code/func.hpp b/include/boost/contract/aux_/code/func.hpp new file mode 100644 index 0000000..cf5f8f4 --- /dev/null +++ b/include/boost/contract/aux_/code/func.hpp @@ -0,0 +1,123 @@ + +#ifndef BOOST_CONTRACT_AUX_FUNC_HPP_ +#define BOOST_CONTRACT_AUX_FUNC_HPP_ + +#include // f +#include + +/* PUBLIC */ + +#define BOOST_CONTRACT_AUX_FUNC_D_R(d, r, id, tpl, f) \ + BOOST_CONTRACT_AUX_NAMED_FUNC_DECL_D_R(d, r, id, tpl, f, \ + BOOST_PP_IIF(BOOST_CONTRACT_EXT_PP_IS_EMPTY( \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_OPERATOR_NAME(f)), \ + BOOST_CONTRACT_AUX_FUNC_NAME_ \ + , \ + BOOST_CONTRACT_AUX_FUNC_OPERATOR_ \ + )(f) \ + ) + +#define BOOST_CONTRACT_AUX_NAMED_FUNC_DECL_D_R(d, r, id, tpl, f, \ + parenthesized_name) \ + BOOST_CONTRACT_AUX_FUNC_DECL_(d, r, id, tpl, f, \ + parenthesized_name, \ + BOOST_CONTRACT_AUX_PARAMS_WITH_DEFAULTS_D_R, BOOST_PP_EMPTY(), \ + (1, 1, 1) \ + ) + +/* PRIVATE */ + +#define BOOST_CONTRACT_AUX_FUNC_NAME_(f) \ + (BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_NAME(f)) + +// Precondition: OPERATOR_NAME(f) != EMPTY(). +#define BOOST_CONTRACT_AUX_FUNC_OPERATOR_(f) \ + (operator BOOST_PP_TUPLE_REM_CTOR( \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_OPERATOR_NAME(f))) + +#define BOOST_CONTRACT_AUX_FUNC_DECL_(d, r, id, tpl, f, parenthesized_name, \ + params_macro, extra_params, access_classifiers_virt) \ + BOOST_CONTRACT_AUX_FUNC_DECL_ARGS_(d, r, id, tpl, f, \ + parenthesized_name, \ + params_macro, extra_params, \ + BOOST_PP_TUPLE_ELEM(3, 0, access_classifiers_virt), \ + BOOST_PP_TUPLE_ELEM(3, 1, access_classifiers_virt), \ + BOOST_PP_TUPLE_ELEM(3, 2, access_classifiers_virt) \ + ) + +// Name is passed within parenthesis in case it is an operator with commas, +// for example: `operator std::map`, `operator,`. +#define BOOST_CONTRACT_AUX_FUNC_DECL_ARGS_(d, r, id, tpl, f, \ + parenthesized_name, \ + params_macro, extra_params, \ + has_access, has_classifiers, has_virtual_specifiers \ +) \ + BOOST_PP_IIF(BOOST_PP_COMPL(has_access), \ + BOOST_PP_TUPLE_EAT(1) \ + , BOOST_PP_IIF(BOOST_CONTRACT_EXT_PP_IS_EMPTY( \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_ACCESS(f)), \ + BOOST_PP_TUPLE_EAT(1) \ + , \ + BOOST_PP_TUPLE_REM(1) \ + ))(BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_ACCESS(f):) \ + BOOST_CONTRACT_EXT_PP_UNPARENTHESIZE( \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_VERBATIM(f)) \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_EXPORT(f) \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_TEMPLATE(f) \ + BOOST_CONTRACT_EXT_PP_VARIADIC_WRAP_IIF( \ + BOOST_PP_COMPL(BOOST_CONTRACT_EXT_PP_IS_EMPTY( \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_TEMPLATE(f)) \ + ), \ + <, >, \ + BOOST_CONTRACT_AUX_TEMPLATE_PARAMS_WITH_DEFAULTS_D_R(d, r, id, tpl, \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_TEMPLATE_PARAMS(f), \ + BOOST_PP_EMPTY() \ + ) \ + ) \ + BOOST_PP_IIF(has_classifiers, \ + BOOST_CONTRACT_AUX_CLASSIFIERS_ \ + , \ + BOOST_PP_TUPLE_EAT(1) \ + )(f) \ + BOOST_CONTRACT_EXT_PP_UNPARENTHESIZE( \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_RETURN(f)) \ + BOOST_CONTRACT_EXT_PP_UNPARENTHESIZE(parenthesized_name) \ + (params_macro(d, r, id, tpl, BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_PARAMS(f), \ + extra_params)) \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_CONST(f) \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_VOLATILE(f) \ + BOOST_PP_IIF(BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_IS_REF_REF( \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_REF(f)), \ + && \ + , BOOST_PP_IIF(BOOST_CONTRACT_EXT_PP_KEYWORD_IS_REF_FRONT( \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_REF(f)), \ + & \ + , \ + BOOST_PP_EMPTY() \ + )) \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_EXCEPT(f) \ + BOOST_PP_EXPR_IIF(BOOST_PP_COMPL(BOOST_CONTRACT_EXT_PP_IS_EMPTY( \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_TRAILING_RETURN(f))), \ + -> BOOST_CONTRACT_EXT_PP_UNPARENTHESIZE \ + ) BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_TRAILING_RETURN(f) \ + BOOST_PP_IIF(has_virtual_specifiers, \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_FINAL \ + , \ + BOOST_PP_TUPLE_EAT(1) \ + )(f) \ + BOOST_PP_IIF(has_virtual_specifiers, \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_OVERRIDE \ + , \ + BOOST_PP_TUPLE_EAT(1) \ + )(f) + +#define BOOST_CONTRACT_AUX_CLASSIFIERS_(f) \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_INLINE(f) \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_STATIC(f) \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_EXTERN(f) \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_EXPLICIT(f) \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_VIRTUAL(f) \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_FRIEND(f) + +#endif // #include guard + diff --git a/include/boost/contract/aux_/code/invoke_or_error.hpp b/include/boost/contract/aux_/code/invoke_or_error.hpp new file mode 100644 index 0000000..34f1da9 --- /dev/null +++ b/include/boost/contract/aux_/code/invoke_or_error.hpp @@ -0,0 +1,44 @@ + +#ifndef BOOST_CONTRACT_AUX_CODE_INVOKE_OR_ERROR_HPP_ +#define BOOST_CONTRACT_AUX_CODE_INVOKE_OR_ERROR_HPP_ + +#include +#include +#include +#include +#include + +/* PUBLIC */ + +// Expand to `op_macro(d, id, traits)` if parsed decl is NIL (i.e., no trait +// parsing error), otherwise expand to a static assertion error messaging the +// decl that remained unparsed. +#define BOOST_CONTRACT_AUX_INVOKE_OR_ERROR(d, r, id, tpl, orig_decl, \ + parsed_decltraits, macro) \ + BOOST_PP_IIF(BOOST_CONTRACT_EXT_PP_IS_NIL_FRONT(BOOST_PP_TUPLE_ELEM(2, 0, \ + parsed_decltraits)), \ + BOOST_CONTRACT_AUX_INVOKE_OR_ERROR_NO_ \ + , \ + BOOST_CONTRACT_AUX_INVOKE_OR_ERROR_YES_ \ + )(d, r, id, tpl, orig_decl, parsed_decltraits, macro) + +/* PRIVATE */ + +#define BOOST_CONTRACT_AUX_INVOKE_OR_ERROR_NO_(d, r, id, tpl, orig_decl, \ + parsed_decltraits, macro) \ + macro(d, r, id, tpl, BOOST_PP_TUPLE_ELEM(2, 1, parsed_decltraits)) + +// Static assertion must be used because there is portable way to report an +// error with a description message using a preprocessor macro expansion +// (because macros cannot expand and therefore use #error). +#define BOOST_CONTRACT_AUX_INVOKE_OR_ERROR_YES_(d, r, id, tpl, orig_decl, \ + parsed_decltraits, macro) \ + BOOST_STATIC_ASSERT_MSG( \ + false, \ + "unable to complete parsing of declaration '" \ + BOOST_PP_STRINGIZE(orig_decl) "', parsed only up until '" \ + BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(2, 0, parsed_decltraits)) "'" \ + ) + +#endif // #include guard + diff --git a/include/boost/contract/aux_/code/params.hpp b/include/boost/contract/aux_/code/params.hpp new file mode 100644 index 0000000..b8413d2 --- /dev/null +++ b/include/boost/contract/aux_/code/params.hpp @@ -0,0 +1,115 @@ + +#ifndef BOOST_CONTRACT_AUX_PARAMS_HPP_ +#define BOOST_CONTRACT_AUX_PARAMS_HPP_ + +#include +#include // p +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* PUBLIC */ + +#define BOOST_CONTRACT_AUX_PP_PARAM_INDEXED_NAME(i) \ + BOOST_CONTRACT_AUX_NAME2(arg, i) + +// Types, names, and default arguments (for usual declarations, etc.). +// If not EMPTY(), extra_params decl pp-tuple is appended at param list's end. +#define BOOST_CONTRACT_AUX_PARAMS_WITH_DEFAULTS_D_R(d, r, id, tpl, \ + params_traits, extra_params) \ + BOOST_CONTRACT_AUX_PARAMS_(d, r, id, tpl, params_traits, extra_params, \ + (0, 1, 1, 0, 1)) + +#define BOOST_CONTRACT_AUX_TEMPLATE_PARAMS_WITH_DEFAULTS_D_R(d, r, id, tpl, \ + params_traits, extra_params) \ + BOOST_CONTRACT_AUX_PARAMS_(d, r, id, tpl, params_traits, extra_params, \ + (1, 1, 1, 0, 1)) + +/* PRIVATE */ + +#define BOOST_CONTRACT_AUX_PARAMS_(d, r, id, tpl, params_traits, extras, \ + template_type_named_indexed_default) \ + BOOST_PP_IIF(BOOST_CONTRACT_EXT_PP_IS_EMPTY(params_traits), \ + BOOST_PP_TUPLE_EAT(3) \ + , \ + BOOST_PP_SEQ_FOR_EACH_I_R \ + )(r, BOOST_CONTRACT_AUX_PARAM_, template_type_named_indexed_default, \ + params_traits) \ + BOOST_PP_IIF(BOOST_CONTRACT_EXT_PP_IS_EMPTY(extras), \ + BOOST_PP_TUPLE_EAT(1) \ + , \ + BOOST_CONTRACT_AUX_PARAMS_EXTRAS_ \ + )(extras) + +#define BOOST_CONTRACT_AUX_PARAMS_EXTRAS_(extras) \ + , BOOST_PP_TUPLE_REM_CTOR(extras) + +#define BOOST_CONTRACT_AUX_PARAM_(r, \ + template_type_named_indexed_default, i, p) \ + BOOST_CONTRACT_AUX_PARAM_ARGS_(r, i, p, \ + BOOST_PP_TUPLE_ELEM(5, 0, template_type_named_indexed_default), \ + BOOST_PP_TUPLE_ELEM(5, 1, template_type_named_indexed_default), \ + BOOST_PP_TUPLE_ELEM(5, 2, template_type_named_indexed_default), \ + BOOST_PP_TUPLE_ELEM(5, 3, template_type_named_indexed_default), \ + BOOST_PP_TUPLE_ELEM(5, 4, template_type_named_indexed_default) \ + ) + +#define BOOST_CONTRACT_AUX_PARAM_ARGS_(r, i, p, \ + is_template, has_type, has_name, has_index, has_default) \ + BOOST_PP_COMMA_IF(i) \ + BOOST_PP_IIF(BOOST_PP_COMPL(has_type), \ + BOOST_PP_TUPLE_EAT(1) \ + , BOOST_PP_IIF(is_template, \ + BOOST_CONTRACT_AUX_TEMPLATE_PARAM_TYPE_ \ + , \ + BOOST_CONTRACT_AUX_PARAM_TYPE_ \ + ))(p) \ + BOOST_PP_IIF(has_name, \ + BOOST_CONTRACT_AUX_PARAM_NAME_ \ + , BOOST_PP_IIF(has_index, \ + BOOST_CONTRACT_AUX_PARAM_INDEXED_NAME_ \ + , \ + BOOST_PP_TUPLE_EAT(1) \ + ))(p, i) \ + BOOST_PP_IIF(has_default, \ + BOOST_CONTRACT_AUX_PARAM_DEFAULT_ \ + , \ + BOOST_PP_TUPLE_EAT(1) \ + )(p) + +#define BOOST_CONTRACT_AUX_PARAM_TYPE_(p) \ + BOOST_PP_TUPLE_REM_CTOR(BOOST_CONTRACT_EXT_PP_PARAM_TRAITS_TYPE(p)) + +#define BOOST_CONTRACT_AUX_TEMPLATE_PARAM_TYPE_(p) \ + BOOST_PP_IIF(BOOST_CONTRACT_EXT_PP_KEYWORD_IS_TEMPLATE_FRONT( \ + BOOST_CONTRACT_EXT_PP_PARAM_TRAITS_TYPE(p)), \ + BOOST_CONTRACT_AUX_TEMPLATE_PARAM_TEMPLATE_ \ + , \ + BOOST_CONTRACT_EXT_PP_UNPARENTHESIZE \ + )(BOOST_CONTRACT_EXT_PP_PARAM_TRAITS_TYPE(p)) + +#define BOOST_CONTRACT_AUX_TEMPLATE_PARAM_TEMPLATE_(type) \ + template< BOOST_PP_TUPLE_REM_CTOR( \ + BOOST_CONTRACT_EXT_PP_TEMPLATE_PARAM_TRAITS_TYPE_TEMPLATE_PARAMS(type) \ + ) > BOOST_CONTRACT_EXT_PP_TEMPLATE_PARAM_TRAITS_TYPE_TEMPLATE_KEY(type) + +#define BOOST_CONTRACT_AUX_PARAM_NAME_(p, i) \ + BOOST_CONTRACT_EXT_PP_PARAM_TRAITS_NAME(p) + +#define BOOST_CONTRACT_AUX_PARAM_INDEXED_NAME_(p, i) \ + BOOST_CONTRACT_AUX_PP_PARAM_INDEXED_NAME(i) + +#define BOOST_CONTRACT_AUX_PARAM_DEFAULT_(p) \ + BOOST_PP_EXPR_IIF(BOOST_PP_COMPL(BOOST_CONTRACT_EXT_PP_IS_EMPTY( \ + BOOST_CONTRACT_EXT_PP_PARAM_TRAITS_DEFAULT(p))), \ + = BOOST_PP_TUPLE_REM(0) \ + ) BOOST_CONTRACT_EXT_PP_PARAM_TRAITS_DEFAULT(p) + +#endif // #include guard + diff --git a/include/boost/contract/aux_/eval.hpp b/include/boost/contract/aux_/eval.hpp new file mode 100644 index 0000000..d38d2c4 --- /dev/null +++ b/include/boost/contract/aux_/eval.hpp @@ -0,0 +1,24 @@ + +#ifndef BOOST_CONTRACT_AUX_EVAL_HPP_ +#define BOOST_CONTRACT_AUX_EVAL_HPP_ + +namespace boost { namespace contract { namespace aux { + +// Used to force evaluation of expressions before a class is constructed: +// +// struct x : private eval, ... { +// x ( ) : eval((expr1, expr2, expr3, ...)), ... { ... } +// ... +// }; +template< class Derived > +struct eval { + eval ( ) {} + + template< typename Expr > + explicit eval ( Expr const& ) {} +}; + +} } } // namespace + +#endif // #include guard + diff --git a/include/boost/contract/aux_/name.hpp b/include/boost/contract/aux_/name.hpp new file mode 100644 index 0000000..97d76bf --- /dev/null +++ b/include/boost/contract/aux_/name.hpp @@ -0,0 +1,23 @@ + +#ifndef BOOST_CONTRACT_AUX_NAME_HPP_ +#define BOOST_CONTRACT_AUX_NAME_HPP_ + +#include + +/* PUBLIC */ + +// IMPORTANT: Cannot use '_' infix to prevent forming reserved C++ names +// (containing "__" if user `name` starts/ends with '_' already) so using 'X'. + +// NOTE: Explicitly list number of names to concatenate using ..._NAME-n +// (instead of using ..._SEQ_CAT or similar) for optimal speed and reentrancy. + +#define BOOST_CONTRACT_AUX_NAME1(name1) \ + BOOST_PP_CAT(boost_contract_auxX, name1) + +#define BOOST_CONTRACT_AUX_NAME2(name1, name2) \ + BOOST_PP_CAT(boost_contract_auxX, BOOST_PP_CAT(name1, BOOST_PP_CAT(X, \ + name2))) + +#endif // #include guard + diff --git a/include/boost/contract/class.hpp b/include/boost/contract/class.hpp new file mode 100644 index 0000000..7aa39b6 --- /dev/null +++ b/include/boost/contract/class.hpp @@ -0,0 +1,22 @@ + +#ifndef BOOST_CONTRACT_CLASS_HPP_ +#define BOOST_CONTRACT_CLASS_HPP_ + +#include +#include +#include // c + +/* PUBLIC */ + +#define BOOST_CONTRACT_CLASS(decl) \ + BOOST_CONTRACT_CLASS_D_R(1, 1, __LINE__, 0, decl) + +#define BOOST_CONTRACT_CLASS_D_R(d, r, id, tpl, decl) \ + BOOST_CONTRACT_AUX_INVOKE_OR_ERROR(d, r, id, tpl, \ + decl, \ + BOOST_CONTRACT_EXT_PP_CLASS_TRAITS_PARSE_D(d, decl), \ + BOOST_CONTRACT_AUX_CLASS_D_R \ + ) + +#endif // #include guard + diff --git a/include/boost/contract/class_invariant.hpp b/include/boost/contract/class_invariant.hpp new file mode 100644 index 0000000..f4a6954 --- /dev/null +++ b/include/boost/contract/class_invariant.hpp @@ -0,0 +1,16 @@ + +#ifndef BOOST_CONTRACT_CLASS_INVARIANT_HPP_ +#define BOOST_CONTRACT_CLASS_INVARIANT_HPP_ + +/* PUBLIC */ + +#define BOOST_CONTRACT_CLASS_INVARIANT_TPL(...) \ + BOOST_CONTRACT_CLASS_INVARIANT_(0, __VA_ARGS__) + +/* PRIVATE */ + +#define BOOST_CONTRACT_CLASS_INVARIANT_(is_template, ...) \ + }; + +#endif // #include guard + diff --git a/include/boost/contract/ext_/preprocessor/keyword/utility/is.hpp b/include/boost/contract/ext_/preprocessor/keyword/utility/is.hpp index cb19a0a..331eb8c 100644 --- a/include/boost/contract/ext_/preprocessor/keyword/utility/is.hpp +++ b/include/boost/contract/ext_/preprocessor/keyword/utility/is.hpp @@ -25,10 +25,11 @@ // #defined to expand to `,`. // Precondition: tokens must start with a token concatenable to a macro name // (e.g., a literal or integral token) or with parenthesis (i.e., -// leading parenthesis are allowed). +// leading parenthesis are allowed). tokens can be EMPTY() +// (trailing handles that). #define BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS_FRONT( \ cat_to_comma_prefix, tokens) \ - BOOST_PP_IIF(BOOST_CONTRACT_EXT_PP_HAS_PAREN(tokens), \ + BOOST_PP_IIF(BOOST_CONTRACT_EXT_PP_HAS_PAREN(tokens BOOST_PP_NIL), \ 0 BOOST_PP_TUPLE_EAT(2) \ , \ BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS_CHECK_ \ diff --git a/include/boost/contract/ext_/preprocessor/paren/has.hpp b/include/boost/contract/ext_/preprocessor/paren/has.hpp index b562433..cea1054 100644 --- a/include/boost/contract/ext_/preprocessor/paren/has.hpp +++ b/include/boost/contract/ext_/preprocessor/paren/has.hpp @@ -21,7 +21,8 @@ /* PUBLIC */ -// Adapted from BOOST_PP_IS_UNARY but for variadic macros. +// NOTE: tokens can be EMPTY() (because of the variadic CHECK(...) above). +// Implementation: Adapted from BOOST_PP_IS_UNARY but for variadic macros. #define BOOST_CONTRACT_EXT_PP_HAS_PAREN(tokens) \ BOOST_PP_CHECK(tokens, BOOST_CONTRACT_EXT_PP_HAS_PAREN_CHECK) diff --git a/include/boost/contract/ext_/preprocessor/parenthesize.hpp b/include/boost/contract/ext_/preprocessor/parenthesize.hpp index 706e529..845d1e0 100644 --- a/include/boost/contract/ext_/preprocessor/parenthesize.hpp +++ b/include/boost/contract/ext_/preprocessor/parenthesize.hpp @@ -3,12 +3,22 @@ #define BOOST_CONTRACT_EXT_PP_PARENTHESIZE_HPP_ #include +#include #include /* PUBLIC */ +// NOTE: tokens can be EMPTY(). #define BOOST_CONTRACT_EXT_PP_PARENTHESIZE(tokens) \ BOOST_PP_IIF(BOOST_CONTRACT_EXT_PP_HAS_PAREN(tokens), tokens, (tokens)) +// NOTE: tokens can be EMPTY(). +#define BOOST_CONTRACT_EXT_PP_UNPARENTHESIZE(tokens) \ + BOOST_PP_IIF(BOOST_CONTRACT_EXT_PP_HAS_PAREN(tokens), \ + BOOST_PP_TUPLE_REM_CTOR \ + , \ + BOOST_PP_TUPLE_REM(1) \ + )(tokens) + #endif // #include guard diff --git a/include/boost/contract/ext_/preprocessor/traits/base/type.hpp b/include/boost/contract/ext_/preprocessor/traits/base/type.hpp index 2f1ea13..b14464b 100644 --- a/include/boost/contract/ext_/preprocessor/traits/base/type.hpp +++ b/include/boost/contract/ext_/preprocessor/traits/base/type.hpp @@ -11,7 +11,7 @@ /* PUBLIC */ -// Expand to `(,,,)`. +// Expand to `(,,,)`, for example: `(vector)` or `(map)`. #define BOOST_CONTRACT_EXT_PP_BASE_TRAITS_TYPE(traits) \ BOOST_CONTRACT_EXT_PP_TRAITS_AUX_ELEM( \ BOOST_CONTRACT_EXT_PP_TRAITS_AUX_INDEX_BASE_TYPE, traits) diff --git a/include/boost/contract/ext_/preprocessor/traits/class/specialization.hpp b/include/boost/contract/ext_/preprocessor/traits/class/specialization.hpp index 4fad225..591c98f 100644 --- a/include/boost/contract/ext_/preprocessor/traits/class/specialization.hpp +++ b/include/boost/contract/ext_/preprocessor/traits/class/specialization.hpp @@ -12,7 +12,7 @@ /* PUBLIC */ -// Expand to `(,,,) | EMPTY()`. +// Expand to `(,,,) | EMPTY()`, for example `(int, std::map)`. #define BOOST_CONTRACT_EXT_PP_CLASS_TRAITS_SPECIALIZATION(traits) \ BOOST_CONTRACT_EXT_PP_TRAITS_AUX_ELEM( \ BOOST_CONTRACT_EXT_PP_TRAITS_AUX_INDEX_CLASS_SPECIALIZATION, \ diff --git a/include/boost/contract/ext_/preprocessor/traits/class/verbatim.hpp b/include/boost/contract/ext_/preprocessor/traits/class/verbatim.hpp index c2bdde1..c42f9c0 100644 --- a/include/boost/contract/ext_/preprocessor/traits/class/verbatim.hpp +++ b/include/boost/contract/ext_/preprocessor/traits/class/verbatim.hpp @@ -10,7 +10,7 @@ /* PUBLIC */ -// Expand to `(,,,) | EMPTY()`. +// Expand to `(,,,) | EMPTY()`, for example: `(__declspec(dllexport))`. #define BOOST_CONTRACT_EXT_PP_CLASS_TRAITS_VERBATIM(traits) \ BOOST_CONTRACT_EXT_PP_TRAITS_AUX_ELEM( \ BOOST_CONTRACT_EXT_PP_TRAITS_AUX_INDEX_CLASS_VERBATIM, traits)() diff --git a/include/boost/contract/ext_/preprocessor/traits/func/ref.hpp b/include/boost/contract/ext_/preprocessor/traits/func/ref.hpp index 2c6ef74..fcc7361 100644 --- a/include/boost/contract/ext_/preprocessor/traits/func/ref.hpp +++ b/include/boost/contract/ext_/preprocessor/traits/func/ref.hpp @@ -10,6 +10,14 @@ /* PUBLIC */ +#define BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_IS_REF_REF(tokens) \ + BOOST_PP_IIF(BOOST_CONTRACT_EXT_PP_KEYWORD_IS_REF_FRONT( \ + tokens), \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_IS_REF_REF_MAYBE_ \ + , \ + 0 BOOST_PP_TUPLE_EAT(1) \ + )(tokens) + // Expand to `ref | ref ref | EMPTY()` (ref for lvalue&, ref ref for rvalue&&). #define BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_REF(traits) \ BOOST_CONTRACT_EXT_PP_TRAITS_AUX_ELEM( \ @@ -22,6 +30,11 @@ /* PRIVATE */ +// Precondition: tokens = `ref ...`. +#define BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_IS_REF_REF_MAYBE_(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_IS_REF_FRONT( \ + BOOST_CONTRACT_EXT_PP_KEYWORD_REF_REMOVE_FRONT(tokens)) + #define BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_REF_PARSE_ARGS_(decl, traits) \ BOOST_PP_IIF( \ BOOST_CONTRACT_EXT_PP_KEYWORD_IS_REF_FRONT(decl), \ diff --git a/include/boost/contract/ext_/preprocessor/traits/func/return.hpp b/include/boost/contract/ext_/preprocessor/traits/func/return.hpp index 517cce0..75c9779 100644 --- a/include/boost/contract/ext_/preprocessor/traits/func/return.hpp +++ b/include/boost/contract/ext_/preprocessor/traits/func/return.hpp @@ -14,13 +14,13 @@ /* PUBLIC */ -// Expand to `result_type | void | auto | EMPTY()` (`auto` for alternative -// function syntax, see also `..._TRAILING_RETURN`). +// Expand to `(,,,) | auto | EMPTY()` (`auto` for alternative function syntax, +// see also `..._TRAILING_RETURN`), for example: `(void)`, `(map)`. #define BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_RETURN(traits) \ BOOST_CONTRACT_EXT_PP_TRAITS_AUX_ELEM( \ BOOST_CONTRACT_EXT_PP_TRAITS_AUX_INDEX_FUNC_RETURN, traits)() -// Expand to `result_type | void | EMPTY()`. +// Expand to `(,,,) | EMPTY()`. #define BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_TRAILING_RETURN(traits) \ BOOST_CONTRACT_EXT_PP_TRAITS_AUX_ELEM( \ BOOST_CONTRACT_EXT_PP_TRAITS_AUX_INDEX_FUNC_TRAILING_RETURN, traits \ diff --git a/include/boost/contract/ext_/preprocessor/traits/param/default.hpp b/include/boost/contract/ext_/preprocessor/traits/param/default.hpp index 87b3170..1b72873 100644 --- a/include/boost/contract/ext_/preprocessor/traits/param/default.hpp +++ b/include/boost/contract/ext_/preprocessor/traits/param/default.hpp @@ -11,7 +11,7 @@ /* PUBLIC */ -// Expand to `(,,,) | EMPTY()`. +// Expand to `(,,,) | EMPTY()`, for example: `(true)` or `(same::value)`. #define BOOST_CONTRACT_EXT_PP_PARAM_TRAITS_DEFAULT(traits) \ BOOST_CONTRACT_EXT_PP_TRAITS_AUX_ELEM( \ BOOST_CONTRACT_EXT_PP_TRAITS_AUX_INDEX_PARAM_DEFAULT, traits)() diff --git a/include/boost/contract/ext_/preprocessor/variadic/wrap_iif.hpp b/include/boost/contract/ext_/preprocessor/variadic/wrap_iif.hpp new file mode 100644 index 0000000..e25ad70 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/variadic/wrap_iif.hpp @@ -0,0 +1,16 @@ + +#ifndef BOOST_CONTRACT_EXT_PP_VARIADIC_WRAP_IIF_HPP_ +#define BOOST_CONTRACT_EXT_PP_VARIADIC_WRAP_IIF_HPP_ + +#include + +/* PUBLIC */ + +// Expand to `prefix ,,, postfix` if bit is 1, or to `,,,` if bit is 0 (where +// `prefix`, `,,,`, and `postfix` can all be EMTPY()). +#define BOOST_CONTRACT_EXT_PP_VARIADIC_WRAP_IIF(bit, prefix, postfix, ...) \ + BOOST_PP_TUPLE_REM_CTOR(BOOST_PP_IIF(bit, \ + (prefix __VA_ARGS__ postfix), (__VA_ARGS__))) + +#endif // #include guard + diff --git a/include/boost/contract/function.hpp b/include/boost/contract/function.hpp new file mode 100644 index 0000000..6fc55a1 --- /dev/null +++ b/include/boost/contract/function.hpp @@ -0,0 +1,25 @@ + +#ifndef BOOST_CONTRACT_FUNCTION_HPP_ +#define BOOST_CONTRACT_FUNCTION_HPP_ + +#include +#include +#include // f + +/* PUBLIC */ + +#define BOOST_CONTRACT_FUNCTION(decl) \ + BOOST_CONTRACT_FUNCTION_D_R(1, 1, __LINE__, 0, decl) + +#define BOOST_CONTRACT_FUNCTION_TPL(decl) \ + BOOST_CONTRACT_FUNCTION_D_R(1, 1, __LINE__, 1, decl) + +#define BOOST_CONTRACT_FUNCTION_D_R(d, r, id, tpl, decl) \ + BOOST_CONTRACT_AUX_INVOKE_OR_ERROR(d, r, id, tpl, \ + decl, \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_PARSE_D(d, decl), \ + BOOST_CONTRACT_AUX_FUNC_D_R \ + ) + +#endif // #include guard + diff --git a/include/boost/contract/oldof.hpp b/include/boost/contract/oldof.hpp index cce56c0..9bfe009 100644 --- a/include/boost/contract/oldof.hpp +++ b/include/boost/contract/oldof.hpp @@ -4,6 +4,8 @@ #include +/* PUBLIC */ + #define BOOST_CONTRACT_OLDOF \ BOOST_CONTRACT_EXT_PP_OLDOF_ASSERTION_TRAITS_OPERATOR diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 7d2b04b..55fc53c 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -59,3 +59,5 @@ test-pp pp_class_traits specialization ; test-pp pp_class_traits virt ; test-pp pp_class_traits bases ; +test-pp code class ; + diff --git a/test/code/class.cpp b/test/code/class.cpp new file mode 100644 index 0000000..d0dfe3e --- /dev/null +++ b/test/code/class.cpp @@ -0,0 +1,30 @@ + +#include +#include + +template< typename T, class Alloc > +struct pushable { + virtual ~pushable ( ) { } + virtual void push_back ( T const& value ) = 0; +}; + +BOOST_CONTRACT_CLASS( + template( typename T, class Alloc, default std::allocator ) + class (vector) extends( public (pushable) ) +) { + BOOST_CONTRACT_CLASS_INVARIANT_TPL() + + BOOST_CONTRACT_FUNCTION_TPL( + public void (push_back) ( (T const&) value ) + ) { + vector_.push_back(value); + } + +private: + std::vector vector_; +} + +int main ( ) { + return 0; +} +