添加项目文件。

This commit is contained in:
CaiXiang
2025-01-20 10:30:01 +08:00
parent 77371da5d7
commit 752be79e06
1010 changed files with 610100 additions and 0 deletions

View File

@@ -0,0 +1,190 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_UTIL_ANY_HPP
#define OPENCV_GAPI_UTIL_ANY_HPP
#include <memory>
#include <type_traits>
#include <typeinfo>
#include <utility>
#include <opencv2/gapi/util/throw.hpp>
#if defined(_MSC_VER)
// disable MSVC warning on "multiple copy constructors specified"
# pragma warning(disable: 4521)
#endif
namespace cv
{
namespace internal
{
template <class T, class Source>
T down_cast(Source operand)
{
#if defined(__GXX_RTTI) || defined(_CPPRTTI)
return dynamic_cast<T>(operand);
#else
#ifdef __GNUC__
#warning used static cast instead of dynamic because RTTI is disabled
#else
#pragma message("WARNING: used static cast instead of dynamic because RTTI is disabled")
#endif
return static_cast<T>(operand);
#endif
}
}
namespace util
{
class bad_any_cast : public std::bad_cast
{
public:
virtual const char* what() const noexcept override
{
return "Bad any cast";
}
};
//modeled against C++17 std::any
class any
{
private:
struct holder;
using holder_ptr = std::unique_ptr<holder>;
struct holder
{
virtual holder_ptr clone() = 0;
virtual ~holder() = default;
};
template <typename value_t>
struct holder_impl : holder
{
value_t v;
template<typename arg_t>
holder_impl(arg_t&& a) : v(std::forward<arg_t>(a)) {}
holder_ptr clone() override { return holder_ptr(new holder_impl (v));}
};
holder_ptr hldr;
public:
template<class value_t>
any(value_t&& arg) : hldr(new holder_impl<typename std::decay<value_t>::type>( std::forward<value_t>(arg))) {}
any(any const& src) : hldr( src.hldr ? src.hldr->clone() : nullptr) {}
//simple hack in order not to write enable_if<not any> for the template constructor
any(any & src) : any (const_cast<any const&>(src)) {}
any() = default;
any(any&& ) = default;
any& operator=(any&&) = default;
any& operator=(any const& src)
{
any copy(src);
swap(*this, copy);
return *this;
}
template<class value_t>
friend value_t* any_cast(any* operand);
template<class value_t>
friend const value_t* any_cast(const any* operand);
template<class value_t>
friend value_t& unsafe_any_cast(any& operand);
template<class value_t>
friend const value_t& unsafe_any_cast(const any& operand);
friend void swap(any & lhs, any& rhs)
{
swap(lhs.hldr, rhs.hldr);
}
};
template<class value_t>
value_t* any_cast(any* operand)
{
auto casted = internal::down_cast<any::holder_impl<typename std::decay<value_t>::type> *>(operand->hldr.get());
if (casted){
return & (casted->v);
}
return nullptr;
}
template<class value_t>
const value_t* any_cast(const any* operand)
{
auto casted = internal::down_cast<any::holder_impl<typename std::decay<value_t>::type> *>(operand->hldr.get());
if (casted){
return & (casted->v);
}
return nullptr;
}
template<class value_t>
value_t& any_cast(any& operand)
{
auto ptr = any_cast<value_t>(&operand);
if (ptr)
{
return *ptr;
}
throw_error(bad_any_cast());
}
template<class value_t>
const value_t& any_cast(const any& operand)
{
auto ptr = any_cast<value_t>(&operand);
if (ptr)
{
return *ptr;
}
throw_error(bad_any_cast());
}
template<class value_t>
inline value_t& unsafe_any_cast(any& operand)
{
#ifdef DEBUG
return any_cast<value_t>(operand);
#else
return static_cast<any::holder_impl<typename std::decay<value_t>::type> *>(operand.hldr.get())->v;
#endif
}
template<class value_t>
inline const value_t& unsafe_any_cast(const any& operand)
{
#ifdef DEBUG
return any_cast<value_t>(operand);
#else
return static_cast<any::holder_impl<typename std::decay<value_t>::type> *>(operand.hldr.get())->v;
#endif
}
} // namespace util
} // namespace cv
#if defined(_MSC_VER)
// Enable "multiple copy constructors specified" back
# pragma warning(default: 4521)
#endif
#endif // OPENCV_GAPI_UTIL_ANY_HPP

View File

@@ -0,0 +1,19 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_UTIL_COMPILER_HINTS_HPP
#define OPENCV_GAPI_UTIL_COMPILER_HINTS_HPP
namespace cv
{
namespace util
{
//! Utility template function to prevent "unused" warnings by various compilers.
template<typename T> void suppress_unused_warning( const T& ) {}
} // namespace util
} // namespace cv
#endif /* OPENCV_GAPI_UTIL_COMPILER_HINTS_HPP */

View File

@@ -0,0 +1,34 @@
// 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_COPY_THROUGH_MOVE_HPP
#define OPENCV_GAPI_UTIL_COPY_THROUGH_MOVE_HPP
#include <opencv2/gapi/util/type_traits.hpp> //decay_t
namespace cv
{
namespace util
{
//This is a tool to move initialize captures of a lambda in C++11
template<typename T>
struct copy_through_move_t{
T value;
const T& get() const {return value;}
T& get() {return value;}
copy_through_move_t(T&& g) : value(std::move(g)) {}
copy_through_move_t(copy_through_move_t&&) = default;
copy_through_move_t(copy_through_move_t const& lhs) : copy_through_move_t(std::move(const_cast<copy_through_move_t&>(lhs))) {}
};
template<typename T>
copy_through_move_t<util::decay_t<T>> copy_through_move(T&& t){
return std::forward<T>(t);
}
} // namespace util
} // namespace cv
#endif /* OPENCV_GAPI_UTIL_COPY_THROUGH_MOVE_HPP */

View File

@@ -0,0 +1,178 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_UTIL_OPTIONAL_HPP
#define OPENCV_GAPI_UTIL_OPTIONAL_HPP
#include <opencv2/gapi/util/variant.hpp>
// A poor man's `optional` implementation, incompletely modeled against C++17 spec.
namespace cv
{
namespace util
{
class bad_optional_access: public std::exception
{
public:
virtual const char *what() const noexcept override
{
return "Bad optional access";
}
};
// TODO: nullopt_t
// Interface ///////////////////////////////////////////////////////////////
template<typename T> class optional
{
public:
// Constructors
// NB.: there were issues with Clang 3.8 when =default() was used
// instead {}
optional() {}
optional(const optional&) = default;
explicit optional(T&&) noexcept;
explicit optional(const T&) noexcept;
optional(optional&&) noexcept;
// TODO: optional(nullopt_t) noexcept;
// TODO: optional(const optional<U> &)
// TODO: optional(optional<U> &&)
// TODO: optional(Args&&...)
// TODO: optional(initializer_list<U>)
// TODO: optional(U&& value);
// Assignment
optional& operator=(const optional&) = default;
optional& operator=(optional&&);
// Observers
T* operator-> ();
const T* operator-> () const;
T& operator* ();
const T& operator* () const;
// TODO: && versions
operator bool() const noexcept;
bool has_value() const noexcept;
T& value();
const T& value() const;
// TODO: && versions
template<class U>
T value_or(U &&default_value) const;
void swap(optional &other) noexcept;
void reset() noexcept;
// TODO: emplace
// TODO: operator==, !=, <, <=, >, >=
private:
struct nothing {};
util::variant<nothing, T> m_holder;
};
template<class T>
optional<typename std::decay<T>::type> make_optional(T&& value);
// TODO: Args... and initializer_list versions
// Implementation //////////////////////////////////////////////////////////
template<class T> optional<T>::optional(T &&v) noexcept
: m_holder(std::move(v))
{
}
template<class T> optional<T>::optional(const T &v) noexcept
: m_holder(v)
{
}
template<class T> optional<T>::optional(optional&& rhs) noexcept
: m_holder(std::move(rhs.m_holder))
{
rhs.reset();
}
template<class T> optional<T>& optional<T>::operator=(optional&& rhs)
{
m_holder = std::move(rhs.m_holder);
rhs.reset();
return *this;
}
template<class T> T* optional<T>::operator-> ()
{
return & *(*this);
}
template<class T> const T* optional<T>::operator-> () const
{
return & *(*this);
}
template<class T> T& optional<T>::operator* ()
{
return this->value();
}
template<class T> const T& optional<T>::operator* () const
{
return this->value();
}
template<class T> optional<T>::operator bool() const noexcept
{
return this->has_value();
}
template<class T> bool optional<T>::has_value() const noexcept
{
return util::holds_alternative<T>(m_holder);
}
template<class T> T& optional<T>::value()
{
if (!this->has_value())
throw_error(bad_optional_access());
return util::get<T>(m_holder);
}
template<class T> const T& optional<T>::value() const
{
if (!this->has_value())
throw_error(bad_optional_access());
return util::get<T>(m_holder);
}
template<class T>
template<class U> T optional<T>::value_or(U &&default_value) const
{
return (this->has_value() ? this->value() : T(default_value));
}
template<class T> void optional<T>::swap(optional<T> &other) noexcept
{
m_holder.swap(other.m_holder);
}
template<class T> void optional<T>::reset() noexcept
{
if (this->has_value())
m_holder = nothing{};
}
template<class T>
optional<typename std::decay<T>::type> make_optional(T&& value)
{
return optional<typename std::decay<T>::type>(std::forward<T>(value));
}
} // namespace util
} // namespace cv
#endif // OPENCV_GAPI_UTIL_OPTIONAL_HPP

View File

@@ -0,0 +1,36 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_UTIL_THROW_HPP
#define OPENCV_GAPI_UTIL_THROW_HPP
#include <utility> // std::forward
#if !defined(__EXCEPTIONS)
#include <stdlib.h>
#include <stdio.h>
#endif
namespace cv
{
namespace util
{
template <class ExceptionType>
[[noreturn]] void throw_error(ExceptionType &&e)
{
#if defined(__EXCEPTIONS) || defined(_CPPUNWIND)
throw std::forward<ExceptionType>(e);
#else
fprintf(stderr, "An exception thrown! %s\n" , e.what());
fflush(stderr);
abort();
#endif
}
} // namespace util
} // namespace cv
#endif // OPENCV_GAPI_UTIL_THROW_HPP

View File

@@ -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

View File

@@ -0,0 +1,190 @@
// 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) 2018-2019 Intel Corporation
#ifndef OPENCV_GAPI_UTIL_HPP
#define OPENCV_GAPI_UTIL_HPP
#include <tuple>
// \cond HIDDEN_SYMBOLS
// This header file contains some generic utility functions which are
// used in other G-API Public API headers.
//
// PLEASE don't put any stuff here if it is NOT used in public API headers!
namespace cv
{
namespace detail
{
// Recursive integer sequence type, useful for enumerating elements of
// template parameter packs.
template<int... I> struct Seq { using next = Seq<I..., sizeof...(I)>; };
template<int Sz> struct MkSeq { using type = typename MkSeq<Sz-1>::type::next; };
template<> struct MkSeq<0>{ using type = Seq<>; };
// Checks if elements of variadic template satisfy the given Predicate.
// Implemented via tuple, with an interface to accept plain type lists
template<template<class> class, typename, typename...> struct all_satisfy;
template<template<class> class F, typename T, typename... Ts>
struct all_satisfy<F, std::tuple<T, Ts...> >
{
static const constexpr bool value = F<T>::value
&& all_satisfy<F, std::tuple<Ts...> >::value;
};
template<template<class> class F, typename T>
struct all_satisfy<F, std::tuple<T> >
{
static const constexpr bool value = F<T>::value;
};
template<template<class> class F, typename T, typename... Ts>
struct all_satisfy: public all_satisfy<F, std::tuple<T, Ts...> > {};
// Permute given tuple type C with given integer sequence II
// Sequence may be less than tuple C size.
template<class, class> struct permute_tuple;
template<class C, int... IIs>
struct permute_tuple<C, Seq<IIs...> >
{
using type = std::tuple< typename std::tuple_element<IIs, C>::type... >;
};
// Given T..., generates a type sequence of sizeof...(T)-1 elements
// which is T... without its last element
// Implemented via tuple, with an interface to accept plain type lists
template<typename T, typename... Ts> struct all_but_last;
template<typename T, typename... Ts>
struct all_but_last<std::tuple<T, Ts...> >
{
using C = std::tuple<T, Ts...>;
using S = typename MkSeq<std::tuple_size<C>::value - 1>::type;
using type = typename permute_tuple<C, S>::type;
};
template<typename T, typename... Ts>
struct all_but_last: public all_but_last<std::tuple<T, Ts...> > {};
template<typename... Ts>
using all_but_last_t = typename all_but_last<Ts...>::type;
// NB.: This is here because there's no constexpr std::max in C++11
template<std::size_t S0, std::size_t... SS> struct max_of_t
{
static constexpr const std::size_t rest = max_of_t<SS...>::value;
static constexpr const std::size_t value = rest > S0 ? rest : S0;
};
template<std::size_t S> struct max_of_t<S>
{
static constexpr const std::size_t value = S;
};
template <typename...>
struct contains : std::false_type{};
template <typename T1, typename T2, typename... Ts>
struct contains<T1, T2, Ts...> : std::integral_constant<bool, std::is_same<T1, T2>::value ||
contains<T1, Ts...>::value> {};
template<typename T, typename... Types>
struct contains<T, std::tuple<Types...>> : std::integral_constant<bool, contains<T, Types...>::value> {};
template <typename...>
struct all_unique : std::true_type{};
template <typename T1, typename... Ts>
struct all_unique<T1, Ts...> : std::integral_constant<bool, !contains<T1, Ts...>::value &&
all_unique<Ts...>::value> {};
template<typename>
struct tuple_wrap_helper;
template<typename T> struct tuple_wrap_helper
{
using type = std::tuple<T>;
static type get(T&& obj) { return std::make_tuple(std::move(obj)); }
};
template<typename... Objs>
struct tuple_wrap_helper<std::tuple<Objs...>>
{
using type = std::tuple<Objs...>;
static type get(std::tuple<Objs...>&& objs) { return std::forward<std::tuple<Objs...>>(objs); }
};
template<typename... Ts>
struct make_void { typedef void type;};
template<typename... Ts>
using void_t = typename make_void<Ts...>::type;
} // namespace detail
namespace util
{
template<typename ...L>
struct overload_lamba_set;
template<typename L1>
struct overload_lamba_set<L1> : public L1
{
overload_lamba_set(L1&& lambda) : L1(std::move(lambda)) {}
overload_lamba_set(const L1& lambda) : L1(lambda) {}
using L1::operator();
};
template<typename L1, typename ...L>
struct overload_lamba_set<L1, L...> : public L1, public overload_lamba_set<L...>
{
using base_type = overload_lamba_set<L...>;
overload_lamba_set(L1 &&lambda1, L&& ...lambdas):
L1(std::move(lambda1)),
base_type(std::forward<L>(lambdas)...) {}
overload_lamba_set(const L1 &lambda1, L&& ...lambdas):
L1(lambda1),
base_type(std::forward<L>(lambdas)...) {}
using L1::operator();
using base_type::operator();
};
template<typename... L>
overload_lamba_set<L...> overload_lambdas(L&& ...lambdas)
{
return overload_lamba_set<L...>(std::forward<L>(lambdas)...);
}
template<typename ...T>
struct find_adapter_impl;
template<typename AdapterT, typename T>
struct find_adapter_impl<AdapterT, T>
{
using type = typename std::conditional<std::is_base_of<AdapterT, T>::value,
T,
void>::type;
static constexpr bool found = std::is_base_of<AdapterT, T>::value;
};
template<typename AdapterT, typename T, typename... Types>
struct find_adapter_impl<AdapterT, T, Types...>
{
using type = typename std::conditional<std::is_base_of<AdapterT, T>::value,
T,
typename find_adapter_impl<AdapterT, Types...>::type>::type;
static constexpr bool found = std::is_base_of<AdapterT, T>::value ||
find_adapter_impl<AdapterT, Types...>::found;
};
} // namespace util
} // namespace cv
// \endcond
#endif // OPENCV_GAPI_UTIL_HPP

View File

@@ -0,0 +1,658 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_UTIL_VARIANT_HPP
#define OPENCV_GAPI_UTIL_VARIANT_HPP
#include <array>
#include <type_traits>
#include <opencv2/gapi/util/compiler_hints.hpp>
#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
{
namespace util
{
namespace detail
{
template<std::size_t I, typename Target, typename First, typename... Remaining>
struct type_list_index_helper
{
static const constexpr bool is_same = std::is_same<Target, First>::value;
static const constexpr std::size_t value =
std::conditional<is_same, std::integral_constant<std::size_t, I>, type_list_index_helper<I + 1, Target, Remaining...>>::type::value;
};
template<std::size_t I, typename Target, typename First>
struct type_list_index_helper<I, Target, First>
{
static_assert(std::is_same<Target, First>::value, "Type not found");
static const constexpr std::size_t value = I;
};
}
template<typename Target, typename... Types>
struct type_list_index
{
static const constexpr std::size_t value = detail::type_list_index_helper<0, Target, Types...>::value;
};
template<std::size_t Index, class... Types >
struct type_list_element
{
using type = typename std::tuple_element<Index, std::tuple<Types...> >::type;
};
class bad_variant_access: public std::exception
{
public:
virtual const char *what() const noexcept override
{
return "Bad variant access";
}
};
// Interface ///////////////////////////////////////////////////////////////
struct monostate {};
inline bool operator==(const util::monostate&, const util::monostate&)
{
return true;
}
template<typename... Ts> // FIXME: no references, arrays, and void
class variant
{
// FIXME: Replace with std::aligned_union after gcc4.8 support is dropped
static constexpr const std::size_t S = cv::detail::max_of_t<sizeof(Ts)...>::value;
static constexpr const std::size_t A = cv::detail::max_of_t<alignof(Ts)...>::value;
using Memory = typename std::aligned_storage<S, A>::type[1];
template<typename T> struct cctr_h {
static void help(Memory memory, const Memory from) {
new (memory) T(*reinterpret_cast<const T*>(from));
}
};
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);
}
};
template<typename T> struct move_h {
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));
}
};
template<typename T> struct swap_h {
static void help(Memory to, Memory from) {
std::swap(*reinterpret_cast<T*>(to), *reinterpret_cast<T*>(from));
}
};
template<typename T> struct dtor_h {
static void help(Memory memory) {
(void) memory; // MSCV warning
reinterpret_cast<T*>(memory)->~T();
}
};
template<typename T> struct equal_h {
static bool help(const Memory lhs, const Memory rhs) {
const T& t_lhs = *reinterpret_cast<const T*>(lhs);
const T& t_rhs = *reinterpret_cast<const T*>(rhs);
return t_lhs == t_rhs;
}
};
typedef void (*CCtr) (Memory, const Memory); // Copy c-tor (variant)
typedef void (*MCtr) (Memory, void*); // Generic move c-tor
typedef void (*Copy) (Memory, const Memory); // Copy 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<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:
template<typename T, typename... Us> friend T& get(variant<Us...> &v);
template<typename T, typename... Us> friend const T& get(const variant<Us...> &v);
template<typename T, typename... Us> friend T* get_if(variant<Us...> *v) noexcept;
template<typename T, typename... Us> friend const T* get_if(const variant<Us...> *v) noexcept;
template<typename... Us> friend bool operator==(const variant<Us...> &lhs,
const variant<Us...> &rhs);
Memory memory;
public:
// Constructors
variant() noexcept;
variant(const variant& other);
variant(variant&& other) noexcept;
// 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).
template<
typename T,
typename = util::are_different_t<variant, T>
>
explicit variant(T&& t);
// template<class T, class... Args> explicit variant(Args&&... args);
// FIXME: other constructors
// Destructor
~variant();
// Assignment
variant& operator=(const variant& rhs);
variant& operator=(variant &&rhs) noexcept;
// SFINAE trick to avoid operator=(T&&) with T=variant<>, see comment above
template<
typename T,
typename = util::are_different_t<variant, T>
>
variant& operator=(T&& t) noexcept;
// Observers
std::size_t index() const noexcept;
// FIXME: valueless_by_exception()
// Modifiers
// FIXME: emplace()
void swap(variant &rhs) noexcept;
// Non-C++17x!
template<typename T> static constexpr std::size_t index_of();
};
// FIMXE: visit
template<typename T, typename... Types>
T* get_if(util::variant<Types...>* v) noexcept;
template<typename T, typename... Types>
const T* get_if(const util::variant<Types...>* v) noexcept;
template<typename T, typename... Types>
T& get(util::variant<Types...> &v);
template<typename T, typename... Types>
const T& get(const util::variant<Types...> &v);
template<std::size_t Index, typename... Types>
typename util::type_list_element<Index, Types...>::type& get(util::variant<Types...> &v);
template<std::size_t Index, typename... Types>
const typename util::type_list_element<Index, Types...>::type& get(const util::variant<Types...> &v);
template<typename T, typename... Types>
bool holds_alternative(const util::variant<Types...> &v) noexcept;
// Visitor
namespace detail
{
struct visitor_interface {};
// Class `visitor_return_type_deduction_helper`
// introduces solution for deduction `return_type` in `visit` function in common way
// for both Lambda and class Visitor and keep one interface invocation point: `visit` only
// his helper class is required to unify return_type deduction mechanism because
// for Lambda it is possible to take type of `decltype(visitor(get<0>(var)))`
// but for class Visitor there is no operator() in base case,
// because it provides `operator() (std::size_t index, ...)`
// So `visitor_return_type_deduction_helper` expose `operator()`
// uses only for class Visitor only for deduction `return type` in visit()
template<typename R>
struct visitor_return_type_deduction_helper
{
using return_type = R;
// to be used in Lambda return type deduction context only
template<typename T>
return_type operator() (T&&);
};
}
// Special purpose `static_visitor` can receive additional arguments
template<typename R, typename Impl>
struct static_visitor : public detail::visitor_interface,
public detail::visitor_return_type_deduction_helper<R> {
// assign responsibility for return type deduction to helper class
using return_type = typename detail::visitor_return_type_deduction_helper<R>::return_type;
using detail::visitor_return_type_deduction_helper<R>::operator();
friend Impl;
template<typename VariantValue, typename ...Args>
return_type operator() (std::size_t index, VariantValue&& value, Args&& ...args)
{
suppress_unused_warning(index);
return static_cast<Impl*>(this)-> visit(
std::forward<VariantValue>(value),
std::forward<Args>(args)...);
}
};
// Special purpose `static_indexed_visitor` can receive additional arguments
// And make forwarding current variant index as runtime function argument to its `Impl`
template<typename R, typename Impl>
struct static_indexed_visitor : public detail::visitor_interface,
public detail::visitor_return_type_deduction_helper<R> {
// assign responsibility for return type deduction to helper class
using return_type = typename detail::visitor_return_type_deduction_helper<R>::return_type;
using detail::visitor_return_type_deduction_helper<R>::operator();
friend Impl;
template<typename VariantValue, typename ...Args>
return_type operator() (std::size_t Index, VariantValue&& value, Args&& ...args)
{
return static_cast<Impl*>(this)-> visit(Index,
std::forward<VariantValue>(value),
std::forward<Args>(args)...);
}
};
template <class T>
struct variant_size;
template <class... Types>
struct variant_size<util::variant<Types...>>
: std::integral_constant<std::size_t, sizeof...(Types)> { };
// FIXME: T&&, const TT&& versions.
// Implementation //////////////////////////////////////////////////////////
template<typename... Ts>
variant<Ts...>::variant() noexcept
{
typedef typename std::tuple_element<0, std::tuple<Ts...> >::type TFirst;
new (memory) TFirst();
}
template<typename... Ts>
variant<Ts...>::variant(const variant &other)
: m_index(other.m_index)
{
(cctrs()[m_index])(memory, other.memory);
}
template<typename... Ts>
variant<Ts...>::variant(variant &&other) noexcept
: m_index(other.m_index)
{
(mctrs()[m_index])(memory, other.memory);
}
template<typename... Ts>
template<class T, typename>
variant<Ts...>::variant(T&& t)
: m_index(util::type_list_index<util::decay_t<T>, Ts...>::value)
{
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>
variant<Ts...>::~variant()
{
(dtors()[m_index])(memory);
}
template<typename... Ts>
variant<Ts...>& variant<Ts...>::operator=(const variant<Ts...> &rhs)
{
if (m_index != rhs.m_index)
{
(dtors()[ m_index])(memory);
(cctrs()[rhs.m_index])(memory, rhs.memory);
m_index = rhs.m_index;
}
else
{
(cpyrs()[rhs.m_index])(memory, rhs.memory);
}
return *this;
}
template<typename... Ts>
variant<Ts...>& variant<Ts...>::operator=(variant<Ts...> &&rhs) noexcept
{
if (m_index != rhs.m_index)
{
(dtors()[ m_index])(memory);
(mctrs()[rhs.m_index])(memory, rhs.memory);
m_index = rhs.m_index;
}
else
{
(mvers()[rhs.m_index])(memory, rhs.memory);
}
return *this;
}
template<typename... Ts>
template<typename T, typename>
variant<Ts...>& variant<Ts...>::operator=(T&& t) noexcept
{
using decayed_t = util::decay_t<T>;
// FIXME: No version with implicit type conversion available!
const constexpr std::size_t t_index =
util::type_list_index<decayed_t, Ts...>::value;
const constexpr bool is_lvalue_arg = std::is_lvalue_reference<T>::value;
if (t_index != m_index)
{
(dtors()[m_index])(memory);
(cnvrt_ctors<is_lvalue_arg>()[t_index])(memory, &t);
m_index = t_index;
}
else
{
(cnvrt_assgnrs<is_lvalue_arg>()[m_index])(memory, &t);
}
return *this;
}
template<typename... Ts>
std::size_t util::variant<Ts...>::index() const noexcept
{
return m_index;
}
template<typename... Ts>
void variant<Ts...>::swap(variant<Ts...> &rhs) noexcept
{
if (m_index == rhs.index())
{
(swprs()[m_index](memory, rhs.memory));
}
else
{
variant<Ts...> tmp(std::move(*this));
*this = std::move(rhs);
rhs = std::move(tmp);
}
}
template<typename... Ts>
template<typename T>
constexpr std::size_t variant<Ts...>::index_of()
{
return util::type_list_index<T, Ts...>::value; // FIXME: tests!
}
template<typename T, typename... Types>
T* get_if(util::variant<Types...>* v) noexcept
{
const constexpr std::size_t t_index =
util::type_list_index<T, Types...>::value;
if (v && v->index() == t_index)
return (T*)(&v->memory); // workaround for ICC 2019
// original code: return reinterpret_cast<T&>(v.memory);
return nullptr;
}
template<typename T, typename... Types>
const T* get_if(const util::variant<Types...>* v) noexcept
{
const constexpr std::size_t t_index =
util::type_list_index<T, Types...>::value;
if (v && v->index() == t_index)
return (const T*)(&v->memory); // workaround for ICC 2019
// original code: return reinterpret_cast<const T&>(v.memory);
return nullptr;
}
template<typename T, typename... Types>
T& get(util::variant<Types...> &v)
{
if (auto* p = get_if<T>(&v))
return *p;
else
throw_error(bad_variant_access());
}
template<typename T, typename... Types>
const T& get(const util::variant<Types...> &v)
{
if (auto* p = get_if<T>(&v))
return *p;
else
throw_error(bad_variant_access());
}
template<std::size_t Index, typename... Types>
typename util::type_list_element<Index, Types...>::type& get(util::variant<Types...> &v)
{
using ReturnType = typename util::type_list_element<Index, Types...>::type;
return const_cast<ReturnType&>(get<Index, Types...>(static_cast<const util::variant<Types...> &>(v)));
}
template<std::size_t Index, typename... Types>
const typename util::type_list_element<Index, Types...>::type& get(const util::variant<Types...> &v)
{
static_assert(Index < sizeof...(Types),
"`Index` it out of bound of `util::variant` type list");
using ReturnType = typename util::type_list_element<Index, Types...>::type;
return get<ReturnType>(v);
}
template<typename T, typename... Types>
bool holds_alternative(const util::variant<Types...> &v) noexcept
{
return v.index() == util::variant<Types...>::template index_of<T>();
}
template<typename... Us> bool operator==(const variant<Us...> &lhs,
const variant<Us...> &rhs)
{
using V = variant<Us...>;
// Instantiate table only here since it requires operator== for <Us...>
// <Us...> should have operator== only if this one is used, not in general
static const std::array<typename V::Equal, sizeof...(Us)> eqs = {
{(&V::template equal_h<Us>::help)...}
};
if (lhs.index() != rhs.index())
return false;
return (eqs[lhs.index()])(lhs.memory, rhs.memory);
}
template<typename... Us> bool operator!=(const variant<Us...> &lhs,
const variant<Us...> &rhs)
{
return !(lhs == rhs);
}
namespace detail
{
// terminate recursion implementation for `non-void` ReturnType
template<typename ReturnType, std::size_t CurIndex, std::size_t ElemCount,
typename Visitor, typename Variant, typename... VisitorArgs>
ReturnType apply_visitor_impl(Visitor&&, Variant&,
std::true_type, std::false_type,
VisitorArgs&& ...)
{
return {};
}
// terminate recursion implementation for `void` ReturnType
template<typename ReturnType, std::size_t CurIndex, std::size_t ElemCount,
typename Visitor, typename Variant, typename... VisitorArgs>
void apply_visitor_impl(Visitor&&, Variant&,
std::true_type, std::true_type,
VisitorArgs&& ...)
{
}
// Intermediate resursion processor for Lambda Visitors
template<typename ReturnType, std::size_t CurIndex, std::size_t ElemCount,
typename Visitor, typename Variant, bool no_return_value, typename... VisitorArgs>
typename std::enable_if<!std::is_base_of<visitor_interface, typename std::decay<Visitor>::type>::value, ReturnType>::type
apply_visitor_impl(Visitor&& visitor, Variant&& v, std::false_type not_processed,
std::integral_constant<bool, no_return_value> should_no_return,
VisitorArgs&& ...args)
{
static_assert(std::is_same<ReturnType, decltype(visitor(get<CurIndex>(v)))>::value,
"Different `ReturnType`s detected! All `Visitor::visit` or `overload_lamba_set`"
" must return the same type");
suppress_unused_warning(not_processed);
if (v.index() == CurIndex)
{
return visitor.operator()(get<CurIndex>(v), std::forward<VisitorArgs>(args)... );
}
using is_variant_processed_t = std::integral_constant<bool, CurIndex + 1 >= ElemCount>;
return apply_visitor_impl<ReturnType, CurIndex +1, ElemCount>(
std::forward<Visitor>(visitor),
std::forward<Variant>(v),
is_variant_processed_t{},
should_no_return,
std::forward<VisitorArgs>(args)...);
}
//Visual Studio 2014 compilation fix: cast visitor to base class before invoke operator()
template<std::size_t CurIndex, typename ReturnType, typename Visitor, class Value, typename... VisitorArgs>
typename std::enable_if<std::is_base_of<static_visitor<ReturnType, typename std::decay<Visitor>::type>,
typename std::decay<Visitor>::type>::value, ReturnType>::type
invoke_class_visitor(Visitor& visitor, Value&& v, VisitorArgs&&...args)
{
return static_cast<static_visitor<ReturnType, typename std::decay<Visitor>::type>&>(visitor).operator() (CurIndex, std::forward<Value>(v), std::forward<VisitorArgs>(args)... );
}
//Visual Studio 2014 compilation fix: cast visitor to base class before invoke operator()
template<std::size_t CurIndex, typename ReturnType, typename Visitor, class Value, typename... VisitorArgs>
typename std::enable_if<std::is_base_of<static_indexed_visitor<ReturnType, typename std::decay<Visitor>::type>,
typename std::decay<Visitor>::type>::value, ReturnType>::type
invoke_class_visitor(Visitor& visitor, Value&& v, VisitorArgs&&...args)
{
return static_cast<static_indexed_visitor<ReturnType, typename std::decay<Visitor>::type>&>(visitor).operator() (CurIndex, std::forward<Value>(v), std::forward<VisitorArgs>(args)... );
}
// Intermediate recursion processor for special case `visitor_interface` derived Visitors
template<typename ReturnType, std::size_t CurIndex, std::size_t ElemCount,
typename Visitor, typename Variant, bool no_return_value, typename... VisitorArgs>
typename std::enable_if<std::is_base_of<visitor_interface, typename std::decay<Visitor>::type>::value, ReturnType>::type
apply_visitor_impl(Visitor&& visitor, Variant&& v, std::false_type not_processed,
std::integral_constant<bool, no_return_value> should_no_return,
VisitorArgs&& ...args)
{
static_assert(std::is_same<ReturnType, decltype(visitor(get<CurIndex>(v)))>::value,
"Different `ReturnType`s detected! All `Visitor::visit` or `overload_lamba_set`"
" must return the same type");
suppress_unused_warning(not_processed);
if (v.index() == CurIndex)
{
return invoke_class_visitor<CurIndex, ReturnType>(visitor, get<CurIndex>(v), std::forward<VisitorArgs>(args)... );
}
using is_variant_processed_t = std::integral_constant<bool, CurIndex + 1 >= ElemCount>;
return apply_visitor_impl<ReturnType, CurIndex +1, ElemCount>(
std::forward<Visitor>(visitor),
std::forward<Variant>(v),
is_variant_processed_t{},
should_no_return,
std::forward<VisitorArgs>(args)...);
}
} // namespace detail
template<typename Visitor, typename Variant, typename... VisitorArg>
auto visit(Visitor &visitor, const Variant& var, VisitorArg &&...args) -> decltype(visitor(get<0>(var)))
{
constexpr std::size_t varsize = util::variant_size<Variant>::value;
static_assert(varsize != 0, "utils::variant must contains one type at least ");
using is_variant_processed_t = std::false_type;
using ReturnType = decltype(visitor(get<0>(var)));
using return_t = std::is_same<ReturnType, void>;
return detail::apply_visitor_impl<ReturnType, 0, varsize, Visitor>(
std::forward<Visitor>(visitor),
var, is_variant_processed_t{},
return_t{},
std::forward<VisitorArg>(args)...);
}
template<typename Visitor, typename Variant>
auto visit(Visitor&& visitor, const Variant& var) -> decltype(visitor(get<0>(var)))
{
constexpr std::size_t varsize = util::variant_size<Variant>::value;
static_assert(varsize != 0, "utils::variant must contains one type at least ");
using is_variant_processed_t = std::false_type;
using ReturnType = decltype(visitor(get<0>(var)));
using return_t = std::is_same<ReturnType, void>;
return detail::apply_visitor_impl<ReturnType, 0, varsize, Visitor>(
std::forward<Visitor>(visitor),
var, is_variant_processed_t{},
return_t{});
}
} // namespace util
} // namespace cv
#endif // OPENCV_GAPI_UTIL_VARIANT_HPP