Merge pull request #17191 from anton-potapov:gapi_variant_converting_ctor_assign_op_reworked

This commit is contained in:
Alexander Alekhin
2020-05-21 12:59:30 +00:00
4 changed files with 142 additions and 52 deletions
+11 -5
View File
@@ -17,6 +17,7 @@
#include <opencv2/gapi/util/variant.hpp>
#include <opencv2/gapi/util/throw.hpp>
#include <opencv2/gapi/util/type_traits.hpp>
#include <opencv2/gapi/own/assert.hpp>
namespace cv
@@ -86,13 +87,13 @@ namespace detail
template <typename T>
bool GOpaqueU::holds() const{
GAPI_Assert(m_hint != nullptr);
using U = typename std::decay<T>::type;
using U = util::decay_t<T>;
return dynamic_cast<TypeHint<U>*>(m_hint.get()) != nullptr;
};
template <typename T>
void GOpaqueU::specifyType(){
m_hint.reset(new TypeHint<typename std::decay<T>::type>);
m_hint.reset(new TypeHint<util::decay_t<T>>);
};
// This class represents a typed object reference.
@@ -220,8 +221,13 @@ namespace detail
public:
OpaqueRef() = default;
template<typename T> explicit OpaqueRef(T&& obj) :
m_ref(new OpaqueRefT<typename std::decay<T>::type>(std::forward<T>(obj))) {}
template<
typename T,
typename = util::are_different_t<OpaqueRef, T>
>
explicit OpaqueRef(T&& obj) :
m_ref(new OpaqueRefT<util::decay_t<T>>(std::forward<T>(obj))) {}
template<typename T> 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<typename std::decay<T>::type>::type;
using HT = typename detail::flatten_g<util::decay_t<T>>::type;
static void CTor(detail::OpaqueRef& ref) {
ref.reset<HT>();
@@ -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 <type_traits>
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<B,T>::type;
template<typename T>
using decay_t = typename std::decay<T>::type;
//this is not part of C++14 but still, of pretty common usage
template<class T, class U, class V = void>
using are_different_t = enable_if_t< !std::is_same<decay_t<T>, decay_t<U>>::value, V>;
} // namespace cv
} // namespace util
#endif // OPENCV_GAPI_UTIL_TYPE_TRAITS_HPP
@@ -13,6 +13,7 @@
#include <opencv2/gapi/util/throw.hpp>
#include <opencv2/gapi/util/util.hpp> // max_of_t
#include <opencv2/gapi/util/type_traits.hpp>
// 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<Target, First>::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<B,T>::type;
template<class T, class U, class V = void>
using are_different_t = enable_if_t<
!std::is_same<typename std::decay<T>::type,
typename std::decay<U>::type>::value,
V>;
}
template<typename Target, typename... Types>
@@ -82,18 +74,20 @@ namespace util
}
};
template<typename T> struct vctr_h {
static void help(Memory memory, const void* pval) {
new (memory) T(*reinterpret_cast<const T*>(pval));
}
};
template<typename T> struct mctr_h {
static void help(Memory memory, void *pval) {
new (memory) T(std::move(*reinterpret_cast<T*>(pval)));
}
};
//FIXME: unify with cctr_h and mctr_h
template<typename T> struct cnvrt_ctor_h {
static void help(Memory memory, void* from) {
using util::decay_t;
new (memory) decay_t<T>(std::forward<T>(*reinterpret_cast<decay_t<T>*>(from)));
}
};
template<typename T> struct copy_h {
static void help(Memory to, const Memory from) {
*reinterpret_cast<T*>(to) = *reinterpret_cast<const T*>(from);
@@ -101,8 +95,16 @@ namespace util
};
template<typename T> struct move_h {
static void help(Memory to, const Memory from) {
*reinterpret_cast<T*>(to) = std::move(*reinterpret_cast<const T*>(from));
static void help(Memory to, Memory from) {
*reinterpret_cast<T*>(to) = std::move(*reinterpret_cast<T*>(from));
}
};
//FIXME: unify with copy_h and move_h
template<typename T> struct cnvrt_assign_h {
static void help(Memory to, void* from) {
using util::decay_t;
*reinterpret_cast<decay_t<T>*>(to) = std::forward<T>(*reinterpret_cast<decay_t<T>*>(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<CCtr, sizeof...(Ts)> cctrs(){ return {{(&cctr_h<Ts>::help)...}};}
static constexpr std::array<VCtr, sizeof...(Ts)> vctrs(){ return {{(&vctr_h<Ts>::help)...}};}
static constexpr std::array<MCtr, sizeof...(Ts)> mctrs(){ return {{(&mctr_h<Ts>::help)...}};}
static constexpr std::array<Copy, sizeof...(Ts)> cpyrs(){ return {{(&copy_h<Ts>::help)...}};}
static constexpr std::array<Move, sizeof...(Ts)> mvers(){ return {{(&move_h<Ts>::help)...}};}
static constexpr std::array<Swap, sizeof...(Ts)> swprs(){ return {{(&swap_h<Ts>::help)...}};}
static constexpr std::array<Dtor, sizeof...(Ts)> dtors(){ return {{(&dtor_h<Ts>::help)...}};}
template<bool cond, typename T>
struct conditional_ref : std::conditional<cond, typename std::remove_reference<T>::type&, typename std::remove_reference<T>::type > {};
template<bool cond, typename T>
using conditional_ref_t = typename conditional_ref<cond, T>::type;
template<bool is_lvalue_arg>
static constexpr std::array<cnvrt_assgn_t, sizeof...(Ts)> cnvrt_assgnrs(){
return {{(&cnvrt_assign_h<conditional_ref_t<is_lvalue_arg,Ts>>::help)...}};
}
template<bool is_lvalue_arg>
static constexpr std::array<cnvrt_ctor_t, sizeof...(Ts)> cnvrt_ctors(){
return {{(&cnvrt_ctor_h<conditional_ref_t<is_lvalue_arg,Ts>>::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<typename T> 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<! std::is_lvalue_reference<T>::value> is a SFINAE
// trick to limit this constructor only to rvalue reference argument
template<
typename T,
typename = detail::are_different_t<variant, T>,
typename = detail::enable_if_t<! std::is_lvalue_reference<T>::value>
typename = util::are_different_t<variant, T>
>
explicit variant(T&& t);
// template<class T, class... Args> 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<variant, T>
typename = util::are_different_t<variant, T>
>
variant& operator=(T&& t) noexcept;
@@ -244,19 +261,12 @@ namespace util
}
template<typename... Ts>
template<class T>
variant<Ts...>::variant(const T& t)
: m_index(util::type_list_index<T, Ts...>::value)
{
(vctrs()[m_index])(memory, &t);
}
template<typename... Ts>
template<class T, typename , typename>
template<class T, typename>
variant<Ts...>::variant(T&& t)
: m_index(util::type_list_index<typename std::remove_reference<T>::type, Ts...>::value)
: m_index(util::type_list_index<util::decay_t<T>, Ts...>::value)
{
(mctrs()[m_index])(memory, &t);
const constexpr bool is_lvalue_arg = std::is_lvalue_reference<T>::value;
(cnvrt_ctors<is_lvalue_arg>()[m_index])(memory, const_cast<util::decay_t<T> *>(&t));
}
template<typename... Ts>
@@ -301,17 +311,25 @@ namespace util
template<typename T, typename>
variant<Ts...>& variant<Ts...>::operator=(T&& t) noexcept
{
using decayed_t = typename std::decay<T>::type;
using decayed_t = util::decay_t<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<decayed_t, Ts...>::value;
if (t_index == m_index)
const constexpr bool is_lvalue_arg = std::is_lvalue_reference<T>::value;
if (t_index != m_index)
{
util::get<decayed_t>(*this) = std::forward<T>(t);
return *this;
(dtors()[m_index])(memory);
(cnvrt_ctors<is_lvalue_arg>()[t_index])(memory, &t);
m_index = t_index;
}
else return (*this = variant(std::forward<T>(t)));
else
{
(cnvrt_assgnrs<is_lvalue_arg>()[m_index])(memory, &t);
}
return *this;
}
template<typename... Ts>