diff options
Diffstat (limited to 'boost/contract/call_if.hpp')
-rw-r--r-- | boost/contract/call_if.hpp | 617 |
1 files changed, 617 insertions, 0 deletions
diff --git a/boost/contract/call_if.hpp b/boost/contract/call_if.hpp new file mode 100644 index 0000000000..7d7586cbfb --- /dev/null +++ b/boost/contract/call_if.hpp @@ -0,0 +1,617 @@ + +#ifndef BOOST_CONTRACT_CALL_IF_HPP_ +#define BOOST_CONTRACT_CALL_IF_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 +Statically disable compilation and execution of functor calls. + +@note This facility allows to emulate C++17 <c>if constexpr</c> statements + when used together with functor templates (or C++14 generic lambdas). +*/ + +#include <boost/contract/detail/none.hpp> +#include <boost/make_shared.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/utility/enable_if.hpp> +#include <boost/config.hpp> + +/* PRIVATE */ + +/** @cond */ + +// Boost.ResultOf not always able to deduce lambda result type (on MSVC). +#ifndef BOOST_NO_CXX11_DECLTYPE + #include <boost/utility/declval.hpp> + #define BOOST_CONTRACT_CALL_IF_RESULT_OF_(F) \ + decltype(boost::declval<F>()()) +#else + #include <boost/utility/result_of.hpp> + #define BOOST_CONTRACT_CALL_IF_RESULT_OF_(F) \ + typename boost::result_of<F()>::type +#endif + +/** @endcond */ + +/* CODE */ + +namespace boost { namespace contract { + +/** +Select compilation and execution of functor template calls using a static +boolean predicate. + +This class template has no members because it is never used directly, it is only +used via its specializations. +Usually this class template is instantiated only via the return value of +@RefFunc{boost::contract::call_if} and @RefFunc{boost::contract::call_if_c}. + +@see @RefSect{extras.assertion_requirements__templates_, + Assertion Requirements} + +@tparam Pred Static boolean predicate that selects which functor template + call to compile and execute. +@tparam Then Type of the functor template to call if the static predicate + @c Pred is @c true. +@tparam ThenResult Return type of then-branch functor template call (this is + usually automatically deduced by this library so it is never explicitly + specified by the user, and that is why it is often marked as + @c internal_type in this documentation). +*/ +template<bool Pred, typename Then, typename ThenResult = + #ifndef BOOST_CONTRACT_DETAIL_DOXYGEN + boost::contract::detail::none + #else + internal_type + #endif +> +struct call_if_statement {}; // Empty so cannot be used (but copyable). + +/** +Template specialization to dispatch between then-branch functor template calls +that return void and the ones that return non-void. + +The base class is a call-if statement so the else and else-if statements can be +specified if needed. +Usually this class template is instantiated only via the return value of +@RefFunc{boost::contract::call_if} and @RefFunc{boost::contract::call_if_c}. + +@note The <c>result_of<Then()>::type</c> expression should be evaluated only + when the static predicate is already checked to be @c true (because + @c Then() is required to compile only in that case). + Thus, this template specialization introduces an extra level of + indirection necessary for proper lazy evaluation of this result-of + expression. + +@see @RefSect{extras.assertion_requirements__templates_, + Assertion Requirements} + +@tparam Then Type of functor template to call when the static predicate is + @c true (as it is for this template specialization). +*/ +template<typename Then> +struct call_if_statement<true, Then, + #ifndef BOOST_CONTRACT_DETAIL_DOXYGEN + boost::contract::detail::none + #else + internal_type + #endif +> : + call_if_statement<true, Then, + #ifndef BOOST_CONTRACT_DETAIL_DOXYGEN + BOOST_CONTRACT_CALL_IF_RESULT_OF_(Then) + #else + typename result_of<Then()>::type + #endif + > +{ // Copyable (as its base). + /** + Construct this object with the then-branch functor template. + + @param f Then-branch nullary functor template. + The functor template call @c f() is compiled and called for this + template specialization (because the if-statement static + predicate is @c true). + The return type of @c f() must be the same as (or implicitly + convertible to) the return type of all other functor template + calls specified for this call-if object. + */ + explicit call_if_statement(Then f) : call_if_statement<true, Then, + BOOST_CONTRACT_CALL_IF_RESULT_OF_(Then)>(f) {} +}; + +/** +Template specialization to handle static predicates that are @c true for +then-branch functor template calls that do not return void. + +Usually this class template is instantiated only via the return value of +@RefFunc{boost::contract::call_if} and @RefFunc{boost::contract::call_if_c}. + +@see @RefSect{extras.assertion_requirements__templates_, + Assertion Requirements} + +@tparam Then Type of functor template to call when the static predicate is + @c true (as it is for this template specialization). +@tparam ThenResult Non-void return type of the then-branch functor template + call. +*/ +template<typename Then, typename ThenResult> +struct call_if_statement<true, Then, ThenResult> { // Copyable (as *). + /** + Construct this object with the then-branch functor template. + + @param f Then-branch nullary functor template. + The functor template call @c f() is actually compiled and + executed for this template specialization (because the + if-statement static predicate is @c true). + The return type of @c f() must be the same as (or implicitly + convertible to) the @p ThenResult type. + */ + explicit call_if_statement(Then f) : + r_(boost::make_shared<ThenResult>(f())) {} + + /** + This implicit type conversion returns a copy of the value returned by the + call to the then-branch functor template. + */ + operator ThenResult() const { return *r_; } + + /** + Specify the else-branch functor template. + + @param f Else-branch nullary functor template. + The functor template call @c f() is never compiled and executed + for this template specialization (because the if-statement + static predicate is @c true). + The return type of @c f() must be the same as (or implicitly + convertible to) the @p ThenResult type. + + @return A copy of the value returned by the call to the then-branch functor + template (because the else-branch functor template call is not + executed). + */ + template<typename Else> + ThenResult else_(Else const& f) const { return *r_; } + + /** + Specify an else-if-branch functor template (using a static boolean + predicate). + + @param f Else-if-branch nullary functor template. + The functor template call @c f() is never compiled and executed + for this template specialization (because the if-statement + static predicate is @c true). + The return type of @c f() must be the same as (or implicitly + convertible to) the @p ThenResult type. + + @tparam ElseIfPred Static boolean predicate selecting which functor + template call to compile and execute. + + @return A call-if statement so the else statement and additional else-if + statements can be specified if needed. + Eventually, it will be the return value of the then-branch functor + template call for this template specialization (because the + if-statement static predicate is @c true). + */ + template<bool ElseIfPred, typename ElseIfThen> + call_if_statement<true, Then, ThenResult> else_if_c(ElseIfThen const& f) + const { return *this; } + + /** + Specify an else-if-branch functor template (using a nullary boolean + meta-function). + + @param f Else-if-branch nullary functor template. + The functor template call @c f() is never compiled and executed + for this template specialization (because the if-statement + static predicate is @c true). + The return type of @c f() must be the same as (or implicitly + convertible to) the @p ThenResult type. + + @tparam ElseIfPred Nullary boolean meta-function selecting which functor + template call to compile and execute. + + @return A call-if statement so the else statement and additional else-if + statements can be specified if needed. + Eventually, it will be the return value of the then-branch functor + template call for this template specialization (because the + if-statement static predicate is @c true). + */ + template<class ElseIfPred, typename ElseIfThen> + call_if_statement<true, Then, ThenResult> else_if(ElseIfThen const& f) + const { return *this; } + +private: + boost::shared_ptr<ThenResult> r_; +}; + +/** +Template specialization to handle static predicates that are @c true for +then-branch functor template calls that return void. + +Usually this class template is instantiated only via the return value of +@RefFunc{boost::contract::call_if} and @RefFunc{boost::contract::call_if_c}. + +@see @RefSect{extras.assertion_requirements__templates_, + Assertion Requirements} + +@tparam Then Type of functor template to call when the static predicate if + @c true (as it is for this template specialization). +*/ +template<typename Then> +struct call_if_statement<true, Then, void> { // Copyable (no data). + /** + Construct this object with the then-branch functor template. + + @param f Then-branch nullary functor template. + The functor template call @c f() is actually compiled and + executed for this template specialization (because the + if-statement static predicate is @c true). + The return type of @c f() must be @c void for this template + specialization (because the then-branch functor template calls + return void). + */ + explicit call_if_statement(Then f) { f(); } + + // Cannot provide `operator ThenResult()` here, because ThenResult is void. + + /** + Specify the else-branch functor template. + + @param f Else-branch nullary functor template. + The functor template call @c f() is never compiled and executed + for this template specialization (because the if-statement + static predicate is @c true). + The return type of @c f() must be @c void for this template + specialization (because the then-branch functor template calls + return void). + */ + template<typename Else> + void else_(Else const& f) const {} + + /** + Specify an else-if-branch functor template (using a static boolean + predicate). + + @param f Else-if-branch nullary functor template. + The functor template call @c f() is never compiled and executed + for this template specialization (because the if-statement + static predicate is @c true). + The return type of @c f() must be @c void for this template + specialization (because the then-branch functor template calls + return void). + + @tparam ElseIfPred Static boolean predicate selecting which functor + template call to compile and execute. + + @return A call-if statement so the else statement and additional else-if + statements can be specified if needed. + Eventually, it will return void for this template specialization + (because the then-branch functor template calls return void). + */ + template<bool ElseIfPred, typename ElseIfThen> + call_if_statement<true, Then, void> else_if_c(ElseIfThen const& f) const { + return *this; + } + + /** + Specify an else-if-branch functor template (using a nullary boolean + meta-function). + + @param f Else-if-branch nullary functor template. + The functor template call @c f() is never compiled and executed + for this template specialization (because the if-statement + static predicate is @c true). + The return type of @c f() must be @c void for this template + specialization (because the then-branch functor template calls + return void). + + @tparam ElseIfPred Nullary boolean meta-function selecting which functor + template call to compile and execute. + + @return A call-if statement so the else statement and additional else-if + statements can be specified if needed. + Eventually, it will return void for this template specialization + (because the then-branch functor template calls return void). + */ + template<class ElseIfPred, typename ElseIfThen> + call_if_statement<true, Then, void> else_if(ElseIfThen const& f) const { + return *this; + } +}; + +/** +Template specialization to handle static predicates that are @c false. + +This template specialization handles all else-branch functor template calls +(whether they return void or not). +Usually this class template is instantiated only via the return value of +@RefFunc{boost::contract::call_if} and @RefFunc{boost::contract::call_if_c}. + +@see @RefSect{extras.assertion_requirements__templates_, + Assertion Requirements} + +@tparam Then Type of functor template to call when the static predicate is + @c true (never the case for this template specialization). +*/ +template<typename Then> // Copyable (no data). +struct call_if_statement<false, Then, + #ifndef BOOST_CONTRACT_DETAIL_DOXYGEN + boost::contract::detail::none + #else + internal_type + #endif +> { + /** + Construct this object with the then-branch functor template. + + @param f Then-branch nullary functor template. + The functor template call @c f() is never compiled and executed + for this template specialization (because the if-statement + static predicate is @c false). + The return type of @c f() must be the same as (or implicitly + convertible to) the return type of all other functor template + calls specified for this call-if object. + */ + explicit call_if_statement(Then const& f) {} + + // Do not provide `operator result_type()` here, require else_ instead. + + /** + Specify the else-branch functor template. + + @note The <c>result_of<Else()>::type</c> expression should be evaluated + only when the static predicate is already checked to be @c false + (because @c Else() is required to compile only in that case). + Thus, this result-of expression is evaluated lazily only in + instantiations of this template specialization. + + @param f Else-branch nullary functor template. + The functor template call @c f() is actually compiled and + executed for this template specialization (because the + if-statement static predicate is @c false). + The return type of @c f() must be the same as (or implicitly + convertible to) the return type of all other functor template + calls specified for this call-if object. + + @return A copy of the value returned by the call to the else-branch functor + template @c f(). + */ + template<typename Else> + #ifndef BOOST_CONTRACT_DETAIL_DOXYGEN + BOOST_CONTRACT_CALL_IF_RESULT_OF_(Else) + #else + typename result_of<Else()>::type + #endif + else_(Else f) const { return f(); } + + /** + Specify an else-if-branch functor template (using a static boolean + predicate). + + @param f Else-if-branch nullary functor template. + The functor template call @c f() is actually compiled and + executed if and only if @c ElseIfPred is @c true (because the + if-statement static predicate is already @c false for this + template specialization). + The return type of @c f() must be the same as (or implicitly + convertible to) the return type of all other functor template + calls specified for this call-if object. + + @tparam ElseIfPred Static boolean predicate selecting which functor + template call to compile and execute. + + @return A call-if statement so the else statement and additional else-if + statements can be specified if needed. + Eventually, this will be the return value of the functor template + call being compiled and executed. + */ + template<bool ElseIfPred, typename ElseIfThen> + call_if_statement<ElseIfPred, ElseIfThen> else_if_c(ElseIfThen f) const { + return call_if_statement<ElseIfPred, ElseIfThen>(f); + } + + /** + Specify an else-if-branch functor template (using a nullary boolen + meta-function). + + @param f Else-if-branch nullary functor template. + The functor template call @c f() is actually compiled and + executed if and only if @c ElseIfPred::value is @c true (because + the if-statement static predicate is already @c false for this + template specialization). + The return type of @c f() must be the same as (or implicitly + convertible to) the return type of all other functor template + calls specified for this call-if object. + + @tparam ElseIfPred Nullary boolean meta-function selecting which functor + template call to compile and execute. + + @return A call-if statement so the else statement and additional else-if + statements can be specified if needed. + Eventually, this will be the return value of the functor template + call being compiled and executed. + */ + template<class ElseIfPred, typename ElseIfThen> + call_if_statement<ElseIfPred::value, ElseIfThen> else_if(ElseIfThen f) + const { + return call_if_statement<ElseIfPred::value, ElseIfThen>(f); + } +}; + +/** +Select compilation and execution of functor template calls using a static +boolean predicate. + +Create a call-if object with the specified then-branch functor template: + +@code +boost::contract::call_if_c<Pred1>( + then_functor_template1 +).template else_if_c<Pred2>( // Optional. + then_functor_template2 +) // Optionally, other `else_if_c` or +... // `else_if`. +.else_( // Optional for `void` functors, + else_functor_template // but required for non `void`. +) +@endcode + +Optional functor templates for else-if-branches and the else-branch can be +specified as needed (the else-branch function template is required if @c f +returns non-void). + +@see @RefSect{extras.assertion_requirements__templates_, + Assertion Requirements} + +@param f Then-branch nullary functor template. + The functor template call @c f() is compiled and executed if and + only if @c Pred is @c true. + The return type of other functor template calls specified for this + call-if statement (else-branch, else-if-branches, etc.) must be the + same as (or implicitly convertible to) the return type of + then-branch functor call @c f(). + +@tparam Pred Static boolean predicate selecting which functor template call + to compile and execute. + +@return A call-if statement so else and else-if statements can be specified if + needed. + Eventually, this will be the return value of the functor template call + being compiled and executed (which can also be @c void). +*/ +template<bool Pred, typename Then> +call_if_statement<Pred, Then> call_if_c(Then f) { + return call_if_statement<Pred, Then>(f); +} + +/** +Select compilation and execution of functor template calls using a nullary +boolean meta-function. + +This is equivalent to <c>boost::contract::call_if_c<Pred::value>(f)</c>. +Create a call-if object with the specified then-branch functor template: + +@code +boost::contract::call_if<Pred1>( + then_functor_template1 +).template else_if<Pred2>( // Optional. + then_functor_template2 +) // Optionally, other `else_if` or +... // `else_if_c`. +.else_( // Optional for `void` functors, + else_functor_template // but required for non `void`. +) +@endcode + +Optional functor templates for else-if-branches and the else-branch can be +specified as needed (the else-branch functor template is required if @c f +returns non-void). + +@see @RefSect{extras.assertion_requirements__templates_, + Assertion Requirements} + +@param f Then-branch nullary functor template. + The functor template call @c f() is compiled and executed if and + only if @c Pred::value is @c true. + The return type of other functor template calls specified for this + call-if statement (else-branch, else-if-branches, etc.) must be the + same as (or implicitly convertible to) the return type of + then-branch functor template call @c f(). + +@tparam Pred Nullary boolean meta-function selecting which functor template + call to compile and execute. + +@return A call-if statement so else and else-if statements can be specified if + needed. + Eventually, this will be the return value of the functor template call + being compiled and executed (which can also be @c void). +*/ +template<class Pred, typename Then> +call_if_statement<Pred::value, Then> call_if(Then f) { + return call_if_statement<Pred::value, Then>(f); +} + +/** +Select compilation and execution of a boolean functor template condition using a +static boolean predicate. + +Compile and execute the nullary boolean functor template call @c f() if and only +if the specified static boolean predicate @p Pred is @c true, otherwise +trivially return @p else_ (@c true by default) at run-time. + +A call to <c>boost::contract::condition_if_c<Pred>(f, else_)</c> is logically +equivalent to +<c>boost::contract::call_if_c<Pred>(f, [else_] { return else_; })</c> (but +its internal implementation is optimized and it does not actually use +@c call_if_c). + +@see @RefSect{extras.assertion_requirements__templates_, + Assertion Requirements} + +@param f Nullary boolean functor template. + The functor template call @c f() is compiled and executed if and + only if @c Pred is @c true. + +@tparam Pred Static boolean predicate selecting when the functor template + call @c f() should be compiled and executed. +@param else_ Boolean value to return when @c Pred is @c false (instead of + compiling and executing the functor template call @c f()). + +@return Boolean value returned by @c f() if the static predicate @c Pred is + @c true. Otherwise, trivially return @p else_. +*/ +#ifdef BOOST_CONTRACT_DETAIL_DOXYGEN + template<bool Pred, typename Then> + bool condition_if_c(Then f, bool else_ = true); +#else + // NOTE: condition_if is a very simple special case of call_if so it can be + // trivially implemented using enable_if instead of call_if as done below. + + template<bool Pred, typename Then> + typename boost::enable_if_c<Pred, bool>::type + condition_if_c(Then f, bool else_ = true) { return f(); } + + template<bool Pred, typename Then> + typename boost::disable_if_c<Pred, bool>::type + condition_if_c(Then f, bool else_ = true) { return else_; } +#endif + +/** +Select compilation and execution of a boolean functor template condition using a +nullary boolean meta-function. + +This is equivalent to +<c>boost::contract::condition_if_c<Pred::value>(f, else_)</c>. +Compile and execute the nullary boolean functor template call @c f() if and only +if the specified nullary boolean meta-function @p Pred is @c true, otherwise +trivially return @p else_ (@c true by default) at run-time. + +@see @RefSect{extras.assertion_requirements__templates_, + Assertion Requirements} + +@param f Nullary boolean functor template. + The functor template call @c f() is compiled and executed if and + only if @c Pred::value is @c true. +@param else_ Boolean value to return when @c Pred::value is @c false (instead + of compiling and executing the functor template call @c f()). + +@tparam Pred Nullary boolean meta-function selecting when the functor + template call @c f() should be compiled and executed. + +@return Boolean value returned by @c f() if the static predicate @c Pred is + @c true. Otherwise, trivially return @p else_. +*/ +template<class Pred, typename Then> +bool condition_if(Then f, bool else_ = true) { + return condition_if_c<Pred::value>(f, else_); +} + +} } // namespace + +#endif // #include guard + |