insert_or_assign exception workarounds

This commit is contained in:
BlackMATov
2023-02-15 18:15:47 +07:00
parent f61f7ebacc
commit 8ba7a71e6b
6 changed files with 190 additions and 14 deletions

View File

@@ -386,7 +386,7 @@ namespace meta_hpp::detail
: std::logic_error(ec.message())
, error_code_{ec} {}
[[nodiscard]] const std::error_code& code() const noexcept {
[[nodiscard]] const std::error_code& get_code() const noexcept {
return error_code_;
}
@@ -756,6 +756,7 @@ namespace std
namespace meta_hpp::detail
{
template < typename Key, typename Compare, typename Allocator >
requires std::is_move_constructible_v<Key> && std::is_move_assignable_v<Key>
typename std::set<Key, Compare, Allocator>::iterator insert_or_assign( //
std::set<Key, Compare, Allocator>& set,
typename std::set<Key, Compare, Allocator>::value_type&& value
@@ -767,11 +768,20 @@ namespace meta_hpp::detail
}
auto node = set.extract(position++);
node.value() = std::move(value);
META_HPP_TRY {
node.value() = std::move(value);
}
META_HPP_CATCH(...) {
set.insert(position, std::move(node));
META_HPP_RETHROW();
}
return set.insert(position, std::move(node));
}
template < typename Key, typename Compare, typename Allocator >
requires std::is_copy_constructible_v<Key> && std::is_copy_assignable_v<Key>
typename std::set<Key, Compare, Allocator>::iterator insert_or_assign( //
std::set<Key, Compare, Allocator>& set,
const typename std::set<Key, Compare, Allocator>::value_type& value
@@ -783,7 +793,15 @@ namespace meta_hpp::detail
}
auto node = set.extract(position++);
node.value() = value;
META_HPP_TRY {
node.value() = value;
}
META_HPP_CATCH(...) {
set.insert(position, std::move(node));
META_HPP_RETHROW();
}
return set.insert(position, std::move(node));
}
}
@@ -2877,7 +2895,7 @@ namespace meta_hpp
class uvalue final {
public:
uvalue() = default;
~uvalue();
~uvalue() noexcept;
uvalue(uvalue&& other) noexcept;
uvalue(const uvalue& other);
@@ -2921,7 +2939,7 @@ namespace meta_hpp
[[nodiscard]] bool is_valid() const noexcept;
[[nodiscard]] explicit operator bool() const noexcept;
void reset();
void reset() noexcept;
void swap(uvalue& other) noexcept;
[[nodiscard]] any_type get_type() const noexcept;
@@ -8553,7 +8571,7 @@ namespace meta_hpp
namespace meta_hpp
{
inline uvalue::~uvalue() {
inline uvalue::~uvalue() noexcept {
reset();
}
@@ -8638,7 +8656,7 @@ namespace meta_hpp
return is_valid();
}
inline void uvalue::reset() {
inline void uvalue::reset() noexcept {
vtable_t::do_reset(*this);
}

View File

@@ -46,6 +46,114 @@ namespace
return l.key == r.key && l.data == r.data;
}
};
struct exception_on_move_value {
int key{};
int data{};
exception_on_move_value(int k, int d)
: key{k}
, data{d} {}
exception_on_move_value(const exception_on_move_value&) = default;
exception_on_move_value& operator=(const exception_on_move_value&) = default;
exception_on_move_value(exception_on_move_value&& other)
: key{other.key}
, data{other.data} {
if ( other.data != 42 ) {
other.key = 0;
other.data = 0;
return;
}
#if !defined(META_HPP_NO_EXCEPTIONS)
throw std::exception{};
#else
std::abort();
#endif
}
exception_on_move_value& operator=(exception_on_move_value&& other) {
if ( this == &other ) {
return *this;
}
if ( other.data != 42 ) {
key = other.key;
data = other.data;
return *this;
}
#if !defined(META_HPP_NO_EXCEPTIONS)
throw std::exception{};
#else
std::abort();
#endif
}
[[maybe_unused]]
friend bool operator<(const exception_on_move_value& l, const exception_on_move_value& r) noexcept {
return l.key < r.key;
}
[[maybe_unused]]
friend bool operator==(const exception_on_move_value& l, const exception_on_move_value& r) noexcept {
return l.key == r.key && l.data == r.data;
}
};
struct exception_on_copy_value {
int key{};
int data{};
exception_on_copy_value(int k, int d)
: key{k}
, data{d} {}
exception_on_copy_value(exception_on_copy_value&& other) = default;
exception_on_copy_value& operator=(exception_on_copy_value&& other) = default;
exception_on_copy_value(const exception_on_copy_value& other)
: key{other.key}
, data{other.data} {
if ( other.data != 42 ) {
return;
}
#if !defined(META_HPP_NO_EXCEPTIONS)
throw std::exception{};
#else
std::abort();
#endif
}
exception_on_copy_value& operator=(const exception_on_copy_value& other) {
if ( this == &other ) {
return *this;
}
if ( other.data != 42 ) {
key = other.key;
data = other.data;
return *this;
}
#if !defined(META_HPP_NO_EXCEPTIONS)
throw std::exception{};
#else
std::abort();
#endif
}
[[maybe_unused]]
friend bool operator<(const exception_on_copy_value& l, const exception_on_copy_value& r) noexcept {
return l.key < r.key;
}
[[maybe_unused]]
friend bool operator==(const exception_on_copy_value& l, const exception_on_copy_value& r) noexcept {
return l.key == r.key && l.data == r.data;
}
};
}
TEST_CASE("meta/meta_base/insert_or_assign") {
@@ -105,3 +213,34 @@ TEST_CASE("meta/meta_base/insert_or_assign") {
CHECK(s == std::set<copyable_value, std::less<>>{{1, 10}, {3, 42}});
}
}
TEST_CASE("meta/meta_base/insert_or_assign/exceptions") {
namespace meta = meta_hpp;
using meta::detail::insert_or_assign;
SUBCASE("on_move/insert") {
std::set<exception_on_move_value, std::less<>> s{{1, 10}, {3, 30}};
CHECK_THROWS(insert_or_assign(s, exception_on_move_value{2, 42}));
CHECK(s == std::set<exception_on_move_value, std::less<>>{{1, 10}, {3, 30}});
}
SUBCASE("on_move/replace") {
std::set<exception_on_move_value, std::less<>> s{{1, 10}, {3, 30}};
CHECK_THROWS(insert_or_assign(s, exception_on_move_value{3, 42}));
CHECK(s == std::set<exception_on_move_value, std::less<>>{{1, 10}, {3, 30}});
}
SUBCASE("on_copy/insert") {
std::set<exception_on_copy_value, std::less<>> s{{1, 10}, {3, 30}};
exception_on_copy_value v{2, 42};
CHECK_THROWS(insert_or_assign(s, v));
CHECK(s == std::set<exception_on_copy_value, std::less<>>{{1, 10}, {3, 30}});
}
SUBCASE("on_copy/replace") {
std::set<exception_on_copy_value, std::less<>> s{{1, 10}, {3, 30}};
exception_on_copy_value v{3, 42};
CHECK_THROWS(insert_or_assign(s, v));
CHECK(s == std::set<exception_on_copy_value, std::less<>>{{1, 10}, {3, 30}});
}
}

View File

@@ -90,7 +90,7 @@ namespace meta_hpp::detail
: std::logic_error(ec.message())
, error_code_{ec} {}
[[nodiscard]] const std::error_code& code() const noexcept {
[[nodiscard]] const std::error_code& get_code() const noexcept {
return error_code_;
}

View File

@@ -7,10 +7,12 @@
#pragma once
#include "base.hpp"
#include "exceptions.hpp"
namespace meta_hpp::detail
{
template < typename Key, typename Compare, typename Allocator >
requires std::is_move_constructible_v<Key> && std::is_move_assignable_v<Key>
typename std::set<Key, Compare, Allocator>::iterator insert_or_assign( //
std::set<Key, Compare, Allocator>& set,
typename std::set<Key, Compare, Allocator>::value_type&& value
@@ -22,11 +24,20 @@ namespace meta_hpp::detail
}
auto node = set.extract(position++);
node.value() = std::move(value);
META_HPP_TRY {
node.value() = std::move(value);
}
META_HPP_CATCH(...) {
set.insert(position, std::move(node));
META_HPP_RETHROW();
}
return set.insert(position, std::move(node));
}
template < typename Key, typename Compare, typename Allocator >
requires std::is_copy_constructible_v<Key> && std::is_copy_assignable_v<Key>
typename std::set<Key, Compare, Allocator>::iterator insert_or_assign( //
std::set<Key, Compare, Allocator>& set,
const typename std::set<Key, Compare, Allocator>::value_type& value
@@ -38,7 +49,15 @@ namespace meta_hpp::detail
}
auto node = set.extract(position++);
node.value() = value;
META_HPP_TRY {
node.value() = value;
}
META_HPP_CATCH(...) {
set.insert(position, std::move(node));
META_HPP_RETHROW();
}
return set.insert(position, std::move(node));
}
}

View File

@@ -29,7 +29,7 @@ namespace meta_hpp
class uvalue final {
public:
uvalue() = default;
~uvalue();
~uvalue() noexcept;
uvalue(uvalue&& other) noexcept;
uvalue(const uvalue& other);
@@ -73,7 +73,7 @@ namespace meta_hpp
[[nodiscard]] bool is_valid() const noexcept;
[[nodiscard]] explicit operator bool() const noexcept;
void reset();
void reset() noexcept;
void swap(uvalue& other) noexcept;
[[nodiscard]] any_type get_type() const noexcept;

View File

@@ -254,7 +254,7 @@ namespace meta_hpp
namespace meta_hpp
{
inline uvalue::~uvalue() {
inline uvalue::~uvalue() noexcept {
reset();
}
@@ -339,7 +339,7 @@ namespace meta_hpp
return is_valid();
}
inline void uvalue::reset() {
inline void uvalue::reset() noexcept {
vtable_t::do_reset(*this);
}