move external dependence mapbox/variant into third_party directory

This commit is contained in:
Dennis Luxen
2015-01-20 18:06:26 +01:00
parent ec9b2dbe42
commit 501863a0eb
24 changed files with 0 additions and 0 deletions
+204
View File
@@ -0,0 +1,204 @@
#include <iostream>
#include <vector>
#include <thread>
#include <string>
#include <utility>
#include <boost/variant.hpp>
#include <boost/timer/timer.hpp>
#include "variant.hpp"
#define TEXT "Testing various variant implementations with a longish string ........................................."
//#define BOOST_VARIANT_MINIMIZE_SIZE
using namespace mapbox;
namespace test {
template <typename V>
struct Holder
{
typedef V value_type;
std::vector<value_type> data;
template <typename T>
void append_move(T && obj)
{
data.emplace_back(std::forward<T>(obj));
}
template <typename T>
void append(T const& obj)
{
data.push_back(obj);
}
};
} // namespace test
struct print : util::static_visitor<>
{
template <typename T>
void operator() (T const& val) const
{
std::cerr << val << ":" << typeid(T).name() << std::endl;
}
};
template <typename V>
struct dummy : boost::static_visitor<>
{
dummy(V & v)
: v_(v) {}
template <typename T>
void operator() (T const& val) const
{
v_ = val;
}
V & v_;
};
template <typename V>
struct dummy2 : util::static_visitor<>
{
dummy2(V & v)
: v_(v) {}
template <typename T>
void operator() (T const& val) const
{
v_.template set<T>(val);
}
V & v_;
};
void run_boost_test(std::size_t runs)
{
test::Holder<boost::variant<int, double, std::string>> h;
h.data.reserve(runs);
for (std::size_t i=0; i< runs; ++i)
{
h.append_move(std::string(TEXT));
h.append_move(123);
h.append_move(3.14159);
}
boost::variant<int, double, std::string> v;
for (auto const& v2 : h.data)
{
dummy<boost::variant<int, double, std::string>> d(v);
boost::apply_visitor(d, v2);
}
}
void run_variant_test(std::size_t runs)
{
test::Holder<util::variant<int, double, std::string>> h;
h.data.reserve(runs);
for (std::size_t i=0; i< runs; ++i)
{
h.append_move(std::string(TEXT));
h.append_move(123);
h.append_move(3.14159);
}
util::variant<int, double, std::string> v;
for (auto const& v2 : h.data)
{
dummy2<util::variant<int, double, std::string>> d(v);
util::apply_visitor (d, v2);
}
}
int main (int argc, char** argv)
{
if (argc!=2)
{
std::cerr << "Usage:" << argv[0] << " <num-runs>" << std::endl;
return 1;
}
#ifndef SINGLE_THREADED
const std::size_t THREADS = 4;
#endif
const std::size_t NUM_RUNS = static_cast<std::size_t>(std::stol(argv[1]));
#ifdef SINGLE_THREADED
{
std::cerr << "custom variant: ";
boost::timer::auto_cpu_timer t;
run_variant_test(NUM_RUNS);
}
{
std::cerr << "boost variant: ";
boost::timer::auto_cpu_timer t;
run_boost_test(NUM_RUNS);
}
{
std::cerr << "custom variant: ";
boost::timer::auto_cpu_timer t;
run_variant_test(NUM_RUNS);
}
{
std::cerr << "boost variant: ";
boost::timer::auto_cpu_timer t;
run_boost_test(NUM_RUNS);
}
#else
{
typedef std::vector<std::unique_ptr<std::thread>> thread_group;
typedef thread_group::value_type value_type;
thread_group tg;
std::cerr << "custom variant: ";
boost::timer::auto_cpu_timer timer;
for (std::size_t i=0; i<THREADS; ++i)
{
tg.emplace_back(new std::thread(run_variant_test, NUM_RUNS));
}
std::for_each(tg.begin(), tg.end(), [](value_type & t) {if (t->joinable()) t->join();});
}
{
typedef std::vector<std::unique_ptr<std::thread>> thread_group;
typedef thread_group::value_type value_type;
thread_group tg;
std::cerr << "boost variant: ";
boost::timer::auto_cpu_timer timer;
for (std::size_t i=0; i<THREADS; ++i)
{
tg.emplace_back(new std::thread(run_boost_test, NUM_RUNS));
}
std::for_each(tg.begin(), tg.end(), [](value_type & t) {if (t->joinable()) t->join();});
}
{
typedef std::vector<std::unique_ptr<std::thread>> thread_group;
typedef thread_group::value_type value_type;
thread_group tg;
std::cerr << "custom variant: ";
boost::timer::auto_cpu_timer timer;
for (std::size_t i=0; i<THREADS; ++i)
{
tg.emplace_back(new std::thread(run_variant_test, NUM_RUNS));
}
std::for_each(tg.begin(), tg.end(), [](value_type & t) {if (t->joinable()) t->join();});
}
{
typedef std::vector<std::unique_ptr<std::thread>> thread_group;
typedef thread_group::value_type value_type;
thread_group tg;
std::cerr << "boost variant: ";
boost::timer::auto_cpu_timer timer;
for (std::size_t i=0; i<THREADS; ++i)
{
tg.emplace_back(new std::thread(run_boost_test, NUM_RUNS));
}
std::for_each(tg.begin(), tg.end(), [](value_type & t) {if (t->joinable()) t->join();});
}
#endif
return EXIT_SUCCESS;
}
+135
View File
@@ -0,0 +1,135 @@
#include <cstdint>
#include <iostream>
#include <vector>
#include <thread>
#include <string>
#include <sstream>
#include <utility>
#include <type_traits>
#include <boost/variant.hpp>
#include <boost/timer/timer.hpp>
#include "variant.hpp"
using namespace mapbox;
namespace test {
template <typename T>
struct string_to_number {};
template <>
struct string_to_number<double>
{
double operator() (std::string const& str) const
{
return std::stod(str);
}
};
template <>
struct string_to_number<std::int64_t>
{
std::int64_t operator() (std::string const& str) const
{
return std::stoll(str);
}
};
template <>
struct string_to_number<std::uint64_t>
{
std::uint64_t operator() (std::string const& str) const
{
return std::stoull(str);
}
};
template <>
struct string_to_number<bool>
{
bool operator() (std::string const& str) const
{
bool result;
std::istringstream(str) >> std::boolalpha >> result;
return result;
}
};
struct javascript_equal_visitor : util::static_visitor<bool>
{
template <typename T>
bool operator() (T lhs, T rhs) const
{
return lhs == rhs;
}
template <typename T, class = typename std::enable_if<std::is_arithmetic<T>::value>::type>
bool operator() (T lhs, std::string const& rhs) const
{
return lhs == string_to_number<T>()(rhs);
}
template <typename T, class = typename std::enable_if<std::is_arithmetic<T>::value>::type>
bool operator() (std::string const& lhs, T rhs) const
{
return string_to_number<T>()(lhs) == rhs;
}
template <typename T0, typename T1>
bool operator() (T0 lhs, T1 rhs) const
{
return lhs == static_cast<T0>(rhs);
}
};
template <typename T>
struct javascript_equal
{
javascript_equal(T const& lhs)
: lhs_(lhs) {}
bool operator() (T const& rhs) const
{
return util::apply_visitor(test::javascript_equal_visitor(), lhs_, rhs);
}
T const& lhs_;
};
} // namespace test
int main (/*int argc, char** argv*/)
{
typedef util::variant<bool, std::int64_t, std::uint64_t, double, std::string> variant_type;
variant_type v0(3.14159);
variant_type v1(std::string("3.14159"));
variant_type v2(std::uint64_t(1));
std::cerr << v0 << " == " << v1 << " -> "
<< std::boolalpha << util::apply_visitor(test::javascript_equal_visitor(), v0, v1) << std::endl;
std::vector<variant_type> vec;
vec.emplace_back(std::string("1"));
vec.push_back(variant_type(std::uint64_t(2)));
vec.push_back(variant_type(std::uint64_t(3)));
vec.push_back(std::string("3.14159"));
vec.emplace_back(3.14159);
//auto itr = std::find_if(vec.begin(), vec.end(), [&v0](variant_type const& val) {
// return util::apply_visitor(test::javascript_equal_visitor(), v0, val);
// });
auto itr = std::find_if(vec.begin(), vec.end(), test::javascript_equal<variant_type>(v2));
if (itr != std::end(vec))
{
std::cout << "found " << *itr << std::endl;
}
else
{
std::cout << "can't find " << v2 << '\n';
}
return EXIT_SUCCESS;
}
+19
View File
@@ -0,0 +1,19 @@
#include <boost/variant.hpp>
#include <cstdint>
#include <stdexcept>
struct check : boost::static_visitor<>
{
template <typename T>
void operator() (T const& val) const
{
if (val != 0) throw std::runtime_error("invalid");
}
};
int main() {
typedef boost::variant<bool, int, double> variant_type;
variant_type v(0);
boost::apply_visitor(check(), v);
return 0;
}
+8683
View File
File diff suppressed because it is too large Load Diff
+82
View File
@@ -0,0 +1,82 @@
#define CATCH_CONFIG_RUNNER
#include "catch.hpp"
#include "optional.hpp"
using namespace mapbox;
struct dummy {
dummy(int _m_1, int _m_2) : m_1(_m_1), m_2(_m_2) {}
int m_1;
int m_2;
};
int main (int argc, char* const argv[])
{
int result = Catch::Session().run(argc, argv);
if (!result) printf("\x1b[1;32m ✓ \x1b[0m\n");
return result;
}
TEST_CASE( "optional can be instantiated with a POD type", "[optiona]" ) {
mapbox::util::optional<double> dbl_opt;
REQUIRE(!dbl_opt);
dbl_opt = 3.1415;
REQUIRE(dbl_opt);
REQUIRE(dbl_opt.get() == 3.1415);
REQUIRE(*dbl_opt == 3.1415);
}
TEST_CASE( "copy c'tor", "[optiona]" ) {
mapbox::util::optional<double> dbl_opt;
REQUIRE(!dbl_opt);
dbl_opt = 3.1415;
REQUIRE(dbl_opt);
mapbox::util::optional<double> other = dbl_opt;
REQUIRE(other.get() == 3.1415);
REQUIRE(*other == 3.1415);
}
TEST_CASE( "const operator*, const get()", "[optiona]" ) {
mapbox::util::optional<double> dbl_opt = 3.1415;
REQUIRE(dbl_opt);
const double pi1 = dbl_opt.get();
const double pi2 = *dbl_opt;
REQUIRE(pi1 == 3.1415);
REQUIRE(pi2 == 3.1415);
}
TEST_CASE( "emplace initialization, reset", "[optional]" ) {
mapbox::util::optional<dummy> dummy_opt;
REQUIRE(!dummy_opt);
// rvalues, baby!
dummy_opt.emplace(1, 2);
REQUIRE(dummy_opt);
REQUIRE(dummy_opt.get().m_1 == 1);
REQUIRE((*dummy_opt).m_2 == 2);
dummy_opt.reset();
REQUIRE(!dummy_opt);
}
TEST_CASE( "assignment", "[optional]") {
mapbox::util::optional<int> a;
mapbox::util::optional<int> b;
a = 1; b = 3;
REQUIRE(a.get() == 1);
REQUIRE(b.get() == 3);
b = a;
REQUIRE(a.get() == b.get());
REQUIRE(b.get() == 1);
}
+132
View File
@@ -0,0 +1,132 @@
#include <iostream>
#include <vector>
#include <thread>
#include <string>
#include <sstream>
#include <utility>
#include <type_traits>
#include <boost/timer/timer.hpp>
#include "variant.hpp"
using namespace mapbox;
namespace test {
struct add;
struct sub;
template <typename OpTag> struct binary_op;
typedef util::variant<int ,
util::recursive_wrapper<binary_op<add>>,
util::recursive_wrapper<binary_op<sub>>
> expression;
template <typename Op>
struct binary_op
{
expression left; // variant instantiated here...
expression right;
binary_op(expression && lhs, expression && rhs)
: left(std::move(lhs)), right(std::move(rhs))
{
}
};
struct print : util::static_visitor<void>
{
template <typename T>
void operator() (T const& val) const
{
std::cerr << val << ":" << typeid(T).name() << std::endl;
}
};
struct test : util::static_visitor<std::string>
{
template <typename T>
std::string operator() (T const& obj) const
{
return std::string("TYPE_ID=") + typeid(obj).name();
}
};
struct calculator : public util::static_visitor<int>
{
public:
int operator()(int value) const
{
return value;
}
int operator()(binary_op<add> const& binary) const
{
return util::apply_visitor(calculator(), binary.left)
+ util::apply_visitor(calculator(), binary.right);
}
int operator()(binary_op<sub> const& binary) const
{
return util::apply_visitor(calculator(), binary.left)
- util::apply_visitor(calculator(), binary.right);
}
};
struct to_string : public util::static_visitor<std::string>
{
public:
std::string operator()(int value) const
{
return std::to_string(value);
}
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);
}
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);
}
};
} // namespace test
int main (int argc, char** argv)
{
if (argc != 2)
{
std::cerr << "Usage" << argv[0] << " <num-iter>" << std::endl;
return EXIT_FAILURE;
}
const std::size_t NUM_ITER = static_cast<std::size_t>(std::stol(argv[1]));
test::expression result(
test::binary_op<test::sub>(
test::binary_op<test::add>(2, 3), 4));
std::cerr << "TYPE OF RESULT-> " << util::apply_visitor(test::test(), result) << std::endl;
{
boost::timer::auto_cpu_timer t;
int total = 0;
for (std::size_t i = 0; i < NUM_ITER; ++i)
{
total += util::apply_visitor(test::calculator(), result);
}
std::cerr << "total=" << total << std::endl;
}
std::cerr << util::apply_visitor(test::to_string(), result) << "=" << util::apply_visitor(test::calculator(), result) << std::endl;
return EXIT_SUCCESS;
}
+128
View File
@@ -0,0 +1,128 @@
#include <iostream>
#include <vector>
#include <thread>
#include <string>
#include <sstream>
#include <utility>
#include <type_traits>
#include <boost/variant.hpp>
#include <boost/timer/timer.hpp>
#include "variant.hpp"
using namespace mapbox;
namespace test {
struct add;
struct sub;
template <typename OpTag> struct binary_op;
typedef util::variant<int ,
std::unique_ptr<binary_op<add>>,
std::unique_ptr<binary_op<sub>>
> expression;
template <typename Op>
struct binary_op
{
expression left; // variant instantiated here...
expression right;
binary_op(expression && lhs, expression && rhs)
: left(std::move(lhs)), right(std::move(rhs)) {}
};
struct print : util::static_visitor<void>
{
template <typename T>
void operator() (T const& val) const
{
std::cerr << val << ":" << typeid(T).name() << std::endl;
}
};
struct test : util::static_visitor<std::string>
{
template <typename T>
std::string operator() (T const& obj) const
{
return std::string("TYPE_ID=") + typeid(obj).name();
}
};
struct calculator : public util::static_visitor<int>
{
public:
int operator()(int value) const
{
return value;
}
int operator()(std::unique_ptr<binary_op<add>> const& binary) const
{
return util::apply_visitor(calculator(), binary->left)
+ util::apply_visitor(calculator(), binary->right);
}
int operator()(std::unique_ptr<binary_op<sub>> const& binary) const
{
return util::apply_visitor(calculator(), binary->left)
- util::apply_visitor(calculator(), binary->right);
}
};
struct to_string : public util::static_visitor<std::string>
{
public:
std::string operator()(int value) const
{
return std::to_string(value);
}
std::string operator()(std::unique_ptr<binary_op<add>> const& binary) const
{
return util::apply_visitor(to_string(), binary->left) + std::string("+")
+ util::apply_visitor(to_string(), binary->right);
}
std::string operator()(std::unique_ptr<binary_op<sub>> const& binary) const
{
return util::apply_visitor(to_string(), binary->left) + std::string("-")
+ util::apply_visitor(to_string(), binary->right);
}
};
} // namespace test
int main (int argc, char** argv)
{
if (argc != 2)
{
std::cerr << "Usage" << argv[0] << " <num-iter>" << std::endl;
return EXIT_FAILURE;
}
const std::size_t NUM_ITER = static_cast<std::size_t>(std::stol(argv[1]));
test::expression sum(std::unique_ptr<test::binary_op<test::add>>(new test::binary_op<test::add>(2, 3)));
test::expression result(std::unique_ptr<test::binary_op<test::sub>>(new test::binary_op<test::sub>(std::move(sum), 4)));
std::cerr << "TYPE OF RESULT-> " << util::apply_visitor(test::test(), result) << std::endl;
{
boost::timer::auto_cpu_timer t;
int total = 0;
for (std::size_t i = 0; i < NUM_ITER; ++i)
{
total += util::apply_visitor(test::calculator(), result);
}
std::cerr << "total=" << total << std::endl;
}
std::cerr << util::apply_visitor(test::to_string(), result) << "=" << util::apply_visitor(test::calculator(), result) << std::endl;
return EXIT_SUCCESS;
}
+306
View File
@@ -0,0 +1,306 @@
#define CATCH_CONFIG_RUNNER
#include "catch.hpp"
#include "variant.hpp"
#include <algorithm>
#include <cstdint>
#include <iterator>
#include <limits>
#include <memory>
#include <ostream>
#include <sstream>
#include <string>
using namespace mapbox;
template <typename T>
struct mutating_visitor
{
mutating_visitor(T & val)
: val_(val) {}
void operator() (T & val) const
{
val = val_;
}
template <typename T1>
void operator() (T1& ) const {} // no-op
T & val_;
};
TEST_CASE( "variant version", "[variant]" ) {
unsigned int version = VARIANT_VERSION;
REQUIRE(version == 100);
#if VARIANT_VERSION == 100
REQUIRE(true);
#else
REQUIRE(false);
#endif
}
TEST_CASE( "variant can be moved into vector", "[variant]" ) {
typedef util::variant<bool,std::string> variant_type;
variant_type v(std::string("test"));
std::vector<variant_type> vec;
vec.emplace_back(std::move(v));
REQUIRE(v.get<std::string>() != std::string("test"));
REQUIRE(vec.at(0).get<std::string>() == std::string("test"));
}
TEST_CASE( "variant should support built-in types", "[variant]" ) {
SECTION( "bool" ) {
util::variant<bool> v(true);
REQUIRE(v.valid());
REQUIRE(v.is<bool>());
REQUIRE(v.get_type_index() == 0);
REQUIRE(v.get<bool>() == true);
v.set<bool>(false);
REQUIRE(v.get<bool>() == false);
v = true;
REQUIRE(v == util::variant<bool>(true));
}
SECTION( "nullptr" ) {
typedef std::nullptr_t value_type;
util::variant<value_type> v(nullptr);
REQUIRE(v.valid());
REQUIRE(v.is<value_type>());
REQUIRE(v.get_type_index() == 0);
// TODO: commented since it breaks on windows: 'operator << is ambiguous'
//REQUIRE(v.get<value_type>() == nullptr);
// FIXME: does not compile: ./variant.hpp:340:14: error: use of overloaded operator '<<' is ambiguous (with operand types 'std::__1::basic_ostream<char>' and 'const nullptr_t')
// https://github.com/mapbox/variant/issues/14
//REQUIRE(v == util::variant<value_type>(nullptr));
}
SECTION( "unique_ptr" ) {
typedef std::unique_ptr<std::string> value_type;
util::variant<value_type> v(value_type(new std::string("hello")));
REQUIRE(v.valid());
REQUIRE(v.is<value_type>());
REQUIRE(v.get_type_index() == 0);
REQUIRE(*v.get<value_type>().get() == *value_type(new std::string("hello")).get());
}
SECTION( "string" ) {
typedef std::string value_type;
util::variant<value_type> v(value_type("hello"));
REQUIRE(v.valid());
REQUIRE(v.is<value_type>());
REQUIRE(v.get_type_index() == 0);
REQUIRE(v.get<value_type>() == value_type("hello"));
v.set<value_type>(value_type("there"));
REQUIRE(v.get<value_type>() == value_type("there"));
v = value_type("variant");
REQUIRE(v == util::variant<value_type>(value_type("variant")));
}
SECTION( "size_t" ) {
typedef std::size_t value_type;
util::variant<value_type> v(std::numeric_limits<value_type>::max());
REQUIRE(v.valid());
REQUIRE(v.is<value_type>());
REQUIRE(v.get_type_index() == 0);
REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
v.set<value_type>(value_type(0));
REQUIRE(v.get<value_type>() == value_type(0));
v = value_type(1);
REQUIRE(v == util::variant<value_type>(value_type(1)));
}
SECTION( "int8_t" ) {
typedef std::int8_t value_type;
util::variant<value_type> v(std::numeric_limits<value_type>::max());
REQUIRE(v.valid());
REQUIRE(v.is<value_type>());
REQUIRE(v.get_type_index() == 0);
REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
v.set<value_type>(0);
REQUIRE(v.get<value_type>() == value_type(0));
v = value_type(1);
REQUIRE(v == util::variant<value_type>(value_type(1)));
}
SECTION( "int16_t" ) {
typedef std::int16_t value_type;
util::variant<value_type> v(std::numeric_limits<value_type>::max());
REQUIRE(v.valid());
REQUIRE(v.is<value_type>());
REQUIRE(v.get_type_index() == 0);
REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
v.set<value_type>(0);
REQUIRE(v.get<value_type>() == value_type(0));
v = value_type(1);
REQUIRE(v == util::variant<value_type>(value_type(1)));
}
SECTION( "int32_t" ) {
typedef std::int32_t value_type;
util::variant<value_type> v(std::numeric_limits<value_type>::max());
REQUIRE(v.valid());
REQUIRE(v.is<value_type>());
REQUIRE(v.get_type_index() == 0);
REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
v.set<value_type>(0);
REQUIRE(v.get<value_type>() == value_type(0));
v = value_type(1);
REQUIRE(v == util::variant<value_type>(value_type(1)));
}
SECTION( "int64_t" ) {
typedef std::int64_t value_type;
util::variant<value_type> v(std::numeric_limits<value_type>::max());
REQUIRE(v.valid());
REQUIRE(v.is<value_type>());
REQUIRE(v.get_type_index() == 0);
REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
v.set<value_type>(0);
REQUIRE(v.get<value_type>() == value_type(0));
v = value_type(1);
REQUIRE(v == util::variant<value_type>(value_type(1)));
}
}
struct MissionInteger
{
typedef uint64_t value_type;
value_type val_;
public:
MissionInteger(uint64_t val) :
val_(val) {}
bool operator==(MissionInteger const& rhs) const
{
return (val_ == rhs.get());
}
uint64_t get() const
{
return val_;
}
};
// TODO - remove after https://github.com/mapbox/variant/issues/14
std::ostream& operator<<(std::ostream& os, MissionInteger const& rhs)
{
os << rhs.get();
return os;
}
TEST_CASE( "variant should support custom types", "[variant]" ) {
// http://www.missionintegers.com/integer/34838300
util::variant<MissionInteger> v(MissionInteger(34838300));
REQUIRE(v.valid());
REQUIRE(v.is<MissionInteger>());
REQUIRE(v.get_type_index() == 0);
REQUIRE(v.get<MissionInteger>() == MissionInteger(34838300));
REQUIRE(v.get<MissionInteger>().get() == MissionInteger::value_type(34838300));
// TODO: should both of the set usages below compile?
v.set<MissionInteger>(MissionInteger::value_type(0));
v.set<MissionInteger>(MissionInteger(0));
REQUIRE(v.get<MissionInteger>().get() == MissionInteger::value_type(0));
v = MissionInteger(1);
REQUIRE(v == util::variant<MissionInteger>(MissionInteger(1)));
}
// Test internal api
TEST_CASE( "variant should correctly index types", "[variant]" ) {
typedef util::variant<bool,std::string,std::uint64_t,std::int64_t,double,float> variant_type;
// Index is in reverse order
REQUIRE(variant_type(true).get_type_index() == 5);
REQUIRE(variant_type(std::string("test")).get_type_index() == 4);
REQUIRE(variant_type(std::uint64_t(0)).get_type_index() == 3);
REQUIRE(variant_type(std::int64_t(0)).get_type_index() == 2);
REQUIRE(variant_type(double(0.0)).get_type_index() == 1);
REQUIRE(variant_type(float(0.0)).get_type_index() == 0);
}
TEST_CASE( "get with type not in variant type list should throw", "[variant]" ) {
typedef util::variant<int> variant_type;
variant_type var = 5;
REQUIRE(var.get<int>() == 5);
REQUIRE_THROWS(var.get<double>()); // XXX shouldn't this be a compile time error? See https://github.com/mapbox/variant/issues/24
}
TEST_CASE( "get with wrong type (here: double) should throw", "[variant]" ) {
typedef util::variant<int, double> variant_type;
variant_type var = 5;
REQUIRE(var.get<int>() == 5);
REQUIRE_THROWS(var.get<double>());
}
TEST_CASE( "get with wrong type (here: int) should throw", "[variant]" ) {
typedef util::variant<int, double> variant_type;
variant_type var = 5.0;
REQUIRE(var.get<double>() == 5.0);
REQUIRE_THROWS(var.get<int>());
}
TEST_CASE( "implicit conversion", "[variant][implicit conversion]" ) {
typedef util::variant<int> variant_type;
variant_type var(5.0); // converted to int
REQUIRE(var.get<int>() == 5);
REQUIRE_THROWS(var.get<double>());
var = 6.0; // works for operator=, too
REQUIRE(var.get<int>() == 6);
}
TEST_CASE( "implicit conversion to first type in variant type list", "[variant][implicit conversion]" ) {
typedef util::variant<long, char> variant_type;
variant_type var = 5.0; // converted to long
REQUIRE(var.get<long>() == 5);
REQUIRE_THROWS(var.get<char>());
REQUIRE_THROWS(var.get<double>());
}
TEST_CASE( "implicit conversion to unsigned char", "[variant][implicit conversion]" ) {
typedef util::variant<unsigned char> variant_type;
variant_type var = 100.0;
CHECK(var.get<unsigned char>() == static_cast<unsigned char>(100.0));
CHECK(var.get<unsigned char>() == static_cast<unsigned char>(static_cast<unsigned int>(100.0)));
}
struct dummy {};
TEST_CASE( "variant value traits", "[variant::detail]" ) {
// Users should not create variants with duplicated types
// however our type indexing should still work
// Index is in reverse order
REQUIRE((util::detail::value_traits<bool, bool, int, double, std::string>::index == 3));
REQUIRE((util::detail::value_traits<int, bool, int, double, std::string>::index == 2));
REQUIRE((util::detail::value_traits<double, bool, int, double, std::string>::index == 1));
REQUIRE((util::detail::value_traits<std::string, bool, int, double, std::string>::index == 0));
REQUIRE((util::detail::value_traits<dummy, bool, int, double, std::string>::index == util::detail::invalid_value));
REQUIRE((util::detail::value_traits<std::vector<int>, bool, int, double, std::string>::index == util::detail::invalid_value));
}
TEST_CASE( "variant default constructor", "[variant][default constructor]" ) {
// By default variant is initialised with (default constructed) first type in template parameters pack
// As a result first type in Types... must be default constructable
// NOTE: index in reverse order -> index = N - 1
REQUIRE((util::variant<int, double, std::string>().get_type_index() == 2));
REQUIRE((util::variant<int, double, std::string>(util::no_init()).get_type_index() == util::detail::invalid_value));
}
TEST_CASE( "variant visitation", "[visitor][unary visitor]" ) {
util::variant<int, double, std::string> var(123);
REQUIRE(var.get<int>() == 123);
int val = 456;
mutating_visitor<int> visitor(val);
util::apply_visitor(visitor, var);
REQUIRE(var.get<int>() == 456);
}
TEST_CASE( "variant printer", "[visitor][unary visitor][printer]" ) {
typedef util::variant<int, double, std::string> variant_type;
std::vector<variant_type> var = {2.1, 123, "foo", 456};
std::stringstream out;
std::copy(var.begin(), var.end(), std::ostream_iterator<variant_type>(out, ","));
out << var[2];
REQUIRE(out.str() == "2.1,123,foo,456,foo");
}
int main (int argc, char* const argv[])
{
int result = Catch::Session().run(argc, argv);
if (!result) printf("\x1b[1;32m ✓ \x1b[0m\n");
return result;
}
+22
View File
@@ -0,0 +1,22 @@
#include "variant.hpp"
#include <cstdint>
#include <stdexcept>
using namespace mapbox;
struct check : util::static_visitor<>
{
template <typename T>
void operator() (T const& val) const
{
if (val != 0) throw std::runtime_error("invalid");
}
};
int main() {
typedef util::variant<bool, int, double> variant_type;
variant_type v(0);
util::apply_visitor(check(), v);
return 0;
}