diff --git a/modules/gapi/include/opencv2/gapi/gopaque.hpp b/modules/gapi/include/opencv2/gapi/gopaque.hpp index f5d06bbed7..46c070a822 100644 --- a/modules/gapi/include/opencv2/gapi/gopaque.hpp +++ b/modules/gapi/include/opencv2/gapi/gopaque.hpp @@ -17,6 +17,7 @@ #include #include +#include #include namespace cv @@ -86,13 +87,13 @@ namespace detail template bool GOpaqueU::holds() const{ GAPI_Assert(m_hint != nullptr); - using U = typename std::decay::type; + using U = util::decay_t; return dynamic_cast*>(m_hint.get()) != nullptr; }; template void GOpaqueU::specifyType(){ - m_hint.reset(new TypeHint::type>); + m_hint.reset(new TypeHint>); }; // This class represents a typed object reference. @@ -220,8 +221,13 @@ namespace detail public: OpaqueRef() = default; - template explicit OpaqueRef(T&& obj) : - m_ref(new OpaqueRefT::type>(std::forward(obj))) {} + + template< + typename T, + typename = util::are_different_t + > + explicit OpaqueRef(T&& obj) : + m_ref(new OpaqueRefT>(std::forward(obj))) {} template void reset() { @@ -274,7 +280,7 @@ public: private: // Host type (or Flat type) - the type this GOpaque is actually // specified to. - using HT = typename detail::flatten_g::type>::type; + using HT = typename detail::flatten_g>::type; static void CTor(detail::OpaqueRef& ref) { ref.reset(); diff --git a/modules/gapi/include/opencv2/gapi/util/type_traits.hpp b/modules/gapi/include/opencv2/gapi/util/type_traits.hpp new file mode 100644 index 0000000000..637f18460b --- /dev/null +++ b/modules/gapi/include/opencv2/gapi/util/type_traits.hpp @@ -0,0 +1,31 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +// +// Copyright (C) 2020 Intel Corporation + + +#ifndef OPENCV_GAPI_UTIL_TYPE_TRAITS_HPP +#define OPENCV_GAPI_UTIL_TYPE_TRAITS_HPP + +#include + +namespace cv +{ +namespace util +{ + //these are C++14 parts of type_traits : + template< bool B, class T = void > + using enable_if_t = typename std::enable_if::type; + + template + using decay_t = typename std::decay::type; + + //this is not part of C++14 but still, of pretty common usage + template + using are_different_t = enable_if_t< !std::is_same, decay_t>::value, V>; + +} // namespace cv +} // namespace util + +#endif // OPENCV_GAPI_UTIL_TYPE_TRAITS_HPP diff --git a/modules/gapi/include/opencv2/gapi/util/variant.hpp b/modules/gapi/include/opencv2/gapi/util/variant.hpp index 6e6a73bd60..71a06d2dcf 100644 --- a/modules/gapi/include/opencv2/gapi/util/variant.hpp +++ b/modules/gapi/include/opencv2/gapi/util/variant.hpp @@ -13,6 +13,7 @@ #include #include // max_of_t +#include // A poor man's `variant` implementation, incompletely modeled against C++17 spec. namespace cv @@ -35,15 +36,6 @@ namespace util static_assert(std::is_same::value, "Type not found"); static const constexpr std::size_t value = I; }; - - template< bool B, class T = void > - using enable_if_t = typename std::enable_if::type; - - template - using are_different_t = enable_if_t< - !std::is_same::type, - typename std::decay::type>::value, - V>; } template @@ -82,18 +74,20 @@ namespace util } }; - template struct vctr_h { - static void help(Memory memory, const void* pval) { - new (memory) T(*reinterpret_cast(pval)); - } - }; - template struct mctr_h { static void help(Memory memory, void *pval) { new (memory) T(std::move(*reinterpret_cast(pval))); } }; + //FIXME: unify with cctr_h and mctr_h + template struct cnvrt_ctor_h { + static void help(Memory memory, void* from) { + using util::decay_t; + new (memory) decay_t(std::forward(*reinterpret_cast*>(from))); + } + }; + template struct copy_h { static void help(Memory to, const Memory from) { *reinterpret_cast(to) = *reinterpret_cast(from); @@ -101,8 +95,16 @@ namespace util }; template struct move_h { - static void help(Memory to, const Memory from) { - *reinterpret_cast(to) = std::move(*reinterpret_cast(from)); + static void help(Memory to, Memory from) { + *reinterpret_cast(to) = std::move(*reinterpret_cast(from)); + } + }; + + //FIXME: unify with copy_h and move_h + template struct cnvrt_assign_h { + static void help(Memory to, void* from) { + using util::decay_t; + *reinterpret_cast*>(to) = std::forward(*reinterpret_cast*>(from)); } }; @@ -128,23 +130,42 @@ namespace util }; typedef void (*CCtr) (Memory, const Memory); // Copy c-tor (variant) - typedef void (*VCtr) (Memory, const void*); // Copy c-tor (value) typedef void (*MCtr) (Memory, void*); // Generic move c-tor typedef void (*Copy) (Memory, const Memory); // Copy assignment - typedef void (*Move) (Memory, const Memory); // Move assignment + typedef void (*Move) (Memory, Memory); // Move assignment + typedef void (*Swap) (Memory, Memory); // Swap typedef void (*Dtor) (Memory); // Destructor + using cnvrt_assgn_t = void (*) (Memory, void*); // Converting assignment (via std::forward) + using cnvrt_ctor_t = void (*) (Memory, void*); // Converting constructor (via std::forward) + typedef bool (*Equal)(const Memory, const Memory); // Equality test (external) static constexpr std::array cctrs(){ return {{(&cctr_h::help)...}};} - static constexpr std::array vctrs(){ return {{(&vctr_h::help)...}};} static constexpr std::array mctrs(){ return {{(&mctr_h::help)...}};} static constexpr std::array cpyrs(){ return {{(©_h::help)...}};} static constexpr std::array mvers(){ return {{(&move_h::help)...}};} static constexpr std::array swprs(){ return {{(&swap_h::help)...}};} static constexpr std::array dtors(){ return {{(&dtor_h::help)...}};} + template + struct conditional_ref : std::conditional::type&, typename std::remove_reference::type > {}; + + template + using conditional_ref_t = typename conditional_ref::type; + + + template + static constexpr std::array cnvrt_assgnrs(){ + return {{(&cnvrt_assign_h>::help)...}}; + } + + template + static constexpr std::array cnvrt_ctors(){ + return {{(&cnvrt_ctor_h>::help)...}}; + } + std::size_t m_index = 0; protected: @@ -162,16 +183,12 @@ namespace util variant() noexcept; variant(const variant& other); variant(variant&& other) noexcept; - template explicit variant(const T& t); // are_different_t is a SFINAE trick to avoid variant(T &&t) with T=variant // for some reason, this version is called instead of variant(variant&& o) when // variant is used in STL containers (examples: vector assignment). - // detail::enable_if_t::value> is a SFINAE - // trick to limit this constructor only to rvalue reference argument template< typename T, - typename = detail::are_different_t, - typename = detail::enable_if_t::value> + typename = util::are_different_t > explicit variant(T&& t); // template explicit variant(Args&&... args); @@ -187,7 +204,7 @@ namespace util // SFINAE trick to avoid operator=(T&&) with T=variant<>, see comment above template< typename T, - typename = detail::are_different_t + typename = util::are_different_t > variant& operator=(T&& t) noexcept; @@ -244,19 +261,12 @@ namespace util } template - template - variant::variant(const T& t) - : m_index(util::type_list_index::value) - { - (vctrs()[m_index])(memory, &t); - } - - template - template + template variant::variant(T&& t) - : m_index(util::type_list_index::type, Ts...>::value) + : m_index(util::type_list_index, Ts...>::value) { - (mctrs()[m_index])(memory, &t); + const constexpr bool is_lvalue_arg = std::is_lvalue_reference::value; + (cnvrt_ctors()[m_index])(memory, const_cast *>(&t)); } template @@ -301,17 +311,25 @@ namespace util template variant& variant::operator=(T&& t) noexcept { - using decayed_t = typename std::decay::type; + using decayed_t = util::decay_t; // FIXME: No version with implicit type conversion available! - static const constexpr std::size_t t_index = + const constexpr std::size_t t_index = util::type_list_index::value; - if (t_index == m_index) + const constexpr bool is_lvalue_arg = std::is_lvalue_reference::value; + + if (t_index != m_index) + { + (dtors()[m_index])(memory); + (cnvrt_ctors()[t_index])(memory, &t); + m_index = t_index; + } + else { - util::get(*this) = std::forward(t); - return *this; + (cnvrt_assgnrs()[m_index])(memory, &t); } - else return (*this = variant(std::forward(t))); + return *this; + } template diff --git a/modules/gapi/test/util/variant_tests.cpp b/modules/gapi/test/util/variant_tests.cpp index 69f88b3fa4..65d5e579f8 100644 --- a/modules/gapi/test/util/variant_tests.cpp +++ b/modules/gapi/test/util/variant_tests.cpp @@ -59,7 +59,9 @@ TEST(Variant, ConvertingCTorMove) util::variant vsi3(std::move(rvs)); EXPECT_EQ(0u, vsi3.index()); EXPECT_EQ("2017", util::get(vsi3)); - EXPECT_EQ("", rvs) <<"Rvalue source argument was not moved from while should?"; + //C++ standard state that std::string instance that was moved from stays in valid, but unspecified state. + //So the best assumption we can made here is that s is not the same as it was before move. + EXPECT_NE("2017", rvs) <<"Rvalue source argument was not moved from while should?"; util::variant vsi2(42); EXPECT_EQ(1u, vsi2.index()); @@ -174,7 +176,25 @@ TEST(Variant, Assign_RValueRef_DiffType) vis = std::move(s); EXPECT_EQ(1u, vis.index()); EXPECT_EQ("42", util::get(vis)); - EXPECT_EQ("", s) << "right hand side argument of assignment operation was not moved from while should?";; + //C++ standard state that std::string instance that was moved from stays in valid, but unspecified state. + //So the best assumption we can made here is that s is not the same as it was before move. + EXPECT_NE("42", s) << "right hand side argument of assignment operation was not moved from while should?"; +} + +TEST(Variant, Assign_RValueRef_SameType) +{ + TestVar vis(std::string("43")); + + EXPECT_EQ(1u, vis.index()); + EXPECT_EQ("43", util::get(vis)); + + std::string s("42"); + vis = std::move(s); + EXPECT_EQ(1u, vis.index()); + EXPECT_EQ("42", util::get(vis)); + //C++ standard state that std::string instance that was moved from stays in valid, but unspecified state. + //So the best assumption we can made here is that s is not the same as it was before move. + EXPECT_NE("42", s) << "right hand side argument of assignment operation was not moved from while should?"; } TEST(Variant, Assign_LValueRef_DiffType) @@ -191,7 +211,7 @@ TEST(Variant, Assign_LValueRef_DiffType) EXPECT_EQ("42", s) << "right hand side argument of assignment operation was moved from while should not ?"; } -TEST(Variant, Assign_ValueUpdate_Const) +TEST(Variant, Assign_ValueUpdate_Const_Variant) { TestVar va(42); const TestVar vb(43); @@ -208,7 +228,7 @@ TEST(Variant, Assign_ValueUpdate_Const) EXPECT_EQ(43, util::get(va)); } -TEST(Variant, Assign_ValueUpdate_Const_DiffType) +TEST(Variant, Assign_ValueUpdate_Const_DiffType_Variant) { TestVar va(42); const TestVar vb(std::string("42")); @@ -229,6 +249,7 @@ TEST(Variant, Assign_Move_Variant) { TestVar va(42); TestVar vb(std::string("42")); + TestVar vd(std::string("43")); TestVar vc(43); EXPECT_EQ(0u, va.index()); @@ -240,10 +261,24 @@ TEST(Variant, Assign_Move_Variant) EXPECT_EQ(0u, vc.index()); EXPECT_EQ(43, util::get(vc)); + EXPECT_EQ(1u, vd.index()); + EXPECT_EQ("43", util::get(vd)); + va = std::move(vb); EXPECT_EQ(1u, va.index()); EXPECT_EQ("42", util::get(va)); + EXPECT_EQ(1u, vb.index()); + EXPECT_EQ("", util::get(vb)); + + + vb = std::move(vd); + EXPECT_EQ(1u, vb.index()); + EXPECT_EQ("43", util::get(vb)); + + EXPECT_EQ(1u, vd.index()); + EXPECT_EQ("", util::get(vd)); + va = std::move(vc); EXPECT_EQ(0u, va.index()); EXPECT_EQ(43, util::get(va));