Bump mapbox/variant to version 1.2.0 (#6898)

This commit is contained in:
Siarhei Fedartsou
2024-05-24 20:39:45 +02:00
committed by GitHub
parent babdced52f
commit 8b48e2ccc6
26 changed files with 10327 additions and 9617 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
// @EXPECTED: enable_if
// @EXPECTED: no matching .*\<function for call to .*\<get\>
#include <mapbox/variant.hpp>
@@ -1,4 +1,4 @@
// @EXPECTED: const int
// @EXPECTED: no matching function for call to .*\<apply_visitor\>
#include <mapbox/variant.hpp>
+8876 -9067
View File
File diff suppressed because it is too large Load Diff
+155
View File
@@ -10,6 +10,15 @@
using namespace mapbox::util;
template <typename T>
struct tag
{
static void dump(const char* prefix)
{
std::cout << prefix << ": " << typeid(tag<T>).name() << std::endl;
}
};
template <typename Left, typename Right>
using Either = mapbox::util::variant<Left, Right>;
@@ -55,6 +64,37 @@ void test_singleton_variant()
apply_visitor(make_visitor([](int) {}), singleton);
}
// See #180
struct test_call_nonconst_member_visitor
{
template <typename T>
void operator() (T & obj) const
{
tag<decltype(obj)>::dump("test_call_nonconst_member: visitor");
obj.foo();
}
};
void test_call_nonconst_member()
{
struct object
{
void foo() { val = 42;}
int val = 0;
};
variant<object> v = object{};
apply_visitor(test_call_nonconst_member_visitor{}, v);
#ifdef HAS_CPP14_SUPPORT
apply_visitor([](auto& obj)
{
tag<decltype(obj)>::dump("test_call_nonconst_member: lambda");
obj.foo();
}, v);
#endif
}
void test_lambda_overloads_sfinae()
#ifdef HAS_CPP14_SUPPORT
{
@@ -85,6 +125,9 @@ void test_match_singleton()
{
variant<int> singleton = 5;
singleton.match([](int) {});
auto lambda = [](int) {};
singleton.match(lambda);
}
void test_match_overloads()
@@ -112,16 +155,128 @@ void test_match_overloads_capture()
std::cout << "Got " << ok << " ok, " << err << " err" << std::endl;
}
struct MovableOnly
{
MovableOnly() = default;
MovableOnly(MovableOnly&&) = default;
MovableOnly& operator=(MovableOnly&&) = default;
};
struct MovableCopyable
{
MovableCopyable() = default;
MovableCopyable(MovableCopyable&&) = default;
MovableCopyable& operator=(MovableCopyable&&) = default;
MovableCopyable(const MovableCopyable&) = default;
MovableCopyable& operator=(const MovableCopyable&) = default;
};
void test_match_overloads_init_capture()
#ifdef HAS_CPP14_SUPPORT
{
Either<Error, Response> rv;
rv = Error{};
rv.match([p = MovableOnly{}](auto&&) {});
{
auto lambda = [p = MovableCopyable{}](auto&&) {};
rv.match(lambda);
rv.match([p = MovableOnly{}](Response) { std::cout << "Response\n"; },
[p = MovableOnly{}](Error) { std::cout << "Error\n"; });
}
{
auto lambda = [](Error) { std::cout << "Error\n"; };
rv.match([p = MovableOnly{}](Response) { std::cout << "Response\n"; },
lambda);
rv.match(lambda,
[p = MovableOnly{}](Response) { std::cout << "Response\n"; });
}
}
#else
{
}
#endif
// See #140
void test_match_overloads_otherwise()
#ifdef HAS_CPP14_SUPPORT
{
struct Center
{
};
struct Indent
{
};
struct Justify
{
};
struct None
{
};
using Properties = mapbox::util::variant<Center, Indent, Justify, None>;
Properties props = Justify{};
props.match([&](Center) { std::cout << "Center\n"; }, //
[&](Indent) { std::cout << "Indent\n"; }, //
[&](auto&&) { std::cout << "Otherwise\n"; }); //
}
#else
{
}
#endif
template <typename>
struct Moveable
{
Moveable() = default; // Default constructible
Moveable(const Moveable&) = delete; // Disable copy ctor
Moveable& operator=(const Moveable&) = delete; // Disable copy assign op
Moveable(Moveable&&) = default; // Enable move ctor
Moveable& operator=(Moveable&&) = default; // Enable move assign op
};
void test_match_move_out_of_variant()
{
// Distinguishable at type level
using T1 = Moveable<struct Tag1>;
using T2 = Moveable<struct Tag2>;
using T3 = mapbox::util::recursive_wrapper<int>;
mapbox::util::variant<T1, T2> v = T1{};
std::move(v).match([](T1&&) {}, // Consume T1 by value
[](T2&&) {}); // Consume T2 by value
mapbox::util::variant<T3, T2> w = T2{};
std::move(w).match([](int&&) {}, // Consume unwrapped int
[](T2&&) {}); // Consume T2 by value
}
int main()
{
test_lambda_overloads();
test_singleton_variant();
test_call_nonconst_member();
test_lambda_overloads_capture();
test_lambda_overloads_sfinae();
test_match_singleton();
test_match_overloads();
test_match_overloads_capture();
test_match_overloads_init_capture();
test_match_overloads_otherwise();
test_match_move_out_of_variant();
}
#undef HAS_CPP14_SUPPORT
+4 -5
View File
@@ -1,4 +1,3 @@
#include <cstdlib>
#include <iostream>
#include <string>
@@ -64,12 +63,12 @@ struct calculator
int operator()(binary_op<add> const& binary) const
{
return util::apply_visitor(calculator(), binary.left) + util::apply_visitor(calculator(), binary.right);
return util::apply_visitor(*this, binary.left) + util::apply_visitor(*this, binary.right);
}
int operator()(binary_op<sub> const& binary) const
{
return util::apply_visitor(calculator(), binary.left) - util::apply_visitor(calculator(), binary.right);
return util::apply_visitor(*this, binary.left) - util::apply_visitor(*this, binary.right);
}
};
@@ -83,12 +82,12 @@ struct to_string
std::string operator()(binary_op<add> const& binary) const
{
return util::apply_visitor(to_string(), binary.left) + std::string("+") + util::apply_visitor(to_string(), binary.right);
return util::apply_visitor(*this, binary.left) + std::string("+") + util::apply_visitor(*this, binary.right);
}
std::string operator()(binary_op<sub> const& binary) const
{
return util::apply_visitor(to_string(), binary.left) + std::string("-") + util::apply_visitor(to_string(), binary.right);
return util::apply_visitor(*this, binary.left) + std::string("-") + util::apply_visitor(*this, binary.right);
}
};
+2 -2
View File
@@ -160,8 +160,8 @@ struct swap_visitor
{
using T = typename std::common_type<A, B>::type;
T tmp = a;
a = b;
b = tmp;
a = static_cast<A>(b);
b = static_cast<B>(tmp);
}
};
+1 -3
View File
@@ -46,9 +46,7 @@ TEST_CASE("set() works cleanly even if the constructor throws ", "[variant]")
variant_type v = obj;
REQUIRE(v.is<t1>());
REQUIRE(v.get<t1>().value == 42);
REQUIRE_THROWS({
v.set<t2>(13);
});
REQUIRE_THROWS(v.set<t2>(13));
}
REQUIRE(count == 0);
}
+66
View File
@@ -0,0 +1,66 @@
#include <typeinfo>
#include <utility>
#include <mapbox/variant.hpp>
using namespace mapbox;
namespace test {
struct t_noexcept_true_1 {
t_noexcept_true_1(t_noexcept_true_1&&) noexcept = default;
t_noexcept_true_1& operator=(t_noexcept_true_1&&) noexcept = default;
};
struct t_noexcept_true_2 {
t_noexcept_true_2(t_noexcept_true_2&&) noexcept = default;
t_noexcept_true_2& operator=(t_noexcept_true_2&&) noexcept = default;
};
struct t_noexcept_false_1 {
t_noexcept_false_1(t_noexcept_false_1&&) noexcept(false) {}
t_noexcept_false_1& operator=(t_noexcept_false_1&&) noexcept(false) { return *this; }
};
using should_be_no_throw_copyable = util::variant<t_noexcept_true_1, t_noexcept_true_2>;
static_assert(std::is_nothrow_move_assignable<should_be_no_throw_copyable>::value,
"variants with no-throw move assignable types should be "
"no-throw move nothrow assignable");
using should_be_no_throw_assignable = util::variant<t_noexcept_true_1, t_noexcept_true_2>;
static_assert(std::is_nothrow_move_constructible<should_be_no_throw_assignable>::value,
"variants with no-throw move assignable types should be "
"no-throw move nothrow assignable");
using should_not_be_no_throw_copyable = util::variant<t_noexcept_true_1, t_noexcept_false_1>;
static_assert(not std::is_nothrow_move_assignable<should_not_be_no_throw_copyable>::value,
"variants with no-throw move assignable types should be "
"no-throw move nothrow assignable");
using should_not_be_no_throw_assignable = util::variant<t_noexcept_true_1, t_noexcept_false_1>;
static_assert(not std::is_nothrow_move_constructible<should_not_be_no_throw_assignable>::value,
"variants with no-throw move assignable types should be "
"no-throw move nothrow assignable");
// this type cannot be nothrow converted from either of its types, even the nothrow moveable one,
// because the conversion operator moves the whole variant.
using convertable_test_type = util::variant<t_noexcept_true_1, t_noexcept_false_1>;
// this type can be nothrow converted from either of its types.
using convertable_test_type_2 = util::variant<t_noexcept_true_1, t_noexcept_true_2>;
static_assert(not std::is_nothrow_assignable<convertable_test_type, t_noexcept_true_1>::value,
"variants with noexcept(true) move constructible types should be nothrow-convertible "
"from those types only IF the variant itself is nothrow_move_assignable");
static_assert(not std::is_nothrow_assignable<convertable_test_type, t_noexcept_false_1>::value,
"variants with noexcept(false) move constructible types should not be nothrow-convertible "
"from those types");
static_assert(std::is_nothrow_assignable<convertable_test_type_2, t_noexcept_true_2>::value,
"variants with noexcept(true) move constructible types should be nothrow-convertible "
"from those types only IF the variant itself is nothrow_move_assignable");
} // namespace test
+2 -1
View File
@@ -1,4 +1,3 @@
#include "catch.hpp"
#include <mapbox/optional.hpp>
@@ -97,6 +96,8 @@ TEST_CASE("self assignment", "[optional]")
a = 1;
REQUIRE(a.get() == 1);
#if !defined(__clang__)
a = a;
REQUIRE(a.get() == 1);
#endif
}
+29 -2
View File
@@ -1,6 +1,6 @@
#include "catch.hpp"
#include <mapbox/variant.hpp>
#include <mapbox/recursive_wrapper.hpp>
#include <type_traits>
@@ -153,6 +153,33 @@ TEST_CASE("recursive wrapper of pair<int, int>")
b = std::move(c);
REQUIRE(b.get().first == 5);
REQUIRE(b.get().second == 6);
// REQUIRE(c.get_pointer() == nullptr);
//REQUIRE(c.get_pointer() == nullptr);
}
SECTION("Multiple recurssive wrappers of polymorphic types")
{
// https://github.com/mapbox/variant/issues/146
// (Visual Studio 2015 update 3)
using namespace mapbox::util;
struct Base;
struct Derived;
using Variant = variant<recursive_wrapper<Base>, recursive_wrapper<Derived>>;
struct Base { };
struct Derived : public Base { };
{
Base base;
Derived derived;
Variant v;
v = base;
v = derived; // compile error prior https://github.com/mapbox/variant/pull/147
CHECK(v.is<Derived>());
}
{
Derived derived;
Variant v(derived); // compile error prior https://github.com/mapbox/variant/pull/147
CHECK(v.is<Derived>());
}
}
}
+1 -2
View File
@@ -1,4 +1,3 @@
#include <algorithm>
#include <cstddef>
#include <cstdint>
@@ -15,7 +14,7 @@ struct some_struct
std::string c;
};
using variant_internal_index_type = size_t;
using variant_internal_index_type = mapbox::util::type_index_t;
TEST_CASE("size of variants")
{
+21 -63
View File
@@ -208,9 +208,7 @@ TEST_CASE("get with wrong type (here: double) should throw", "[variant]")
REQUIRE(var.is<int>());
REQUIRE_FALSE(var.is<double>());
REQUIRE(var.get<int>() == 5);
REQUIRE_THROWS_AS({
var.get<double>();
},
REQUIRE_THROWS_AS(var.get<double>(),
mapbox::util::bad_variant_access&);
}
@@ -222,13 +220,9 @@ TEST_CASE("get with wrong type (here: int) should throw", "[variant]")
REQUIRE_FALSE(var.is<int>());
REQUIRE(var.get<double>() == 5.0);
REQUIRE(mapbox::util::get<double>(var) == 5.0);
REQUIRE_THROWS_AS({
var.get<int>();
},
REQUIRE_THROWS_AS(var.get<int>(),
mapbox::util::bad_variant_access&);
REQUIRE_THROWS_AS({
mapbox::util::get<int>(var);
},
REQUIRE_THROWS_AS(mapbox::util::get<int>(var),
mapbox::util::bad_variant_access&);
}
@@ -240,26 +234,18 @@ TEST_CASE("get on const varint with wrong type (here: int) should throw", "[vari
REQUIRE_FALSE(var.is<int>());
REQUIRE(var.get<double>() == 5.0);
REQUIRE(mapbox::util::get<double>(var) == 5.0);
REQUIRE_THROWS_AS({
var.get<int>();
},
REQUIRE_THROWS_AS(var.get<int>(),
mapbox::util::bad_variant_access&);
REQUIRE_THROWS_AS({
mapbox::util::get<int>(var);
},
REQUIRE_THROWS_AS(mapbox::util::get<int>(var),
mapbox::util::bad_variant_access&);
}
TEST_CASE("get with any type should throw if not initialized", "[variant]")
{
mapbox::util::variant<int, double> var{mapbox::util::no_init()};
REQUIRE_THROWS_AS({
var.get<int>();
},
REQUIRE_THROWS_AS(var.get<int>(),
mapbox::util::bad_variant_access&);
REQUIRE_THROWS_AS({
var.get<double>();
},
REQUIRE_THROWS_AS(var.get<double>(),
mapbox::util::bad_variant_access&);
}
@@ -273,16 +259,12 @@ TEST_CASE("no_init variant can be copied and moved from", "[variant]")
REQUIRE(v2.get<int>() == 42);
v2 = v1;
REQUIRE_THROWS_AS({
v2.get<int>();
},
REQUIRE_THROWS_AS(v2.get<int>(),
mapbox::util::bad_variant_access&);
REQUIRE(v3.get<int>() == 23);
v3 = std::move(v1);
REQUIRE_THROWS_AS({
v3.get<int>();
},
REQUIRE_THROWS_AS(v3.get<int>(),
mapbox::util::bad_variant_access&);
}
@@ -294,9 +276,7 @@ TEST_CASE("no_init variant can be copied and moved to", "[variant]")
variant_type v2{mapbox::util::no_init()};
variant_type v3{mapbox::util::no_init()};
REQUIRE_THROWS_AS({
v2.get<int>();
},
REQUIRE_THROWS_AS(v2.get<int>(),
mapbox::util::bad_variant_access&);
REQUIRE(v1.get<int>() == 42);
@@ -304,9 +284,7 @@ TEST_CASE("no_init variant can be copied and moved to", "[variant]")
REQUIRE(v2.get<int>() == 42);
REQUIRE(v1.get<int>() == 42);
REQUIRE_THROWS_AS({
v3.get<int>();
},
REQUIRE_THROWS_AS(v3.get<int>(),
mapbox::util::bad_variant_access&);
v3 = std::move(v1);
@@ -327,9 +305,7 @@ TEST_CASE("implicit conversion to first type in variant type list", "[variant][i
using variant_type = mapbox::util::variant<long, char>;
variant_type var = 5l; // converted to long
REQUIRE(var.get<long>() == 5);
REQUIRE_THROWS_AS({
var.get<char>();
},
REQUIRE_THROWS_AS(var.get<char>(),
mapbox::util::bad_variant_access&);
}
@@ -498,13 +474,9 @@ TEST_CASE("storing reference wrappers works")
variant_type v{std::ref(a)};
REQUIRE(v.get<int>() == 1);
REQUIRE(mapbox::util::get<int>(v) == 1);
REQUIRE_THROWS_AS({
v.get<double>();
},
REQUIRE_THROWS_AS(v.get<double>(),
mapbox::util::bad_variant_access&);
REQUIRE_THROWS_AS({
mapbox::util::get<double>(v);
},
REQUIRE_THROWS_AS(mapbox::util::get<double>(v),
mapbox::util::bad_variant_access&);
a = 2;
REQUIRE(v.get<int>() == 2);
@@ -515,13 +487,9 @@ TEST_CASE("storing reference wrappers works")
v = std::ref(b);
REQUIRE(v.get<double>() == Approx(3.141));
REQUIRE(mapbox::util::get<double>(v) == Approx(3.141));
REQUIRE_THROWS_AS({
v.get<int>();
},
REQUIRE_THROWS_AS(v.get<int>(),
mapbox::util::bad_variant_access&);
REQUIRE_THROWS_AS({
mapbox::util::get<int>(v);
},
REQUIRE_THROWS_AS(mapbox::util::get<int>(v),
mapbox::util::bad_variant_access&);
b = 2.718;
REQUIRE(v.get<double>() == Approx(2.718));
@@ -530,9 +498,7 @@ TEST_CASE("storing reference wrappers works")
v.get<double>() = 4.1;
REQUIRE(b == Approx(4.1));
REQUIRE_THROWS_AS({
v.get<int>() = 4;
},
REQUIRE_THROWS_AS(v.get<int>() = 4,
mapbox::util::bad_variant_access&);
}
@@ -546,26 +512,18 @@ TEST_CASE("storing reference wrappers to consts works")
REQUIRE(v.get<int>() == 1);
REQUIRE(mapbox::util::get<int const>(v) == 1);
REQUIRE(mapbox::util::get<int>(v) == 1);
REQUIRE_THROWS_AS({
v.get<double const>();
},
REQUIRE_THROWS_AS(v.get<double const>(),
mapbox::util::bad_variant_access&);
REQUIRE_THROWS_AS({
mapbox::util::get<double const>(v);
},
REQUIRE_THROWS_AS(mapbox::util::get<double const>(v),
mapbox::util::bad_variant_access&);
double b = 3.141;
v = std::cref(b);
REQUIRE(v.get<double const>() == Approx(3.141));
REQUIRE(mapbox::util::get<double const>(v) == Approx(3.141));
REQUIRE_THROWS_AS({
v.get<int const>();
},
REQUIRE_THROWS_AS(v.get<int const>(),
mapbox::util::bad_variant_access&);
REQUIRE_THROWS_AS({
mapbox::util::get<int const>(v);
},
REQUIRE_THROWS_AS(mapbox::util::get<int const>(v),
mapbox::util::bad_variant_access&);
}
+31
View File
@@ -0,0 +1,31 @@
#include "catch.hpp"
#include <mapbox/variant.hpp>
#include <mapbox/variant_io.hpp>
#include <string>
TEST_CASE("variant_alternative", "[types]")
{
using variant_type = mapbox::util::variant<int, double, std::string>;
using type_0 = mapbox::util::variant_alternative<0, variant_type>::type;
using type_1 = mapbox::util::variant_alternative<1, variant_type>::type;
using type_2 = mapbox::util::variant_alternative<2, variant_type>::type;
//using type_3 = mapbox::util::variant_alternative<3, variant_type>::type; // compile error
constexpr bool check_0 = std::is_same<int, type_0>::value;
constexpr bool check_1 = std::is_same<double, type_1>::value;
constexpr bool check_2 = std::is_same<std::string, type_2>::value;
CHECK(check_0);
CHECK(check_1);
CHECK(check_2);
}
TEST_CASE("variant_size", "[types]")
{
constexpr auto value_0 = mapbox::util::variant_size<mapbox::util::variant<>>::value;
constexpr auto value_1 = mapbox::util::variant_size<mapbox::util::variant<int>>::value;
constexpr auto value_2 = mapbox::util::variant_size<mapbox::util::variant<int, std::string>>::value;
CHECK(value_0 == 0);
CHECK(value_1 == 1);
CHECK(value_2 == 2);
}
+52
View File
@@ -0,0 +1,52 @@
#include <mapbox/variant.hpp>
using namespace mapbox::util;
namespace {
template <typename... T>
struct tag {};
struct deduced_result_visitor
{
template <typename T>
tag<T> operator() (T);
template <typename T>
tag<T const> operator() (T) const;
template <typename T, typename U>
tag<T, U> operator() (T, U);
template <typename T, typename U>
tag<T, U const> operator() (T, U) const;
};
struct explicit_result_visitor : deduced_result_visitor
{
using result_type = tag<float>;
};
// Doing this compile-time test via assignment to typed tag objects gives
// more useful error messages when something goes wrong, than std::is_same
// in a static_assert would. Here if result_of_unary_visit returns anything
// other than the expected type on the left hand side, the conversion error
// message will tell you exactly what it was.
#ifdef __clang__
# pragma clang diagnostic ignored "-Wunused-variable"
#endif
tag<int> d1m = detail::result_of_unary_visit<deduced_result_visitor, int>{};
tag<int const> d1c = detail::result_of_unary_visit<deduced_result_visitor const, int>{};
tag<float> e1m = detail::result_of_unary_visit<explicit_result_visitor, int>{};
tag<float> e1c = detail::result_of_unary_visit<explicit_result_visitor const, int>{};
tag<int, int> d2m = detail::result_of_binary_visit<deduced_result_visitor, int>{};
tag<int, int const> d2c = detail::result_of_binary_visit<deduced_result_visitor const, int>{};
tag<float> e2m = detail::result_of_binary_visit<explicit_result_visitor, int>{};
tag<float> e2c = detail::result_of_binary_visit<explicit_result_visitor const, int>{};
} // namespace