##// END OF EJS Templates
Some refac for new PySide2 bindings...
Some refac for new PySide2 bindings - made DataSourceItem iterable - added some tree print function for debug - fixed minor bug on DataSourceContorller which prevented from adding products in more than one call per provider - improved IDataProvider for future refac Signed-off-by: Alexis Jeandet <alexis.jeandet@member.fsf.org>

File last commit:

r4:96a6baa9f92b
r92:9ff5f48e3d71
Show More
binop_overload.hpp
308 lines | 13.0 KiB | text/x-c++hdr | CppLexer
#ifndef OPAQUE_BINOP_OVERLOAD_HPP
#define OPAQUE_BINOP_OVERLOAD_HPP
//
// Copyright (c) 2015, 2016
// Kyle Markley. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// 3. Neither the name of the author nor the names of any contributors may be
// used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
#include "../constexpr14.hpp"
#include "../type_traits.hpp"
#include "../utility.hpp"
#include "../convert.hpp"
#include <type_traits>
namespace opaque {
namespace binop {
/// \addtogroup internal
/// @{
///
/// Overloads of binary operators
///
template <typename OP, typename RT, bool apply_commutativity=false,
typename P1=RT, typename P2=RT, typename I1=P1, typename I2=P2>
struct overload;
template <typename OP, typename RT,
typename P1, typename P2, typename I1, typename I2>
struct overload<OP,RT,false,const P1& ,const P2& ,I1,I2> {
// No return type conversion - enable NRVO
template <typename R=RT> static constexpr14
typename std::enable_if< std::is_same<RT,I1>::value, R>::type
func(const P1& p1, const P2& p2, OP op=OP{}) noexcept(
std::is_nothrow_constructible<I1,const P1&>::value and
noexcept(op(std::declval<I1>(), convert<I2>(p2)))) {
I1 temp(p1);
op(temp, convert<I2>(p2));
return temp;
}
// Return type conversion
template <typename R=RT> static constexpr14
typename std::enable_if<not std::is_same<RT,I1>::value, R>::type
func(const P1& p1, const P2& p2, OP op=OP{}) noexcept(
std::is_nothrow_constructible<I1,const P1&>::value and
std::is_nothrow_constructible<RT,I1&&>::value and
noexcept(op(std::declval<I1>(), convert<I2>(p2)))) {
I1 temp(p1);
op(temp, convert<I2>(p2));
return static_cast<RT>(opaque::move(temp));
}
};
template <typename OP, typename RT,
typename P1, typename P2, typename I1, typename I2>
struct overload<OP,RT,false,const P1& , P2&&,I1,I2> {
// No return type conversion - enable NRVO
template <typename R=RT> static constexpr14
typename std::enable_if< std::is_same<RT,I1>::value, R>::type
func(const P1& p1, P2&& p2, OP op=OP{}) noexcept(
std::is_nothrow_constructible<I1,const P1&>::value and
noexcept(op(std::declval<I1>(), convert<I2>(opaque::move(p2))))) {
I1 temp(p1);
op(temp, convert<I2>(opaque::move(p2)));
return temp;
}
// Return type conversion
template <typename R=RT> static constexpr14
typename std::enable_if<not std::is_same<RT,I1>::value, R>::type
func(const P1& p1, P2&& p2, OP op=OP{}) noexcept(
std::is_nothrow_constructible<I1,const P1&>::value and
std::is_nothrow_constructible<RT,I1&&>::value and
noexcept(op(std::declval<I1>(), convert<I2>(opaque::move(p2))))) {
I1 temp(p1);
op(temp, convert<I2>(opaque::move(p2)));
return static_cast<RT>(opaque::move(temp));
}
};
template <typename OP, typename RT,
typename P1, typename P2, typename I1, typename I2>
struct overload<OP,RT,false, P1&&,const P2& ,I1,I2> {
static constexpr RT func( P1&& p1, const P2& p2, OP op=OP{}) noexcept(
noexcept(static_cast<RT>(
op(convert_mutable<I1>(opaque::move(p1)),
convert<I2>( p2 ))))) {
return static_cast<RT>(
op(convert_mutable<I1>(opaque::move(p1)),
convert<I2>( p2 ))); }
};
template <typename OP, typename RT,
typename P1, typename P2, typename I1, typename I2>
struct overload<OP,RT,false, P1&&, P2&&,I1,I2> {
static constexpr RT func( P1&& p1, P2&& p2, OP op=OP{}) noexcept(
noexcept(static_cast<RT>(
op(convert_mutable<I1>(opaque::move(p1)),
convert<I2>( opaque::move(p2)))))) {
return static_cast<RT>(
op(convert_mutable<I1>(opaque::move(p1)),
convert<I2>( opaque::move(p2)))); }
};
template <typename OP, typename RT,
typename P1, typename P2, typename I1, typename I2>
struct overload<OP,RT,true,P1,P2,I1,I2> {
using overload_t = overload<OP,RT,false,P2,P1,I2,I1>;
static constexpr RT func(P1&& p1, P2&& p2, OP op=OP{}) noexcept(
noexcept(overload_t::func(
opaque::forward<P2>(p2), opaque::forward<P1>(p1), op))) {
return overload_t::func(
opaque::forward<P2>(p2), opaque::forward<P1>(p1), op);
}
};
//
// Four flavors of overload are required, but we cannot inherit from the same
// base class more than once (ISO/IEC 14882 �10.1/3). Work around this by
// creating four distinct classes to inherit from.
//
template <typename OP, typename RT, bool apply_commutativity,
typename P1, typename P2, typename I1, typename I2>
struct overload_1 : overload<OP,RT,apply_commutativity,P1,P2,I1,I2> { };
template <typename OP, typename RT, bool apply_commutativity,
typename P1, typename P2, typename I1, typename I2>
struct overload_2 : overload<OP,RT,apply_commutativity,P1,P2,I1,I2> { };
template <typename OP, typename RT, bool apply_commutativity,
typename P1, typename P2, typename I1, typename I2>
struct overload_3 : overload<OP,RT,apply_commutativity,P1,P2,I1,I2> { };
template <typename OP, typename RT, bool apply_commutativity,
typename P1, typename P2, typename I1, typename I2>
struct overload_4 : overload<OP,RT,apply_commutativity,P1,P2,I1,I2> { };
///
/// Conversion costs associated with a binary operation
///
/// The parameter types must reflect the actual types passed to the binary
/// operation, e.g. const T& or T&&. All the other types must be decayed
/// types.
///
template<typename return_type, typename result_type,
typename inter1_type, typename inter2_type,
typename param1_type, typename param2_type>
static constexpr unsigned binop_conversion_cost() noexcept {
static_assert(is_decayed<return_type>::value, "");
static_assert(is_decayed<result_type>::value, "");
static_assert(is_decayed<inter1_type>::value, "");
static_assert(is_decayed<inter2_type>::value, "");
return converter<inter1_type,param1_type>::mutable_cost() +
converter<inter2_type,param2_type>::cost() +
converter<return_type,result_type>::cost();
}
///
/// Select between the regular overload and the commutative alternative
///
/// If the operator is not commutative, use the regular overload.
/// Otherwise, if only one option is well-formed, use that.
/// Otherwise, if both are well-formed, select the lower-cost one.
///
template <bool regular_well_formed, bool swapped_well_formed,
typename OPN, typename RT, bool commutative=false,
typename P1=RT, typename P2=RT, typename I1=P1, typename I2=P2,
typename OPS=OPN>
struct overload_selector {
// overload_selector<false,false,OPN,RT,commutative,P1,P2,I1,I2,OPS>
// --> No overload is well-formed
static_assert( swapped_well_formed, "Operation is not well-formed");
// overload_selector<false,true ,OPN,RT,false,P1,P2,I1,I2,OPS>>
// --> Only swapped overload is well-formed, but we can't use it
static_assert(not swapped_well_formed, "Operation is not commutative");
};
template <typename OPN, typename RT,
typename P1, typename P2, typename I1, typename I2, typename OPS>
struct overload_selector<false,true ,OPN,RT,true ,P1,P2,I1,I2,OPS> {
// Only swapped overload is well-formed, and we can use it
using type_1 = overload_1<OPS,RT,true ,const P1& , const P2& ,I1,I2>;
using type_2 = overload_2<OPS,RT,true ,const P1& , P2&&,I1,I2>;
using type_3 = overload_3<OPS,RT,true , P1&&, const P2& ,I1,I2>;
using type_4 = overload_4<OPS,RT,true , P1&&, P2&&,I1,I2>;
};
template <typename OPN, typename RT, bool commutative,
typename P1, typename P2, typename I1, typename I2, typename OPS>
struct overload_selector<true ,false,OPN,RT,commutative,P1,P2,I1,I2,OPS> {
// Only regular overload is well-formed
using type_1 = overload_1<OPN,RT,false,const P1& , const P2& ,I1,I2>;
using type_2 = overload_2<OPN,RT,false,const P1& , P2&&,I1,I2>;
using type_3 = overload_3<OPN,RT,false, P1&&, const P2& ,I1,I2>;
using type_4 = overload_4<OPN,RT,false, P1&&, P2&&,I1,I2>;
};
template <typename OPN, typename RT,
typename P1, typename P2, typename I1, typename I2, typename OPS>
struct overload_selector<true ,true ,OPN,RT,false,P1,P2,I1,I2,OPS> {
// Both overloads are well-formed, but we must use the regular one
using type_1 = overload_1<OPN,RT,false,const P1& , const P2& ,I1,I2>;
using type_2 = overload_2<OPN,RT,false,const P1& , P2&&,I1,I2>;
using type_3 = overload_3<OPN,RT,false, P1&&, const P2& ,I1,I2>;
using type_4 = overload_4<OPN,RT,false, P1&&, P2&&,I1,I2>;
};
template <typename OPN, typename RT,
typename P1, typename P2, typename I1, typename I2, typename OPS>
struct overload_selector<true ,true ,OPN,RT,true ,P1,P2,I1,I2,OPS> {
// Both overloads are well-formed, and we must choose between them
template <typename result, typename param1, typename param2>
static constexpr unsigned norm_cost() noexcept {
return binop_conversion_cost<RT,result,I1,I2,param1,param2>();
}
template <typename result, typename param1, typename param2>
static constexpr unsigned swap_cost() noexcept {
return binop_conversion_cost<RT,result,I2,I1,param2,param1>();
}
using RN = typename std::decay<typename
is_functor_call_well_formed<OPN,I1&,const I2&>::result_type>::type;
using RS = typename std::decay<typename
is_functor_call_well_formed<OPS,I2&,const I1&>::result_type>::type;
using type_1 = typename std::conditional<
swap_cost <RS,const P1& ,const P2& >() <
norm_cost <RN,const P1& ,const P2& >(),
overload_1<OPS,RT,true ,const P1& ,const P2& ,I1,I2>,
overload_1<OPN,RT,false,const P1& ,const P2& ,I1,I2>>::type;
using type_2 = typename std::conditional<
swap_cost <RS,const P1& , P2&&>() <
norm_cost <RN,const P1& , P2&&>(),
overload_2<OPS,RT,true ,const P1& , P2&&,I1,I2>,
overload_2<OPN,RT,false,const P1& , P2&&,I1,I2>>::type;
using type_3 = typename std::conditional<
swap_cost <RS, P1&&,const P2& >() <
norm_cost <RN, P1&&,const P2& >(),
overload_3<OPS,RT,true , P1&&,const P2& ,I1,I2>,
overload_3<OPN,RT,false, P1&&,const P2& ,I1,I2>>::type;
using type_4 = typename std::conditional<
swap_cost <RS, P1&&, P2&&>() <
norm_cost <RN, P1&&, P2&&>(),
overload_4<OPS,RT,true , P1&&, P2&&,I1,I2>,
overload_4<OPN,RT,false, P1&&, P2&&,I1,I2>>::type;
};
template <typename OPN, typename RT, bool commutative,
typename P1, typename P2, typename I1, typename I2, typename OPS>
using overload_selector_t = overload_selector<
is_functor_call_well_formed<OPN,I1&,I2>::value,
is_functor_call_well_formed<OPS,I2&,I1>::value,
OPN,RT,commutative,P1,P2,I1,I2,OPS>;
///
/// Generalized binary operator
///
template <typename OPN, typename RT, bool commutative=false,
typename P1=RT, typename P2=RT, typename I1=P1, typename I2=P2,
typename OPS=OPN>
struct binary_operator
: overload_selector_t<OPN,RT,commutative,P1,P2,I1,I2,OPS>::type_1
, overload_selector_t<OPN,RT,commutative,P1,P2,I1,I2,OPS>::type_2
, overload_selector_t<OPN,RT,commutative,P1,P2,I1,I2,OPS>::type_3
, overload_selector_t<OPN,RT,commutative,P1,P2,I1,I2,OPS>::type_4
{
//
// Inheriting a function with the same name from different base classes is
// ambiguous (ISO/IEC 14882 �10.2/6). Work around this by pulling the
// declarations into the derived class.
//
using overload_selector_t<OPN,RT,commutative,P1,P2,I1,I2,OPS>::type_1::func;
using overload_selector_t<OPN,RT,commutative,P1,P2,I1,I2,OPS>::type_2::func;
using overload_selector_t<OPN,RT,commutative,P1,P2,I1,I2,OPS>::type_3::func;
using overload_selector_t<OPN,RT,commutative,P1,P2,I1,I2,OPS>::type_4::func;
};
/// @}
}
}
#endif