variant: split into variant and optional_variant
Upstreaming https://github.com/UkoeHB/monero/pull/28
This commit is contained in:
parent
059028a30a
commit
49ca1ad6ae
|
@ -74,15 +74,14 @@ struct variant_static_visitor : public boost::static_visitor<ResultT>
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename... Types>
|
template <typename... Types>
|
||||||
class variant final
|
class variant
|
||||||
{
|
{
|
||||||
using VType = boost::variant<boost::blank, Types...>;
|
using VType = boost::variant<Types...>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
//constructors
|
//constructors
|
||||||
/// default constructor
|
/// default constructor
|
||||||
variant() = default;
|
variant() = default;
|
||||||
variant(boost::none_t) : variant{} {} //act like boost::optional
|
|
||||||
|
|
||||||
/// construct from variant type (use enable_if to avoid issues with copy/move constructor)
|
/// construct from variant type (use enable_if to avoid issues with copy/move constructor)
|
||||||
template <typename T,
|
template <typename T,
|
||||||
|
@ -95,14 +94,7 @@ public:
|
||||||
>::type = true>
|
>::type = true>
|
||||||
variant(T &&value) : m_value{std::forward<T>(value)} {}
|
variant(T &&value) : m_value{std::forward<T>(value)} {}
|
||||||
|
|
||||||
//overloaded operators
|
|
||||||
/// boolean operator: true if the variant isn't empty/uninitialized
|
|
||||||
explicit operator bool() const noexcept { return !this->is_empty(); }
|
|
||||||
|
|
||||||
//member functions
|
//member functions
|
||||||
/// check if empty/uninitialized
|
|
||||||
bool is_empty() const noexcept { return m_value.which() == 0; }
|
|
||||||
|
|
||||||
/// check the variant type
|
/// check the variant type
|
||||||
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>(); }
|
||||||
|
@ -136,7 +128,7 @@ public:
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static constexpr int type_index_of() noexcept
|
static constexpr int type_index_of() noexcept
|
||||||
{
|
{
|
||||||
using types = boost::mpl::vector<boost::blank, Types...>;
|
using types = typename VType::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;
|
||||||
|
@ -164,4 +156,35 @@ private:
|
||||||
VType m_value;
|
VType m_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename... Types>
|
||||||
|
class optional_variant: public variant<boost::blank, Types...>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//constructors
|
||||||
|
/// default constructor
|
||||||
|
optional_variant() = default;
|
||||||
|
|
||||||
|
/// construct from variant type (use enable_if to avoid issues with copy/move constructor)
|
||||||
|
template <typename T,
|
||||||
|
typename std::enable_if<
|
||||||
|
!std::is_same<
|
||||||
|
std::remove_cv_t<std::remove_reference_t<T>>,
|
||||||
|
optional_variant<Types...>
|
||||||
|
>::value,
|
||||||
|
bool
|
||||||
|
>::type = true>
|
||||||
|
optional_variant(T &&value) : variant<boost::blank, Types...>(std::forward<T>(value)) {}
|
||||||
|
|
||||||
|
// construct like boost::optional
|
||||||
|
optional_variant(boost::none_t) {}
|
||||||
|
|
||||||
|
//overloaded operators
|
||||||
|
/// boolean operator: true if the variant isn't empty/uninitialized
|
||||||
|
explicit operator bool() const noexcept { return !this->is_empty(); }
|
||||||
|
|
||||||
|
//member functions
|
||||||
|
/// check if empty/uninitialized
|
||||||
|
bool is_empty() const noexcept { return this->index() == 0; }
|
||||||
|
};
|
||||||
|
|
||||||
} //namespace tools
|
} //namespace tools
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
using tools::optional_variant;
|
||||||
using tools::variant;
|
using tools::variant;
|
||||||
using tools::variant_static_visitor;
|
using tools::variant_static_visitor;
|
||||||
|
|
||||||
|
@ -239,7 +240,7 @@ struct test_stringify_visitor: public variant_static_visitor<std::string>
|
||||||
//-------------------------------------------------------------------------------------------------------------------
|
//-------------------------------------------------------------------------------------------------------------------
|
||||||
TEST(variant, operatorbool)
|
TEST(variant, operatorbool)
|
||||||
{
|
{
|
||||||
variant<int8_t, uint8_t, int16_t, uint16_t, std::string> v;
|
optional_variant<int8_t, uint8_t, int16_t, uint16_t, std::string> v;
|
||||||
EXPECT_FALSE(v);
|
EXPECT_FALSE(v);
|
||||||
v = (int16_t) 2023;
|
v = (int16_t) 2023;
|
||||||
EXPECT_TRUE(v);
|
EXPECT_TRUE(v);
|
||||||
|
@ -251,7 +252,7 @@ TEST(variant, operatorbool)
|
||||||
//-------------------------------------------------------------------------------------------------------------------
|
//-------------------------------------------------------------------------------------------------------------------
|
||||||
TEST(variant, is_empty)
|
TEST(variant, is_empty)
|
||||||
{
|
{
|
||||||
variant<int8_t, uint8_t, int16_t, uint16_t, std::string> v;
|
optional_variant<int8_t, uint8_t, int16_t, uint16_t, std::string> v;
|
||||||
EXPECT_TRUE(v.is_empty());
|
EXPECT_TRUE(v.is_empty());
|
||||||
v = (int16_t) 2023;
|
v = (int16_t) 2023;
|
||||||
EXPECT_FALSE(v.is_empty());
|
EXPECT_FALSE(v.is_empty());
|
||||||
|
@ -260,7 +261,7 @@ TEST(variant, is_empty)
|
||||||
v = boost::blank{};
|
v = boost::blank{};
|
||||||
EXPECT_TRUE(v.is_empty());
|
EXPECT_TRUE(v.is_empty());
|
||||||
|
|
||||||
variant<> v2;
|
optional_variant<> v2;
|
||||||
EXPECT_TRUE(v2.is_empty());
|
EXPECT_TRUE(v2.is_empty());
|
||||||
v2 = boost::blank{};
|
v2 = boost::blank{};
|
||||||
EXPECT_TRUE(v2.is_empty());
|
EXPECT_TRUE(v2.is_empty());
|
||||||
|
@ -269,7 +270,7 @@ TEST(variant, is_empty)
|
||||||
TEST(variant, is_type)
|
TEST(variant, is_type)
|
||||||
{
|
{
|
||||||
variant<int8_t, uint8_t, int16_t, uint16_t, std::string> v;
|
variant<int8_t, uint8_t, int16_t, uint16_t, std::string> v;
|
||||||
EXPECT_TRUE(v.is_type<boost::blank>());
|
EXPECT_TRUE(v.is_type<int8_t>());
|
||||||
v = (int16_t) 2023;
|
v = (int16_t) 2023;
|
||||||
EXPECT_TRUE(v.is_type<int16_t>());
|
EXPECT_TRUE(v.is_type<int16_t>());
|
||||||
|
|
||||||
|
@ -279,7 +280,7 @@ TEST(variant, is_type)
|
||||||
TEST(variant, try_unwrap)
|
TEST(variant, try_unwrap)
|
||||||
{
|
{
|
||||||
variant<int8_t, uint8_t, int16_t, uint16_t, std::string> v;
|
variant<int8_t, uint8_t, int16_t, uint16_t, std::string> v;
|
||||||
EXPECT_FALSE(v.try_unwrap<int8_t>());
|
EXPECT_TRUE(v.try_unwrap<int8_t>());
|
||||||
v = (int16_t) 5252;
|
v = (int16_t) 5252;
|
||||||
ASSERT_TRUE(v.try_unwrap<int16_t>());
|
ASSERT_TRUE(v.try_unwrap<int16_t>());
|
||||||
EXPECT_EQ(5252, *v.try_unwrap<int16_t>());
|
EXPECT_EQ(5252, *v.try_unwrap<int16_t>());
|
||||||
|
@ -290,7 +291,7 @@ TEST(variant, try_unwrap)
|
||||||
TEST(variant, unwrap)
|
TEST(variant, unwrap)
|
||||||
{
|
{
|
||||||
variant<int8_t, uint8_t, int16_t, uint16_t, std::string> v;
|
variant<int8_t, uint8_t, int16_t, uint16_t, std::string> v;
|
||||||
EXPECT_THROW(v.unwrap<int8_t>(), std::runtime_error);
|
EXPECT_EQ(0, v.unwrap<int8_t>());
|
||||||
v = (int16_t) 5252;
|
v = (int16_t) 5252;
|
||||||
EXPECT_EQ(5252, v.unwrap<int16_t>());
|
EXPECT_EQ(5252, v.unwrap<int16_t>());
|
||||||
EXPECT_THROW(v.unwrap<uint16_t>(), std::runtime_error);
|
EXPECT_THROW(v.unwrap<uint16_t>(), std::runtime_error);
|
||||||
|
@ -321,35 +322,55 @@ 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;
|
||||||
EXPECT_EQ(0, v.index());
|
EXPECT_EQ(0, v.index());
|
||||||
v = (int8_t) 7;
|
v = (int8_t) 7;
|
||||||
EXPECT_EQ(1, v.index());
|
EXPECT_EQ(0, v.index());
|
||||||
v = (uint8_t) 7;
|
v = (uint8_t) 7;
|
||||||
EXPECT_EQ(2, v.index());
|
EXPECT_EQ(1, v.index());
|
||||||
v = (int16_t) 7;
|
v = (int16_t) 7;
|
||||||
EXPECT_EQ(3, v.index());
|
EXPECT_EQ(2, v.index());
|
||||||
v = (uint16_t) 7;
|
v = (uint16_t) 7;
|
||||||
EXPECT_EQ(4, v.index());
|
EXPECT_EQ(3, v.index());
|
||||||
v = "verifiable variant vying for vengence versus visa";
|
v = "verifiable variant vying for vengence versus visa";
|
||||||
EXPECT_EQ(5, v.index());
|
EXPECT_EQ(4, v.index());
|
||||||
|
|
||||||
|
optional_variant<int8_t, uint8_t, int16_t, uint16_t, std::string> vo;
|
||||||
|
EXPECT_EQ(0, vo.index());
|
||||||
|
vo = (int8_t) 7;
|
||||||
|
EXPECT_EQ(1, vo.index());
|
||||||
|
vo = (uint8_t) 7;
|
||||||
|
EXPECT_EQ(2, vo.index());
|
||||||
|
vo = (int16_t) 7;
|
||||||
|
EXPECT_EQ(3, vo.index());
|
||||||
|
vo = (uint16_t) 7;
|
||||||
|
EXPECT_EQ(4, vo.index());
|
||||||
|
vo = "verifiable variant vying for vengence versus visa";
|
||||||
|
EXPECT_EQ(5, vo.index());
|
||||||
}
|
}
|
||||||
//-------------------------------------------------------------------------------------------------------------------
|
//-------------------------------------------------------------------------------------------------------------------
|
||||||
TEST(variant, type_index_of)
|
TEST(variant, type_index_of)
|
||||||
{
|
{
|
||||||
variant<int8_t, uint8_t, int16_t, uint16_t, std::string> v;
|
variant<int8_t, uint8_t, int16_t, uint16_t, std::string> v;
|
||||||
EXPECT_EQ(0, decltype(v)::type_index_of<boost::blank>());
|
EXPECT_EQ(0, decltype(v)::type_index_of<int8_t>());
|
||||||
EXPECT_EQ(1, decltype(v)::type_index_of<int8_t>());
|
EXPECT_EQ(1, decltype(v)::type_index_of<uint8_t>());
|
||||||
EXPECT_EQ(2, decltype(v)::type_index_of<uint8_t>());
|
EXPECT_EQ(2, decltype(v)::type_index_of<int16_t>());
|
||||||
EXPECT_EQ(3, decltype(v)::type_index_of<int16_t>());
|
EXPECT_EQ(3, decltype(v)::type_index_of<uint16_t>());
|
||||||
EXPECT_EQ(4, decltype(v)::type_index_of<uint16_t>());
|
EXPECT_EQ(4, decltype(v)::type_index_of<std::string>());
|
||||||
EXPECT_EQ(5, decltype(v)::type_index_of<std::string>());
|
|
||||||
|
optional_variant<int8_t, uint8_t, int16_t, uint16_t, std::string> vo;
|
||||||
|
EXPECT_EQ(0, decltype(vo)::type_index_of<boost::blank>());
|
||||||
|
EXPECT_EQ(1, decltype(vo)::type_index_of<int8_t>());
|
||||||
|
EXPECT_EQ(2, decltype(vo)::type_index_of<uint8_t>());
|
||||||
|
EXPECT_EQ(3, decltype(vo)::type_index_of<int16_t>());
|
||||||
|
EXPECT_EQ(4, decltype(vo)::type_index_of<uint16_t>());
|
||||||
|
EXPECT_EQ(5, decltype(vo)::type_index_of<std::string>());
|
||||||
}
|
}
|
||||||
//-------------------------------------------------------------------------------------------------------------------
|
//-------------------------------------------------------------------------------------------------------------------
|
||||||
TEST(variant, constexpr_type_index_of)
|
TEST(variant, constexpr_type_index_of)
|
||||||
{
|
{
|
||||||
variant<int8_t, uint8_t, int16_t, uint16_t, std::string> v;
|
variant<int8_t, uint8_t, int16_t, uint16_t, std::string> v;
|
||||||
constexpr int TINDEX0 = decltype(v)::type_index_of<boost::blank>();
|
constexpr int TINDEX2 = decltype(v)::type_index_of<int16_t>();
|
||||||
EXPECT_EQ(0, TINDEX0);
|
EXPECT_EQ(2, TINDEX2);
|
||||||
constexpr int TINDEX5 = decltype(v)::type_index_of<std::string>();
|
constexpr int TINDEX4 = decltype(v)::type_index_of<std::string>();
|
||||||
EXPECT_EQ(5, TINDEX5);
|
EXPECT_EQ(4, TINDEX4);
|
||||||
}
|
}
|
||||||
//-------------------------------------------------------------------------------------------------------------------
|
//-------------------------------------------------------------------------------------------------------------------
|
||||||
TEST(variant, same_type)
|
TEST(variant, same_type)
|
||||||
|
@ -362,7 +383,6 @@ TEST(variant, same_type)
|
||||||
TEST(variant, visit)
|
TEST(variant, visit)
|
||||||
{
|
{
|
||||||
variant<int8_t, uint8_t, int16_t, uint16_t, std::string> v;
|
variant<int8_t, uint8_t, int16_t, uint16_t, std::string> v;
|
||||||
EXPECT_THROW(v.visit(test_stringify_visitor()), std::runtime_error);
|
|
||||||
|
|
||||||
v = "Rev";
|
v = "Rev";
|
||||||
test_stringify_visitor::test_visitation(v, std::string("Rev"));
|
test_stringify_visitor::test_visitation(v, std::string("Rev"));
|
||||||
|
@ -377,7 +397,7 @@ TEST(variant, ad_hoc_recursion)
|
||||||
struct left_t;
|
struct left_t;
|
||||||
struct right_t;
|
struct right_t;
|
||||||
|
|
||||||
using twisty = variant<boost::recursive_wrapper<left_t>, boost::recursive_wrapper<right_t>>;
|
using twisty = optional_variant<boost::recursive_wrapper<left_t>, boost::recursive_wrapper<right_t>>;
|
||||||
|
|
||||||
struct left_t
|
struct left_t
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue