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 <type_traits>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include "../serialize.h"
|
#include "../serialize.h"
|
||||||
#include "../invoke.h"
|
#include "../utility.h"
|
||||||
|
|
||||||
namespace dlib
|
namespace dlib
|
||||||
{
|
{
|
||||||
@ -139,41 +139,38 @@ namespace dlib
|
|||||||
typename std::aligned_union<0, Types...>::type mem;
|
typename std::aligned_union<0, Types...>::type mem;
|
||||||
int type_identity = 0;
|
int type_identity = 0;
|
||||||
|
|
||||||
template<
|
template<typename F, typename TSU>
|
||||||
typename F,
|
struct dispatcher
|
||||||
typename TSU,
|
|
||||||
std::size_t I
|
|
||||||
>
|
|
||||||
static void apply_to_contents_as_type(
|
|
||||||
F&& f,
|
|
||||||
TSU&& me
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
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>>()));
|
||||||
|
|
||||||
template<
|
constexpr static const bool is_noexcept =
|
||||||
typename F,
|
And<std::is_default_constructible<R>::value &&
|
||||||
typename TSU,
|
noexcept(std::declval<F>()(std::declval<TSU>().template unchecked_get<Types>()))...>::value;
|
||||||
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[] = {
|
template<size_t I, typename std::enable_if<I == N, bool>::type = true>
|
||||||
/*! Empty (type_identity == 0) case !*/
|
inline R operator()(F&&, TSU&&, size_<I>)
|
||||||
[](F&&, TSU&&) {
|
noexcept(is_noexcept) { return R(); }
|
||||||
},
|
|
||||||
/*! 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<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>
|
||||||
|
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>
|
template <typename T>
|
||||||
@ -402,19 +399,19 @@ namespace dlib
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename F>
|
template <typename F>
|
||||||
void apply_to_contents(
|
auto apply_to_contents(
|
||||||
F&& f
|
F&& f
|
||||||
)
|
) noexcept(noexcept(dispatch(std::forward<F>(f), std::declval<type_safe_union&>())))
|
||||||
{
|
-> decltype(dispatch(std::forward<F>(f), *this)) {
|
||||||
apply_to_contents_impl(std::forward<F>(f), *this, dlib::make_index_sequence<sizeof...(Types)>{});
|
return dispatch(std::forward<F>(f), *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename F>
|
template <typename F>
|
||||||
void apply_to_contents(
|
auto apply_to_contents(
|
||||||
F&& f
|
F&& f
|
||||||
) const
|
) const noexcept(noexcept(dispatch(std::forward<F>(f), std::declval<const type_safe_union&>())))
|
||||||
{
|
-> decltype(dispatch(std::forward<F>(f), *this)) {
|
||||||
apply_to_contents_impl(std::forward<F>(f), *this, dlib::make_index_sequence<sizeof...(Types)>{});
|
return dispatch(std::forward<F>(f), *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -492,7 +489,7 @@ namespace dlib
|
|||||||
{
|
{
|
||||||
if (type_identity == item.type_identity)
|
if (type_identity == item.type_identity)
|
||||||
{
|
{
|
||||||
item.apply_to_contents(swap_to{*this});
|
apply_to_contents(swap_to{item});
|
||||||
}
|
}
|
||||||
else if (is_empty())
|
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<
|
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>{});
|
detail::for_each_type_impl(std::forward<F>(f), std::forward<TSU>(tsu), dlib::make_index_sequence<Size>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<
|
template<typename F, typename TSU>
|
||||||
typename F,
|
|
||||||
typename TSU,
|
|
||||||
typename Tsu = typename std::decay<TSU>::type,
|
|
||||||
typename T0 = type_safe_union_alternative_t<0, Tsu>
|
|
||||||
>
|
|
||||||
auto visit(
|
auto visit(
|
||||||
F&& f,
|
F&& f,
|
||||||
TSU&& tsu
|
TSU&& tsu
|
||||||
) -> dlib::invoke_result_t<F, decltype(tsu.template cast_to<T0>())>
|
) noexcept(noexcept(tsu.apply_to_contents(std::forward<F>(f))))
|
||||||
{
|
-> decltype(tsu.apply_to_contents(std::forward<F>(f))) {
|
||||||
using ReturnType = dlib::invoke_result_t<F, decltype(tsu.template cast_to<T0>())>;
|
return tsu.apply_to_contents(std::forward<F>(f));
|
||||||
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>{});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
|
@ -124,6 +124,19 @@ namespace dlib
|
|||||||
struct are_nothrow_swappable<T> : is_nothrow_swappable<T> {};
|
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_
|
#endif //DLIB_UTILITY_Hh_
|
||||||
|
Loading…
Reference in New Issue
Block a user