mirror of
https://github.com/davisking/dlib.git
synced 2024-11-01 10:14:53 +08:00
type_safe_union : visit() and apply_to_contents() performance improvements (#2615)
This commit is contained in:
parent
7c32e1c18e
commit
3c73978de8
@ -9,7 +9,7 @@
|
||||
#include <type_traits>
|
||||
#include <functional>
|
||||
#include "../serialize.h"
|
||||
#include "../invoke.h"
|
||||
#include "../utility.h"
|
||||
|
||||
namespace dlib
|
||||
{
|
||||
@ -139,41 +139,38 @@ namespace dlib
|
||||
typename std::aligned_union<0, Types...>::type mem;
|
||||
int type_identity = 0;
|
||||
|
||||
template<
|
||||
typename F,
|
||||
typename TSU,
|
||||
std::size_t I
|
||||
>
|
||||
static void apply_to_contents_as_type(
|
||||
F&& f,
|
||||
TSU&& me
|
||||
)
|
||||
template<typename F, typename TSU>
|
||||
struct dispatcher
|
||||
{
|
||||
std::forward<F>(f)(me.template unchecked_get<get_type_t<I>>());
|
||||
constexpr static const std::size_t N = sizeof...(Types);
|
||||
using R = decltype(std::declval<F>()(std::declval<TSU>().template unchecked_get<get_type_t<0>>()));
|
||||
|
||||
constexpr static const bool is_noexcept =
|
||||
And<std::is_default_constructible<R>::value &&
|
||||
noexcept(std::declval<F>()(std::declval<TSU>().template unchecked_get<Types>()))...>::value;
|
||||
|
||||
template<size_t I, typename std::enable_if<I == N, bool>::type = true>
|
||||
inline R operator()(F&&, TSU&&, size_<I>)
|
||||
noexcept(is_noexcept) { return R(); }
|
||||
|
||||
template<size_t I, typename std::enable_if<I < N, bool>::type = true>
|
||||
inline R operator()(F&& f, TSU&& me, size_<I>)
|
||||
noexcept(is_noexcept)
|
||||
{
|
||||
if (me.is_empty())
|
||||
return R();
|
||||
else if (me.get_current_type_id() == (I+1))
|
||||
return std::forward<F>(f)(me.template unchecked_get<get_type_t<I>>());
|
||||
else
|
||||
return (*this)(std::forward<F>(f), std::forward<TSU>(me), size_<I+1>{});
|
||||
}
|
||||
|
||||
template<
|
||||
typename F,
|
||||
typename TSU,
|
||||
std::size_t... I
|
||||
>
|
||||
static void apply_to_contents_impl(
|
||||
F&& f,
|
||||
TSU&& me,
|
||||
dlib::index_sequence<I...>
|
||||
)
|
||||
{
|
||||
using func_t = void(*)(F&&, TSU&&);
|
||||
|
||||
const func_t vtable[] = {
|
||||
/*! Empty (type_identity == 0) case !*/
|
||||
[](F&&, TSU&&) {
|
||||
},
|
||||
/*! Non-empty cases !*/
|
||||
&apply_to_contents_as_type<F&&,TSU&&,I>...
|
||||
};
|
||||
|
||||
return vtable[me.get_current_type_id()](std::forward<F>(f), std::forward<TSU>(me));
|
||||
template<typename F, typename TSU>
|
||||
static inline auto dispatch(F&& f, TSU&& me)
|
||||
noexcept(noexcept(dispatcher<F&&,TSU&&>{}(std::forward<F>(f), std::forward<TSU>(me), size_<0>{})))
|
||||
-> decltype(dispatcher<F&&,TSU&&>{}(std::forward<F>(f), std::forward<TSU>(me), size_<0>{})) {
|
||||
return dispatcher<F&&,TSU&&>{}(std::forward<F>(f), std::forward<TSU>(me), size_<0>{});
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@ -402,19 +399,19 @@ namespace dlib
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void apply_to_contents(
|
||||
auto apply_to_contents(
|
||||
F&& f
|
||||
)
|
||||
{
|
||||
apply_to_contents_impl(std::forward<F>(f), *this, dlib::make_index_sequence<sizeof...(Types)>{});
|
||||
) noexcept(noexcept(dispatch(std::forward<F>(f), std::declval<type_safe_union&>())))
|
||||
-> decltype(dispatch(std::forward<F>(f), *this)) {
|
||||
return dispatch(std::forward<F>(f), *this);
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void apply_to_contents(
|
||||
auto apply_to_contents(
|
||||
F&& f
|
||||
) const
|
||||
{
|
||||
apply_to_contents_impl(std::forward<F>(f), *this, dlib::make_index_sequence<sizeof...(Types)>{});
|
||||
) const noexcept(noexcept(dispatch(std::forward<F>(f), std::declval<const type_safe_union&>())))
|
||||
-> decltype(dispatch(std::forward<F>(f), *this)) {
|
||||
return dispatch(std::forward<F>(f), *this);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@ -492,7 +489,7 @@ namespace dlib
|
||||
{
|
||||
if (type_identity == item.type_identity)
|
||||
{
|
||||
item.apply_to_contents(swap_to{*this});
|
||||
apply_to_contents(swap_to{item});
|
||||
}
|
||||
else if (is_empty())
|
||||
{
|
||||
@ -540,48 +537,6 @@ namespace dlib
|
||||
)...
|
||||
};
|
||||
}
|
||||
|
||||
template<
|
||||
typename R,
|
||||
typename F,
|
||||
typename TSU,
|
||||
std::size_t I
|
||||
>
|
||||
R visit_impl_as_type(
|
||||
F&& f,
|
||||
TSU&& tsu
|
||||
)
|
||||
{
|
||||
using Tsu = typename std::decay<TSU>::type;
|
||||
using T = type_safe_union_alternative_t<I, Tsu>;
|
||||
return dlib::invoke(std::forward<F>(f), tsu.template cast_to<T>());
|
||||
}
|
||||
|
||||
template<
|
||||
typename R,
|
||||
typename F,
|
||||
typename TSU,
|
||||
std::size_t... I
|
||||
>
|
||||
R visit_impl(
|
||||
F&& f,
|
||||
TSU&& tsu,
|
||||
dlib::index_sequence<I...>
|
||||
)
|
||||
{
|
||||
using func_t = R(*)(F&&, TSU&&);
|
||||
|
||||
const func_t vtable[] = {
|
||||
/*! Empty (type_identity == 0) case !*/
|
||||
[](F&&, TSU&&) {
|
||||
return R();
|
||||
},
|
||||
/*! Non-empty cases !*/
|
||||
&visit_impl_as_type<R,F&&,TSU&&,I>...
|
||||
};
|
||||
|
||||
return vtable[tsu.get_current_type_id()](std::forward<F>(f), std::forward<TSU>(tsu));
|
||||
}
|
||||
}
|
||||
|
||||
template<
|
||||
@ -598,20 +553,13 @@ namespace dlib
|
||||
detail::for_each_type_impl(std::forward<F>(f), std::forward<TSU>(tsu), dlib::make_index_sequence<Size>{});
|
||||
}
|
||||
|
||||
template<
|
||||
typename F,
|
||||
typename TSU,
|
||||
typename Tsu = typename std::decay<TSU>::type,
|
||||
typename T0 = type_safe_union_alternative_t<0, Tsu>
|
||||
>
|
||||
template<typename F, typename TSU>
|
||||
auto visit(
|
||||
F&& f,
|
||||
TSU&& tsu
|
||||
) -> dlib::invoke_result_t<F, decltype(tsu.template cast_to<T0>())>
|
||||
{
|
||||
using ReturnType = dlib::invoke_result_t<F, decltype(tsu.template cast_to<T0>())>;
|
||||
static constexpr std::size_t Size = type_safe_union_size<Tsu>::value;
|
||||
return detail::visit_impl<ReturnType>(std::forward<F>(f), std::forward<TSU>(tsu), dlib::make_index_sequence<Size>{});
|
||||
) noexcept(noexcept(tsu.apply_to_contents(std::forward<F>(f))))
|
||||
-> decltype(tsu.apply_to_contents(std::forward<F>(f))) {
|
||||
return tsu.apply_to_contents(std::forward<F>(f));
|
||||
}
|
||||
|
||||
namespace detail
|
||||
|
@ -124,6 +124,19 @@ namespace dlib
|
||||
struct are_nothrow_swappable<T> : is_nothrow_swappable<T> {};
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
template<bool First, bool... Rest>
|
||||
struct And : std::integral_constant<bool, First && And<Rest...>::value> {};
|
||||
|
||||
template<bool Value>
|
||||
struct And<Value> : std::integral_constant<bool, Value>{};
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
template<std::size_t I>
|
||||
using size_ = std::integral_constant<std::size_t, I>;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
}
|
||||
|
||||
#endif //DLIB_UTILITY_Hh_
|
||||
|
Loading…
Reference in New Issue
Block a user