From ec9a143e078fbc9dab8a852e00ee26c1a528e072 Mon Sep 17 00:00:00 2001 From: pfeatherstone <45853521+pfeatherstone@users.noreply.github.com> Date: Mon, 27 Jun 2022 13:05:50 +0100 Subject: [PATCH] noexcept dlib::type_safe_union::swap() (#2604) * [TYPE_SAFE_UNION] removed explicit swap(). let the compiler define swap from move semantics * - added type traits: are_nothrow_move_construtible are_nothrow_move_assignable are_nothrow_copy_construtible are_nothrow_copy_assignable - everything has (conditional) noexcept specifiers * - formatting - bug fix * - added .swap() back in * - type traits - added .swap(item) and swap(a,b) back in, but with some cleanup and all the noexcept * added docs for swap(a,b) back in Co-authored-by: pfeatherstone --- dlib/type_safe_union/type_safe_union_kernel.h | 89 +++++++++++-------- .../type_safe_union_kernel_abstract.h | 7 +- dlib/utility.h | 87 ++++++++++++++++++ 3 files changed, 143 insertions(+), 40 deletions(-) diff --git a/dlib/type_safe_union/type_safe_union_kernel.h b/dlib/type_safe_union/type_safe_union_kernel.h index 04c0e473f..b6ab50600 100644 --- a/dlib/type_safe_union/type_safe_union_kernel.h +++ b/dlib/type_safe_union/type_safe_union_kernel.h @@ -177,13 +177,13 @@ namespace dlib } template - const T& unchecked_get() const + const T& unchecked_get() const noexcept { return *reinterpret_cast(&mem); } template - T& unchecked_get() + T& unchecked_get() noexcept { return *reinterpret_cast(&mem); } @@ -267,6 +267,7 @@ namespace dlib This class swaps an object with `me`. !*/ swap_to(type_safe_union& me) : _me(me) {} + template void operator()(T& x) /*! @@ -287,7 +288,9 @@ namespace dlib type_safe_union ( const type_safe_union& item - ) : type_safe_union() + ) + noexcept(are_nothrow_copy_construtible::value) + : type_safe_union() { item.apply_to_contents(assign_to{*this}); } @@ -295,6 +298,8 @@ namespace dlib type_safe_union& operator=( const type_safe_union& item ) + noexcept(are_nothrow_copy_construtible::value && + are_nothrow_copy_assignable::value) { if (item.is_empty()) destruct(); @@ -305,7 +310,9 @@ namespace dlib type_safe_union ( type_safe_union&& item - ) : type_safe_union() + ) + noexcept(are_nothrow_move_construtible::value) + : type_safe_union() { item.apply_to_contents(move_to{*this}); item.destruct(); @@ -314,6 +321,8 @@ namespace dlib type_safe_union& operator= ( type_safe_union&& item ) + noexcept(are_nothrow_move_construtible::value && + are_nothrow_move_assignable::value) { if (item.is_empty()) { @@ -333,7 +342,9 @@ namespace dlib > type_safe_union ( T&& item - ) : type_safe_union() + ) + noexcept(std::is_nothrow_constructible::type, T>::value) + : type_safe_union() { assign_to{*this}(std::forward(item)); } @@ -345,6 +356,8 @@ namespace dlib type_safe_union& operator= ( T&& item ) + noexcept(std::is_nothrow_constructible::type, T>::value && + std::is_nothrow_assignable::type, T>::value) { assign_to{*this}(std::forward(item)); return *this; @@ -359,6 +372,8 @@ namespace dlib in_place_tag, Args&&... args ) + noexcept(std::is_nothrow_constructible::value) + : type_safe_union() { construct(std::forward(args)...); } @@ -381,6 +396,7 @@ namespace dlib void emplace( Args&&... args ) + noexcept(std::is_nothrow_constructible::value) { construct(std::forward(args)...); } @@ -403,55 +419,29 @@ namespace dlib template bool contains ( - ) const + ) const noexcept { return type_identity == get_type_id(); } bool is_empty ( - ) const + ) const noexcept { return type_identity == 0; } - int get_current_type_id() const + int get_current_type_id() const noexcept { return type_identity; } - void swap ( - type_safe_union& item - ) - { - if (type_identity == item.type_identity) - { - item.apply_to_contents(swap_to{*this}); - } - else if (is_empty()) - { - item.apply_to_contents(move_to{*this}); - item.destruct(); - } - else if (item.is_empty()) - { - apply_to_contents(move_to{item}); - destruct(); - } - else - { - type_safe_union tmp; - swap(tmp); // this -> tmp - swap(item); // item -> this - tmp.swap(item); // tmp (this) -> item - } - } - template < typename T, is_valid_check = true > T& get( ) + noexcept(std::is_nothrow_default_constructible::value) { if (type_identity != get_type_id()) construct(); @@ -464,6 +454,7 @@ namespace dlib T& get( in_place_tag ) + noexcept(std::is_nothrow_default_constructible::value) { return get(); } @@ -493,13 +484,39 @@ namespace dlib else throw bad_type_safe_union_cast(); } + + void swap( + type_safe_union& item + ) noexcept(std::is_nothrow_move_constructible::value && + are_nothrow_swappable::value) + { + if (type_identity == item.type_identity) + { + item.apply_to_contents(swap_to{*this}); + } + else if (is_empty()) + { + *this = std::move(item); + } + else if (item.is_empty()) + { + item = std::move(*this); + } + else + { + type_safe_union tmp{std::move(*this)}; + *this = std::move(item); + item = std::move(tmp); + } + } }; template inline void swap ( type_safe_union& a, type_safe_union& b - ) { a.swap(b); } + ) noexcept(noexcept(a.swap(b))) + { a.swap(b); } namespace detail { diff --git a/dlib/type_safe_union/type_safe_union_kernel_abstract.h b/dlib/type_safe_union/type_safe_union_kernel_abstract.h index 00e67da61..e36376caf 100644 --- a/dlib/type_safe_union/type_safe_union_kernel_abstract.h +++ b/dlib/type_safe_union/type_safe_union_kernel_abstract.h @@ -360,16 +360,15 @@ namespace dlib ensures - swaps *this and item !*/ - }; // ---------------------------------------------------------------------------------------- template inline void swap ( - type_safe_union& a, - type_safe_union& b - ) { a.swap(b); } + type_safe_union& a, + type_safe_union& b + ) { a.swap(b); } /*! provides a global swap function !*/ diff --git a/dlib/utility.h b/dlib/utility.h index 78af92ed5..e10de2511 100644 --- a/dlib/utility.h +++ b/dlib/utility.h @@ -12,6 +12,8 @@ namespace dlib { + // --------------------------------------------------------------------- + template struct index_sequence { @@ -37,6 +39,91 @@ namespace dlib template using index_sequence_for = make_index_sequence; + + // --------------------------------------------------------------------- + + template + struct are_nothrow_move_construtible + : std::integral_constant::value && + are_nothrow_move_construtible::value> {}; + + template + struct are_nothrow_move_construtible : std::is_nothrow_move_constructible {}; + + // --------------------------------------------------------------------- + + template + struct are_nothrow_move_assignable + : std::integral_constant::value && + are_nothrow_move_assignable::value> {}; + + template + struct are_nothrow_move_assignable : std::is_nothrow_move_assignable {}; + + // --------------------------------------------------------------------- + + template + struct are_nothrow_copy_construtible + : std::integral_constant::value && + are_nothrow_copy_construtible::value> {}; + + template + struct are_nothrow_copy_construtible : std::is_nothrow_copy_constructible {}; + + // --------------------------------------------------------------------- + + template + struct are_nothrow_copy_assignable + : std::integral_constant::value && + are_nothrow_copy_assignable::value> {}; + + template + struct are_nothrow_copy_assignable : std::is_nothrow_copy_assignable {}; + + // --------------------------------------------------------------------- + + template< class... > + using void_t = void; + + // --------------------------------------------------------------------- + + namespace swappable_details + { + using std::swap; + + template + struct is_swappable : std::false_type {}; + + template + struct is_swappable(), std::declval()))>> : std::true_type {}; + + template + struct is_nothrow_swappable : + std::integral_constant::value && + noexcept(swap(std::declval(), std::declval()))> {}; + } + + // --------------------------------------------------------------------- + + template + struct is_swappable : swappable_details::is_swappable{}; + + // --------------------------------------------------------------------- + + template + struct is_nothrow_swappable : swappable_details::is_nothrow_swappable{}; + + // --------------------------------------------------------------------- + + template + struct are_nothrow_swappable + : std::integral_constant::value && + are_nothrow_swappable::value> {}; + + template + struct are_nothrow_swappable : is_nothrow_swappable {}; + + // --------------------------------------------------------------------- } #endif //DLIB_UTILITY_Hh_ \ No newline at end of file