value's exception safety fixes

This commit is contained in:
BlackMATov
2023-07-20 10:37:10 +07:00
parent c44b5bf614
commit a408421e45
4 changed files with 98 additions and 24 deletions

View File

@@ -9507,7 +9507,7 @@ namespace meta_hpp
}
}
static void do_copy(const uvalue& self, uvalue& to) noexcept {
static void do_copy(const uvalue& self, uvalue& to) {
META_HPP_DEV_ASSERT(!to);
auto&& [tag, vtable] = unpack_vtag(self);
@@ -9548,15 +9548,21 @@ namespace meta_hpp
if ( l && r ) {
if ( unpack_vtag(l).first == storage_e::external ) {
r = std::exchange(l, std::move(r));
uvalue o;
do_move(std::move(l), o);
do_move(std::move(r), l);
do_move(std::move(o), r);
} else {
l = std::exchange(r, std::move(l));
uvalue o;
do_move(std::move(r), o);
do_move(std::move(l), r);
do_move(std::move(o), l);
}
} else {
if ( l ) {
r = std::move(l);
do_move(std::move(l), r);
} else {
l = std::move(r);
do_move(std::move(r), l);
}
}
}
@@ -9667,16 +9673,14 @@ namespace meta_hpp
inline uvalue& uvalue::operator=(uvalue&& other) noexcept {
if ( this != &other ) {
vtable_t::do_reset(*this);
vtable_t::do_move(std::move(other), *this);
uvalue{std::move(other)}.swap(*this);
}
return *this;
}
inline uvalue& uvalue::operator=(const uvalue& other) {
if ( this != &other ) {
vtable_t::do_reset(*this);
vtable_t::do_copy(other, *this);
uvalue{other}.swap(*this);
}
return *this;
}
@@ -9688,8 +9692,7 @@ namespace meta_hpp
template < typename T, typename Tp, typename >
uvalue& uvalue::operator=(T&& val) {
vtable_t::do_reset(*this);
vtable_t::do_ctor<T>(*this, std::forward<T>(val));
uvalue{std::forward<T>(val)}.swap(*this);
return *this;
}

View File

@@ -0,0 +1,68 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021-2023, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#include <meta.hpp/meta_all.hpp>
#include <doctest/doctest.h>
#if !defined(META_HPP_NO_EXCEPTIONS)
namespace
{
struct throw_on_copy {
throw_on_copy() = default;
[[noreturn]] throw_on_copy(const throw_on_copy&) {
throw 42;
}
};
struct throw_on_move {
throw_on_move() = default;
[[noreturn]] throw_on_move(throw_on_move&&) {
throw 42;
}
[[noreturn]] throw_on_move(const throw_on_move&) {
throw 42;
}
};
}
TEST_CASE("meta/meta_issues/random/4") {
namespace meta = meta_hpp;
meta::uvalue v{42};
CHECK(v.get_type() == meta::resolve_type<int>());
SUBCASE("1") {
CHECK_THROWS(v = throw_on_copy{});
CHECK(v.get_type() == meta::resolve_type<int>());
}
SUBCASE("2") {
CHECK_THROWS(v = throw_on_move{});
CHECK(v.get_type() == meta::resolve_type<int>());
}
SUBCASE("3") {
meta::uvalue v2{std::in_place_type<throw_on_copy>};
CHECK_THROWS(v = v2);
CHECK(v.get_type() == meta::resolve_type<int>());
CHECK_NOTHROW(v = std::move(v2));
CHECK(v.get_type() == meta::resolve_type<throw_on_copy>());
}
SUBCASE("4") {
meta::uvalue v2{std::in_place_type<throw_on_move>};
CHECK_THROWS(v = v2);
CHECK(v.get_type() == meta::resolve_type<int>());
CHECK_NOTHROW(v = std::move(v2));
CHECK(v.get_type() == meta::resolve_type<throw_on_move>());
}
}
#endif

View File

@@ -381,7 +381,7 @@ TEST_CASE("meta/meta_utilities/value") {
val_dst = std::move(val_src2);
CHECK(val_dst.as<ivec2>() == ivec2{1,2});
CHECK(ivec2::move_constructor_counter == 2);
CHECK(ivec2::move_constructor_counter == 3);
CHECK(ivec2::copy_constructor_counter == 0);
}
@@ -400,7 +400,7 @@ TEST_CASE("meta/meta_utilities/value") {
val_dst = val_src2;
CHECK(val_dst.as<ivec2>() == ivec2{1,2});
CHECK(ivec2::move_constructor_counter == 1);
CHECK(ivec2::move_constructor_counter == 2);
CHECK(ivec2::copy_constructor_counter == 1);
CHECK(val_src2.as<ivec2>() == ivec2{1,2});

View File

@@ -111,7 +111,7 @@ namespace meta_hpp
}
}
static void do_copy(const uvalue& self, uvalue& to) noexcept {
static void do_copy(const uvalue& self, uvalue& to) {
META_HPP_DEV_ASSERT(!to);
auto&& [tag, vtable] = unpack_vtag(self);
@@ -152,15 +152,21 @@ namespace meta_hpp
if ( l && r ) {
if ( unpack_vtag(l).first == storage_e::external ) {
r = std::exchange(l, std::move(r));
uvalue o;
do_move(std::move(l), o);
do_move(std::move(r), l);
do_move(std::move(o), r);
} else {
l = std::exchange(r, std::move(l));
uvalue o;
do_move(std::move(r), o);
do_move(std::move(l), r);
do_move(std::move(o), l);
}
} else {
if ( l ) {
r = std::move(l);
do_move(std::move(l), r);
} else {
l = std::move(r);
do_move(std::move(r), l);
}
}
}
@@ -271,16 +277,14 @@ namespace meta_hpp
inline uvalue& uvalue::operator=(uvalue&& other) noexcept {
if ( this != &other ) {
vtable_t::do_reset(*this);
vtable_t::do_move(std::move(other), *this);
uvalue{std::move(other)}.swap(*this);
}
return *this;
}
inline uvalue& uvalue::operator=(const uvalue& other) {
if ( this != &other ) {
vtable_t::do_reset(*this);
vtable_t::do_copy(other, *this);
uvalue{other}.swap(*this);
}
return *this;
}
@@ -292,8 +296,7 @@ namespace meta_hpp
template < typename T, typename Tp, typename >
uvalue& uvalue::operator=(T&& val) {
vtable_t::do_reset(*this);
vtable_t::do_ctor<T>(*this, std::forward<T>(val));
uvalue{std::forward<T>(val)}.swap(*this);
return *this;
}