diff --git a/dlib/type_safe_union/type_safe_union_kernel.h b/dlib/type_safe_union/type_safe_union_kernel.h index 342858e2c..e4d067744 100644 --- a/dlib/type_safe_union/type_safe_union_kernel.h +++ b/dlib/type_safe_union/type_safe_union_kernel.h @@ -9,7 +9,7 @@ #include #include #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 + struct dispatcher { - std::forward(f)(me.template unchecked_get>()); - } + constexpr static const std::size_t N = sizeof...(Types); + using R = decltype(std::declval()(std::declval().template unchecked_get>())); - template< - typename F, - typename TSU, - std::size_t... I - > - static void apply_to_contents_impl( - F&& f, - TSU&& me, - dlib::index_sequence - ) - { - using func_t = void(*)(F&&, TSU&&); + constexpr static const bool is_noexcept = + And::value && + noexcept(std::declval()(std::declval().template unchecked_get()))...>::value; - const func_t vtable[] = { - /*! Empty (type_identity == 0) case !*/ - [](F&&, TSU&&) { - }, - /*! Non-empty cases !*/ - &apply_to_contents_as_type... - }; + template::type = true> + inline R operator()(F&&, TSU&&, size_) + noexcept(is_noexcept) { return R(); } - return vtable[me.get_current_type_id()](std::forward(f), std::forward(me)); + template::type = true> + inline R operator()(F&& f, TSU&& me, size_) + noexcept(is_noexcept) + { + if (me.is_empty()) + return R(); + else if (me.get_current_type_id() == (I+1)) + return std::forward(f)(me.template unchecked_get>()); + else + return (*this)(std::forward(f), std::forward(me), size_{}); + } + }; + + template + static inline auto dispatch(F&& f, TSU&& me) + noexcept(noexcept(dispatcher{}(std::forward(f), std::forward(me), size_<0>{}))) + -> decltype(dispatcher{}(std::forward(f), std::forward(me), size_<0>{})) { + return dispatcher{}(std::forward(f), std::forward(me), size_<0>{}); } template @@ -402,19 +399,19 @@ namespace dlib } template - void apply_to_contents( + auto apply_to_contents( F&& f - ) - { - apply_to_contents_impl(std::forward(f), *this, dlib::make_index_sequence{}); + ) noexcept(noexcept(dispatch(std::forward(f), std::declval()))) + -> decltype(dispatch(std::forward(f), *this)) { + return dispatch(std::forward(f), *this); } template - void apply_to_contents( + auto apply_to_contents( F&& f - ) const - { - apply_to_contents_impl(std::forward(f), *this, dlib::make_index_sequence{}); + ) const noexcept(noexcept(dispatch(std::forward(f), std::declval()))) + -> decltype(dispatch(std::forward(f), *this)) { + return dispatch(std::forward(f), *this); } template @@ -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::type; - using T = type_safe_union_alternative_t; - return dlib::invoke(std::forward(f), tsu.template cast_to()); - } - - template< - typename R, - typename F, - typename TSU, - std::size_t... I - > - R visit_impl( - F&& f, - TSU&& tsu, - dlib::index_sequence - ) - { - 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... - }; - - return vtable[tsu.get_current_type_id()](std::forward(f), std::forward(tsu)); - } } template< @@ -598,20 +553,13 @@ namespace dlib detail::for_each_type_impl(std::forward(f), std::forward(tsu), dlib::make_index_sequence{}); } - template< - typename F, - typename TSU, - typename Tsu = typename std::decay::type, - typename T0 = type_safe_union_alternative_t<0, Tsu> - > + template auto visit( F&& f, TSU&& tsu - ) -> dlib::invoke_result_t())> - { - using ReturnType = dlib::invoke_result_t())>; - static constexpr std::size_t Size = type_safe_union_size::value; - return detail::visit_impl(std::forward(f), std::forward(tsu), dlib::make_index_sequence{}); + ) noexcept(noexcept(tsu.apply_to_contents(std::forward(f)))) + -> decltype(tsu.apply_to_contents(std::forward(f))) { + return tsu.apply_to_contents(std::forward(f)); } namespace detail diff --git a/dlib/utility.h b/dlib/utility.h index 5a200eb51..8298a87fb 100644 --- a/dlib/utility.h +++ b/dlib/utility.h @@ -124,6 +124,19 @@ namespace dlib struct are_nothrow_swappable : is_nothrow_swappable {}; // --------------------------------------------------------------------- + + template + struct And : std::integral_constant::value> {}; + + template + struct And : std::integral_constant{}; + + // --------------------------------------------------------------------- + + template + using size_ = std::integral_constant; + + // --------------------------------------------------------------------- } #endif //DLIB_UTILITY_Hh_