variant: add mutable unwrap and visitation
This commit is contained in:
parent
bc3cec4634
commit
2a7435e026
|
@ -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
|
||||||
{
|
{
|
||||||
|
@ -131,7 +137,7 @@ public:
|
||||||
static constexpr int type_index_of() noexcept
|
static constexpr int type_index_of() noexcept
|
||||||
{
|
{
|
||||||
using types = boost::mpl::vector<boost::blank, Types...>;
|
using types = boost::mpl::vector<boost::blank, Types...>;
|
||||||
using elem = typename boost::mpl::find<types, T>::type;
|
using elem = typename boost::mpl::find<types, T>::type;
|
||||||
using begin = typename boost::mpl::begin<types>::type;
|
using begin = typename boost::mpl::begin<types>::type;
|
||||||
return boost::mpl::distance<begin, elem>::value;
|
return boost::mpl::distance<begin, elem>::value;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue