variant: add mutable unwrap and visitation

This commit is contained in:
koe 2023-02-12 13:00:53 -06:00
parent bc3cec4634
commit 2a7435e026
2 changed files with 41 additions and 9 deletions

View file

@ -62,7 +62,6 @@ namespace tools
//// ////
// variant: convenience wrapper around boost::variant with a cleaner interface // variant: convenience wrapper around boost::variant with a cleaner interface
// - the value may be assigned to but is otherwise read-only
// - the variant is 'optional' - an empty variant will evaluate to 'false' and an initialized variant will be 'true' // - the variant is 'optional' - an empty variant will evaluate to 'false' and an initialized variant will be 'true'
/// ///
template <typename ResultT> template <typename ResultT>
@ -70,6 +69,7 @@ struct variant_static_visitor : public boost::static_visitor<ResultT>
{ {
/// provide visitation for empty variants /// provide visitation for empty variants
/// - add this to your visitor with: using variant_static_visitor::operator(); /// - add this to your visitor with: using variant_static_visitor::operator();
[[noreturn]] ResultT operator()(const boost::blank) { variant_static_visitor_blank_err(); }
[[noreturn]] ResultT operator()(const boost::blank) const { variant_static_visitor_blank_err(); } [[noreturn]] ResultT operator()(const boost::blank) const { variant_static_visitor_blank_err(); }
}; };
@ -107,14 +107,20 @@ public:
template <typename T> template <typename T>
bool is_type() const noexcept { return this->index() == this->type_index_of<T>(); } bool is_type() const noexcept { return this->index() == this->type_index_of<T>(); }
/// try to get a read-only handle to the embedded value (return nullptr on failure) /// try to get a handle to the embedded value (return nullptr on failure)
template <typename T> template <typename T>
const T* try_unwrap() const T* try_unwrap() noexcept { return boost::strict_get< T>(&m_value); }
{ template <typename T>
return boost::strict_get<T>(&m_value); const T* try_unwrap() const noexcept { return boost::strict_get<const T>(&m_value); }
}
/// get a read-only handle to the embedded value /// get a handle to the embedded value
template <typename T>
T& unwrap()
{
T *value_ptr{this->try_unwrap<T>()};
if (!value_ptr) variant_unwrap_err();
return *value_ptr;
}
template <typename T> template <typename T>
const T& unwrap() const const T& unwrap() const
{ {
@ -142,6 +148,11 @@ public:
/// apply a visitor to the variant /// apply a visitor to the variant
template <typename VisitorT> template <typename VisitorT>
typename VisitorT::result_type visit(VisitorT &&visitor)
{
return boost::apply_visitor(std::forward<VisitorT>(visitor), m_value);
}
template <typename VisitorT>
typename VisitorT::result_type visit(VisitorT &&visitor) const typename VisitorT::result_type visit(VisitorT &&visitor) const
{ {
return boost::apply_visitor(std::forward<VisitorT>(visitor), m_value); return boost::apply_visitor(std::forward<VisitorT>(visitor), m_value);

View file

@ -232,8 +232,10 @@ struct test_stringify_visitor: public variant_static_visitor<std::string>
return test_stringify_visitor::stringify(t); return test_stringify_visitor::stringify(t);
} }
}; };
} // anonymous namespace
//------------------------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------
} // anonymous namespace
//------------------------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------------------------
TEST(variant, operatorbool) TEST(variant, operatorbool)
{ {
@ -295,6 +297,25 @@ TEST(variant, unwrap)
EXPECT_THROW(v.unwrap<std::string>(), std::runtime_error); EXPECT_THROW(v.unwrap<std::string>(), std::runtime_error);
} }
//------------------------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------------------------
TEST(variant, mutation)
{
variant<uint8_t> v;
v = (uint8_t) 5;
EXPECT_EQ(5, v.unwrap<uint8_t>());
uint8_t &intref{v.unwrap<uint8_t>()};
intref = 10;
EXPECT_EQ(10, v.unwrap<uint8_t>());
EXPECT_TRUE(v.try_unwrap<uint8_t>());
uint8_t *intptr{v.try_unwrap<uint8_t>()};
*intptr = 15;
EXPECT_EQ(15, v.unwrap<uint8_t>());
const variant<uint8_t> &v_ref{v};
EXPECT_EQ(15, v_ref.unwrap<uint8_t>());
EXPECT_TRUE(v_ref.try_unwrap<uint8_t>());
EXPECT_EQ(15, *(v_ref.try_unwrap<uint8_t>()));
}
//-------------------------------------------------------------------------------------------------------------------
TEST(variant, index) TEST(variant, index)
{ {
variant<int8_t, uint8_t, int16_t, uint16_t, std::string> v; variant<int8_t, uint8_t, int16_t, uint16_t, std::string> v;