a2a485834 Update CHANGELOG 82f95612e Merge pull request #180 from mapbox/lightmare-move-out c0e7ac6fd Merge pull request #181 from lightmare/revive-result-type d13e61784 Revert "visitor - revive using explicit return type when provided" 0ebf09dea revive using visitor::result_type when available b1076bbee visitor - revive using explicit return type when provided 2e3947578 properly forward through variant::visit b09c7e121 travis: force compiling all tests 0ce49d837 add test case for issue #180 discovered by @artemp 8fc03c4d9 Remove clang 3.7 and gcc47 builds f6e57e9c2 Merge branch 'move-out' of https://github.com/lightmare/variant into lightmare-move-out 94c8ccf54 fix expected compilation error messages 6d21f7704 perfect forwarding in apply_visitor d960916fc implement match on rvalue 8b9eeb238 test matching unwrapped rvalue with lambda expression 77a24b9c0 Merge remote-tracking branch 'upstream/move-out' into move-out 4ce01e1c2 clang - self-assignment is a compile time error c94634bbd Merge pull request #172 from mapbox/self-assignment 3dcac646f updated move assignment as suggested in https://github.com/mapbox/variant/pull/172#discussion_r328043024 b36c78e12 Just use `assert(this!=&other)` in move assignment operator (https://stackoverflow.com/questions/9322174/move-assignment-operator-and-if-this-rhs) 767bc18f3 Improve self-assignment/move checks to have one return path. 94fc9377e Revert "disable -Wself-assign-overloaded (-Werror) in self-assignment test" da2b171b7 Revert "don't fail old compilers" 7918a4847 don't fail old compilers ad85832b8 disable -Wself-assign-overloaded (-Werror) in self-assignment test 4da455725 add self-assignment checks in copy and move assignment operator= (ref #164) cb02ad487 update CHANGELOG for variant v1.1.6 release [skip ci] a4f87dc69 fix version number ff14f222a update CHANGELOG 0305fdb2a Merge pull request #171 from mapbox/jrex-mute-clang-analyzer 2fef61f08 Moved to in-class initialization 52df2765e update CHANGELOG in preparation for v1.1.6 release 63854e5c9 Add explicit initialization of data to mute clang static analyzer warnings in Xcode (10.2). 0f734f01e Merge pull request #167 from mapbox/clang++4 5a5ecca5b Run ASAN builda in isolated VM via `sudo : required` c1a14e7d9 update mason + update clang++ to 4.0.1 fe0a0666f update mason 11a36a9f1 steady .. downgrade clang++ to 4.0.0 f31bcfb4b try fixing travis via upgrading clang++ from 3.9.1 -> 4.0.1 502e32b8b fix Makefile a64062576 use `ls -lah` as `du -h --apparent-size` is not universally supported. ef3856c85 report actual file size not allocated size. 256ddd555 Merge pull request #160 from mlogan/master 9c81bef8c Fix the noexcept specifications for move assignment and conversion. 5eee328d6 Merge pull request #165 from nick70/master 0888a8e92 Fix README.md issues 859a8c933 Merge pull request #163 from MaxRis/master 215d64585 Removes deprecated static_visitor to avoid msvc C4996 compiler warning 237f83cad Merge pull request #162 from mapbox/variant_alternative 835ebc193 add `variant_size` helper 30560e19e fix preprocessor logic 8b1de3147 add compile index in range check for __type_pack_element branch. ae1931413 add optimized 'variant_alternative' implementation usinh built-in `__type_pack_element` when available (clang++) 3ffef950b add `variant_alternative_t` 3449d00cf alternative implementation of `variant_alternative` 4b98c485c add lost test check + remove stderr 43357808c add intial `variant_alternative` implementation (#161 http://en.cppreference.com/w/cpp/utility/variant/variant_alternative) ba3085a5e use full sha1 75bb549d2 update CHANGELOG (git log <tag1>...<tag2> --pretty=format:'* %s [view commit](http://github.com/mapbox/variant/commit/%H)' --reverse) 6497bce68 add <sha1> to CHANGELOG entries. 555436f71 add CHANGELOG.md skeleton b78b51548 Merge pull request #154 from ricardocosme/forwarding_reference_make_visitor f0b50062b Add copy assignment and move assignment operators. 9f991da78 Use forwarding reference in make_visitor and visitor 266f68d9f Merge pull request #153 from ricardocosme/boost-build 04a6797a6 - Add auxiliar rule exe-test. bd0a2d559 - Use of the module 'os' to get BOOST_DIR. - Add macro SINGLE_THREADED to single threading mode. - Define single threading mode as default. - Add lambda_overload_test and hashable_test. 561a09dd0 - Remove the use of boost libraries. - Add default build. b2471ffc7 - Add a project mapbox_variant. - Use of the 'os' module to capture CXX_STD. - Common configs moved to project. - Built targets moved to 'out' directory. 624720759 add test for ref #147 + https://github.com/mapbox/variant/pull/147 e01b7bf33 Merge branch 'BlueSolei-master' 195367cfc Merge branch 'master' of https://github.com/BlueSolei/variant into BlueSolei-master ea106db54 recursive_wrapper test - avoid constructing new functor in recursive calls, call itself via `this` pointer. 7a541ba10 recursive_wrapper fail to compile when used with 2 classes which are base and derived #146 291121f6a Merge pull request #144 from narizhny/Casts 51fccd755 Add static_variant_cast, dynamic_variant_cast 550ac2f15 Merge pull request #143 from tomhughes/catch a064940e2 REQUIRE_THROWS etc take an expression not a block f9c265d7e Update bundled Catch to v1.9.0 5778eede1 Fixes example: rvalue variant matching cdb9faf0f Simplifies result_of_* and let them handle rvalue refs c5dac859a Failing Test Case: std::move-ing out of variant 916139a2e Merge pull request #141 from mapbox/match-otherwise 3d807d316 Merge pull request #138 from mapbox/sizeof 9ac8978f5 Adds a test for polymorphic lambdas in match, resolves #140 c839c666c add missing <limits> 35487cd39 Make `type_index_t` configurable at compile time via `MAPBOX_VARIANT_MINIMIZE_SIZE` and `MAPBOX_VARIANT_OPTIMIZE_FOR_SPEED`. Default is `unsigned int`. (ref #138) 3f6fd131e Add compile time check to disallow array types as alternatives. fa8e124a2 Ensure internal index type is capable of holding all alternatives (ref #138) 05ee9aca1 use `mapbox::util::type_index_t` (#19) 9eec1fd48 make type used for `type_index` configurable via `type_index_t` typdef + use `unsigned int` by default. This addresses `sizeof` discrepancies between boost/std/mapbox variants (ref #19) d2588a8f1 Trivial missing comma in README example code 05b7612aa Merge pull request #135 from mapbox/llvm-3.9.1 61f8acea1 upgrade mason f5fb4661e upgrade to llvm 3.9.1 5baa948fa fix gyp build 4923eb527 osx: test that will support both latest (10.12) and oldest with c++11 support: 10.7 18a8055fe Merge pull request #134 from lightmare/warnings 5141d8d21 remove useless and/or dubious compiler flags a9707c3de Merge pull request #133 from mapbox/Werror a80beaafc disable -Wparentheses for older gcc c8ec829ff drop -Wstack-protector which gives unhelpful warnings 7b409402c upgrade libstdc++ for coverage build b43398619 Add -pthread 904dcaee6 limit some flags to clang++ 1023f2d9a try without pthreads 886377de0 fortification flags + -pthreads for linux where needed cf9a53499 build in both release and debug on travis 539d71274 fix conversion warnings 253047f53 enable -Werror, suppress warnings from non variant headers using isystem 18919174d Merge pull request #132 from lightmare/avoid-tuple-instantiation 4febf973c avoid expensive instantiation of tuple constructor in noexcept 6317a0b74 re-enable older compilers, trim excess 4fe5ced5d more sanitizer options d1bb6e546 -fsanitize=cfi and -fsanitize=safe-stack 20d693ed9 fix LDFLAGS 9b2de4546 test with clang++ sanitizers and flto 702826365 disable clang++ 3.9, will work on getting working in a branch e07a533a8 fix clang++ PATH 84eeb54c9 test clang++ via mason a760cea8d upgrade mason b9c58d631 upgrade boost to 1.62.0 c81b475b4 makefile improvements ce2eea644 travis: fix addons efa75df27 test with clang 3.9 and g++-6 cb5635ba2 add package.json for publishing to npm 02bd1ac4c Merge pull request #129 from daniel-j-h/docs ed84def12 Merge pull request #128 from daniel-j-h/match 3c17c37ae Merge pull request #126 from daniel-j-h/hashable d0266436b Adds Documentation for Readme, resolves #98 720c23736 Implements Pattern Matching for Sum Types via `.match` Member Function. 97d0379f0 Makes variant<Ts...> hashable iff Ts... are hashable, closes #125 9a115c5eb Merge branch 'daniel-j-h-lambda-visitor' 4d462f27b Adds C++14 SFINAE Test 2275a6197 Removes ::type Usage d09188640 Provides Convenient Lambda Overload Visitor Interface, resolves #113. a5a79a594 Fix #122 by adding an extra compile check in universal ctor (via @lightmare) + test case 9b46167f5 nicer stderr 84a426a31 Merge pull request #120 from mapbox/types 173a74579 add `struct adapted_variant_tag;` e5818212a expose `using types = std::tuple<Types...>;` - useful for adapting variant to `boost::spirit` (QI,Karma,X3) aaddee927 Update README 8e2f69641 Merge pull request #116 from lightmare/disjunction 2c7ddecdb use C++17 disjunction for no-references and one-convertible tests 388376ac9 Merge pull request #114 from mapbox/strict-conversions 075d9636f comment out code 8be6a2aa8 update tests 71ac8fdf9 Re-implement type matching logic to reject ambigious conversions c511b2f34 add test for b3a002d185afac295486e2ebd6b84c78a2267ba0 (ref #112) b3a002d18 fix value_traits to be able to match T, T& and T const& to the direct type stored in variant (ref #112) b5728ad76 update .mason pkgs eedafd31f use local HAS_EXCEPTIONS #define (__EXCEPTIONS is g++/clang specific macro) 372d7c88f c++ apply formatting 20e44accb Merge pull request #110 from mapbox/110-get_unchecked 37acc5a7c uncomment tests ref #82 adf0e02bc variant - yield return type of mapbox::util::get<T> automatically and make interface consistent (addresses #82) bb8c2d203 Merge branch '111-which-constexpr' dca3d967c Merge branch 'master' into 111-which-constexpr 74ce146d9 add static which<T>() function to get a contained types' which value 48d60445c remove unused internal metafunctions 434dab048 Add get_unchecked<T>() to enable use with exceptions disabled 2f8a4a381 Merge pull request #109 from mapbox/darwin-build-flags 33e27ec4c Update README.md 55579f03f Fix building with GCC (g++-5.2.0) on OS X (Darwin) (ref #108) 8bdad6b6d Update README.md 7f7470fee Jamroot - add missing include directory ./test/include for auto_cpu_timer.hpp 4368d7529 remove expected error string - current implementation emits compiler specific error message e.g c6ae1ea0a `is<T>()` - add specialisation for recursive_wrapper<T> + update tests (ref #102) 04dc3a46b Install boost with mason; eliminate boost::timer dependency 9b2fc858c Remove Xcode 6 from CI matrix 1bc46e525 Merge pull request #101 from mapbox/include 390229a59 fix compilation bfe0f19dd update remaining `<variant.hpp>` to `<mapbox/variant.hpp>` 343831611 ammend include dir a606e9024 fix typo 9bd902536 Merge branch 'master' into include 7e4a01189 Add include directory 13c631a62 Update README.md f00b24bf6 move headers into include/mapbox folder - closes #99 35ca16c74 issue warning `-Wweak-vtables` so this issue is not forgotten (https://github.com/mapbox/variant/issues/95) 82bb901b6 run coverage with clang 3.5 - fix clang 3.8 build 5f6ed7149 remove invalid option for llvm-cov f034d5571 fix clang 3.8 compile, try 3.9 b0ee4729b fix coverage to avoid warning: unit.gcno:version '402*', prefer '406*' 3f025adbf remove erroneous `;` ref #96 git-subtree-dir: third_party/variant git-subtree-split: a2a4858345423a760eca300ec42acad1ad123aa3
1054 lines
32 KiB
C++
1054 lines
32 KiB
C++
#ifndef MAPBOX_UTIL_VARIANT_HPP
|
|
#define MAPBOX_UTIL_VARIANT_HPP
|
|
|
|
#include <cassert>
|
|
#include <cstddef> // size_t
|
|
#include <new> // operator new
|
|
#include <stdexcept> // runtime_error
|
|
#include <string>
|
|
#include <tuple>
|
|
#include <type_traits>
|
|
#include <typeinfo>
|
|
#include <utility>
|
|
#include <functional>
|
|
#include <limits>
|
|
|
|
#include <mapbox/recursive_wrapper.hpp>
|
|
#include <mapbox/variant_visitor.hpp>
|
|
|
|
// clang-format off
|
|
// [[deprecated]] is only available in C++14, use this for the time being
|
|
#if __cplusplus <= 201103L
|
|
# ifdef __GNUC__
|
|
# define MAPBOX_VARIANT_DEPRECATED __attribute__((deprecated))
|
|
# elif defined(_MSC_VER)
|
|
# define MAPBOX_VARIANT_DEPRECATED __declspec(deprecated)
|
|
# else
|
|
# define MAPBOX_VARIANT_DEPRECATED
|
|
# endif
|
|
#else
|
|
# define MAPBOX_VARIANT_DEPRECATED [[deprecated]]
|
|
#endif
|
|
|
|
|
|
#ifdef _MSC_VER
|
|
// https://msdn.microsoft.com/en-us/library/bw1hbe6y.aspx
|
|
# ifdef NDEBUG
|
|
# define VARIANT_INLINE __forceinline
|
|
# else
|
|
# define VARIANT_INLINE //__declspec(noinline)
|
|
# endif
|
|
#else
|
|
# ifdef NDEBUG
|
|
# define VARIANT_INLINE //inline __attribute__((always_inline))
|
|
# else
|
|
# define VARIANT_INLINE __attribute__((noinline))
|
|
# endif
|
|
#endif
|
|
// clang-format on
|
|
|
|
// Exceptions
|
|
#if defined( __EXCEPTIONS) || defined( _MSC_VER)
|
|
#define HAS_EXCEPTIONS
|
|
#endif
|
|
|
|
#define VARIANT_MAJOR_VERSION 1
|
|
#define VARIANT_MINOR_VERSION 1
|
|
#define VARIANT_PATCH_VERSION 0
|
|
|
|
#define VARIANT_VERSION (VARIANT_MAJOR_VERSION * 100000) + (VARIANT_MINOR_VERSION * 100) + (VARIANT_PATCH_VERSION)
|
|
|
|
namespace mapbox {
|
|
namespace util {
|
|
|
|
// XXX This should derive from std::logic_error instead of std::runtime_error.
|
|
// See https://github.com/mapbox/variant/issues/48 for details.
|
|
class bad_variant_access : public std::runtime_error
|
|
{
|
|
|
|
public:
|
|
explicit bad_variant_access(const std::string& what_arg)
|
|
: runtime_error(what_arg) {}
|
|
|
|
explicit bad_variant_access(const char* what_arg)
|
|
: runtime_error(what_arg) {}
|
|
|
|
}; // class bad_variant_access
|
|
|
|
#if !defined(MAPBOX_VARIANT_MINIMIZE_SIZE)
|
|
using type_index_t = unsigned int;
|
|
#else
|
|
#if defined(MAPBOX_VARIANT_OPTIMIZE_FOR_SPEED)
|
|
using type_index_t = std::uint_fast8_t;
|
|
#else
|
|
using type_index_t = std::uint_least8_t;
|
|
#endif
|
|
#endif
|
|
|
|
namespace detail {
|
|
|
|
static constexpr type_index_t invalid_value = type_index_t(-1);
|
|
|
|
template <typename T, typename... Types>
|
|
struct direct_type;
|
|
|
|
template <typename T, typename First, typename... Types>
|
|
struct direct_type<T, First, Types...>
|
|
{
|
|
static constexpr type_index_t index = std::is_same<T, First>::value
|
|
? sizeof...(Types)
|
|
: direct_type<T, Types...>::index;
|
|
};
|
|
|
|
template <typename T>
|
|
struct direct_type<T>
|
|
{
|
|
static constexpr type_index_t index = invalid_value;
|
|
};
|
|
|
|
#if __cpp_lib_logical_traits >= 201510L
|
|
|
|
using std::conjunction;
|
|
using std::disjunction;
|
|
|
|
#else
|
|
|
|
template <typename...>
|
|
struct conjunction : std::true_type {};
|
|
|
|
template <typename B1>
|
|
struct conjunction<B1> : B1 {};
|
|
|
|
template <typename B1, typename B2>
|
|
struct conjunction<B1, B2> : std::conditional<B1::value, B2, B1>::type {};
|
|
|
|
template <typename B1, typename... Bs>
|
|
struct conjunction<B1, Bs...> : std::conditional<B1::value, conjunction<Bs...>, B1>::type {};
|
|
|
|
template <typename...>
|
|
struct disjunction : std::false_type {};
|
|
|
|
template <typename B1>
|
|
struct disjunction<B1> : B1 {};
|
|
|
|
template <typename B1, typename B2>
|
|
struct disjunction<B1, B2> : std::conditional<B1::value, B1, B2>::type {};
|
|
|
|
template <typename B1, typename... Bs>
|
|
struct disjunction<B1, Bs...> : std::conditional<B1::value, B1, disjunction<Bs...>>::type {};
|
|
|
|
#endif
|
|
|
|
template <typename T, typename... Types>
|
|
struct convertible_type;
|
|
|
|
template <typename T, typename First, typename... Types>
|
|
struct convertible_type<T, First, Types...>
|
|
{
|
|
static constexpr type_index_t index = std::is_convertible<T, First>::value
|
|
? disjunction<std::is_convertible<T, Types>...>::value ? invalid_value : sizeof...(Types)
|
|
: convertible_type<T, Types...>::index;
|
|
};
|
|
|
|
template <typename T>
|
|
struct convertible_type<T>
|
|
{
|
|
static constexpr type_index_t index = invalid_value;
|
|
};
|
|
|
|
template <typename T, typename... Types>
|
|
struct value_traits
|
|
{
|
|
using value_type = typename std::remove_const<typename std::remove_reference<T>::type>::type;
|
|
using value_type_wrapper = recursive_wrapper<value_type>;
|
|
static constexpr type_index_t direct_index = direct_type<value_type, Types...>::index;
|
|
static constexpr bool is_direct = direct_index != invalid_value;
|
|
static constexpr type_index_t index_direct_or_wrapper = is_direct ? direct_index : direct_type<value_type_wrapper, Types...>::index;
|
|
static constexpr bool is_direct_or_wrapper = index_direct_or_wrapper != invalid_value;
|
|
static constexpr type_index_t index = is_direct_or_wrapper ? index_direct_or_wrapper : convertible_type<value_type, Types...>::index;
|
|
static constexpr bool is_valid = index != invalid_value;
|
|
static constexpr type_index_t tindex = is_valid ? sizeof...(Types)-index : 0;
|
|
using target_type = typename std::tuple_element<tindex, std::tuple<void, Types...>>::type;
|
|
};
|
|
|
|
template <typename Src, typename Dest>
|
|
struct copy_cvref
|
|
{
|
|
using type = Dest;
|
|
};
|
|
|
|
template <typename Src, typename Dest>
|
|
struct copy_cvref<Src const&, Dest>
|
|
{
|
|
using type = Dest const&;
|
|
};
|
|
|
|
template <typename Src, typename Dest>
|
|
struct copy_cvref<Src&, Dest>
|
|
{
|
|
using type = Dest&;
|
|
};
|
|
|
|
template <typename Src, typename Dest>
|
|
struct copy_cvref<Src&&, Dest>
|
|
{
|
|
using type = Dest&&;
|
|
};
|
|
|
|
template <typename F, typename = void>
|
|
struct deduced_result_type
|
|
{};
|
|
|
|
template <typename F, typename... Args>
|
|
struct deduced_result_type<F(Args...), decltype((void)std::declval<F>()(std::declval<Args>()...))>
|
|
{
|
|
using type = decltype(std::declval<F>()(std::declval<Args>()...));
|
|
};
|
|
|
|
template <typename F, typename = void>
|
|
struct visitor_result_type : deduced_result_type<F>
|
|
{};
|
|
|
|
// specialization for explicit result_type member in visitor class
|
|
template <typename F, typename... Args>
|
|
struct visitor_result_type<F(Args...), decltype((void)std::declval<typename std::decay<F>::type::result_type>())>
|
|
{
|
|
using type = typename std::decay<F>::type::result_type;
|
|
};
|
|
|
|
template <typename F, typename T>
|
|
using result_of_unary_visit = typename visitor_result_type<F&&(T&&)>::type;
|
|
|
|
template <typename F, typename T>
|
|
using result_of_binary_visit = typename visitor_result_type<F&&(T&&, T&&)>::type;
|
|
|
|
template <type_index_t arg1, type_index_t... others>
|
|
struct static_max;
|
|
|
|
template <type_index_t arg>
|
|
struct static_max<arg>
|
|
{
|
|
static const type_index_t value = arg;
|
|
};
|
|
|
|
template <type_index_t arg1, type_index_t arg2, type_index_t... others>
|
|
struct static_max<arg1, arg2, others...>
|
|
{
|
|
static const type_index_t value = arg1 >= arg2 ? static_max<arg1, others...>::value : static_max<arg2, others...>::value;
|
|
};
|
|
|
|
template <typename... Types>
|
|
struct variant_helper;
|
|
|
|
template <typename T, typename... Types>
|
|
struct variant_helper<T, Types...>
|
|
{
|
|
VARIANT_INLINE static void destroy(const type_index_t type_index, void* data)
|
|
{
|
|
if (type_index == sizeof...(Types))
|
|
{
|
|
reinterpret_cast<T*>(data)->~T();
|
|
}
|
|
else
|
|
{
|
|
variant_helper<Types...>::destroy(type_index, data);
|
|
}
|
|
}
|
|
|
|
VARIANT_INLINE static void move(const type_index_t old_type_index, void* old_value, void* new_value)
|
|
{
|
|
if (old_type_index == sizeof...(Types))
|
|
{
|
|
new (new_value) T(std::move(*reinterpret_cast<T*>(old_value)));
|
|
}
|
|
else
|
|
{
|
|
variant_helper<Types...>::move(old_type_index, old_value, new_value);
|
|
}
|
|
}
|
|
|
|
VARIANT_INLINE static void copy(const type_index_t old_type_index, const void* old_value, void* new_value)
|
|
{
|
|
if (old_type_index == sizeof...(Types))
|
|
{
|
|
new (new_value) T(*reinterpret_cast<const T*>(old_value));
|
|
}
|
|
else
|
|
{
|
|
variant_helper<Types...>::copy(old_type_index, old_value, new_value);
|
|
}
|
|
}
|
|
};
|
|
|
|
template <>
|
|
struct variant_helper<>
|
|
{
|
|
VARIANT_INLINE static void destroy(const type_index_t, void*) {}
|
|
VARIANT_INLINE static void move(const type_index_t, void*, void*) {}
|
|
VARIANT_INLINE static void copy(const type_index_t, const void*, void*) {}
|
|
};
|
|
|
|
template <typename T>
|
|
struct unwrapper
|
|
{
|
|
using value_type = T;
|
|
|
|
template <typename V>
|
|
static auto apply(typename std::remove_reference<V>::type& var)
|
|
-> typename std::enable_if<std::is_lvalue_reference<V>::value,
|
|
decltype(var.template get_unchecked<T>())>::type
|
|
{
|
|
return var.template get_unchecked<T>();
|
|
}
|
|
|
|
template <typename V>
|
|
static auto apply(typename std::remove_reference<V>::type& var)
|
|
-> typename std::enable_if<!std::is_lvalue_reference<V>::value,
|
|
decltype(std::move(var.template get_unchecked<T>()))>::type
|
|
{
|
|
return std::move(var.template get_unchecked<T>());
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
struct unwrapper<recursive_wrapper<T>> : unwrapper<T>
|
|
{};
|
|
|
|
template <typename T>
|
|
struct unwrapper<std::reference_wrapper<T>> : unwrapper<T>
|
|
{};
|
|
|
|
template <typename R, typename... Types>
|
|
struct dispatcher;
|
|
|
|
template <typename R, typename T, typename... Types>
|
|
struct dispatcher<R, T, Types...>
|
|
{
|
|
template <typename V, typename F>
|
|
VARIANT_INLINE static R apply(V&& v, F&& f)
|
|
{
|
|
if (v.template is<T>())
|
|
{
|
|
return std::forward<F>(f)(unwrapper<T>::template apply<V>(v));
|
|
}
|
|
else
|
|
{
|
|
return dispatcher<R, Types...>::apply(std::forward<V>(v), std::forward<F>(f));
|
|
}
|
|
}
|
|
};
|
|
|
|
template <typename R, typename T>
|
|
struct dispatcher<R, T>
|
|
{
|
|
template <typename V, typename F>
|
|
VARIANT_INLINE static R apply(V&& v, F&& f)
|
|
{
|
|
return std::forward<F>(f)(unwrapper<T>::template apply<V>(v));
|
|
}
|
|
};
|
|
|
|
template <typename R, typename T, typename... Types>
|
|
struct binary_dispatcher_rhs;
|
|
|
|
template <typename R, typename T0, typename T1, typename... Types>
|
|
struct binary_dispatcher_rhs<R, T0, T1, Types...>
|
|
{
|
|
template <typename V, typename F>
|
|
VARIANT_INLINE static R apply(V&& lhs, V&& rhs, F&& f)
|
|
{
|
|
if (rhs.template is<T1>()) // call binary functor
|
|
{
|
|
return std::forward<F>(f)(unwrapper<T0>::template apply<V>(lhs),
|
|
unwrapper<T1>::template apply<V>(rhs));
|
|
}
|
|
else
|
|
{
|
|
return binary_dispatcher_rhs<R, T0, Types...>::apply(std::forward<V>(lhs),
|
|
std::forward<V>(rhs),
|
|
std::forward<F>(f));
|
|
}
|
|
}
|
|
};
|
|
|
|
template <typename R, typename T0, typename T1>
|
|
struct binary_dispatcher_rhs<R, T0, T1>
|
|
{
|
|
template <typename V, typename F>
|
|
VARIANT_INLINE static R apply(V&& lhs, V&& rhs, F&& f)
|
|
{
|
|
return std::forward<F>(f)(unwrapper<T0>::template apply<V>(lhs),
|
|
unwrapper<T1>::template apply<V>(rhs));
|
|
}
|
|
};
|
|
|
|
template <typename R, typename T, typename... Types>
|
|
struct binary_dispatcher_lhs;
|
|
|
|
template <typename R, typename T0, typename T1, typename... Types>
|
|
struct binary_dispatcher_lhs<R, T0, T1, Types...>
|
|
{
|
|
template <typename V, typename F>
|
|
VARIANT_INLINE static R apply(V&& lhs, V&& rhs, F&& f)
|
|
{
|
|
if (lhs.template is<T1>()) // call binary functor
|
|
{
|
|
return std::forward<F>(f)(unwrapper<T1>::template apply<V>(lhs),
|
|
unwrapper<T0>::template apply<V>(rhs));
|
|
}
|
|
else
|
|
{
|
|
return binary_dispatcher_lhs<R, T0, Types...>::apply(std::forward<V>(lhs),
|
|
std::forward<V>(rhs),
|
|
std::forward<F>(f));
|
|
}
|
|
}
|
|
};
|
|
|
|
template <typename R, typename T0, typename T1>
|
|
struct binary_dispatcher_lhs<R, T0, T1>
|
|
{
|
|
template <typename V, typename F>
|
|
VARIANT_INLINE static R apply(V&& lhs, V&& rhs, F&& f)
|
|
{
|
|
return std::forward<F>(f)(unwrapper<T1>::template apply<V>(lhs),
|
|
unwrapper<T0>::template apply<V>(rhs));
|
|
}
|
|
};
|
|
|
|
template <typename R, typename... Types>
|
|
struct binary_dispatcher;
|
|
|
|
template <typename R, typename T, typename... Types>
|
|
struct binary_dispatcher<R, T, Types...>
|
|
{
|
|
template <typename V, typename F>
|
|
VARIANT_INLINE static R apply(V&& v0, V&& v1, F&& f)
|
|
{
|
|
if (v0.template is<T>())
|
|
{
|
|
if (v1.template is<T>())
|
|
{
|
|
return std::forward<F>(f)(unwrapper<T>::template apply<V>(v0),
|
|
unwrapper<T>::template apply<V>(v1)); // call binary functor
|
|
}
|
|
else
|
|
{
|
|
return binary_dispatcher_rhs<R, T, Types...>::apply(std::forward<V>(v0),
|
|
std::forward<V>(v1),
|
|
std::forward<F>(f));
|
|
}
|
|
}
|
|
else if (v1.template is<T>())
|
|
{
|
|
return binary_dispatcher_lhs<R, T, Types...>::apply(std::forward<V>(v0),
|
|
std::forward<V>(v1),
|
|
std::forward<F>(f));
|
|
}
|
|
return binary_dispatcher<R, Types...>::apply(std::forward<V>(v0),
|
|
std::forward<V>(v1),
|
|
std::forward<F>(f));
|
|
}
|
|
};
|
|
|
|
template <typename R, typename T>
|
|
struct binary_dispatcher<R, T>
|
|
{
|
|
template <typename V, typename F>
|
|
VARIANT_INLINE static R apply(V&& v0, V&& v1, F&& f)
|
|
{
|
|
return std::forward<F>(f)(unwrapper<T>::template apply<V>(v0),
|
|
unwrapper<T>::template apply<V>(v1)); // call binary functor
|
|
}
|
|
};
|
|
|
|
// comparator functors
|
|
struct equal_comp
|
|
{
|
|
template <typename T>
|
|
bool operator()(T const& lhs, T const& rhs) const
|
|
{
|
|
return lhs == rhs;
|
|
}
|
|
};
|
|
|
|
struct less_comp
|
|
{
|
|
template <typename T>
|
|
bool operator()(T const& lhs, T const& rhs) const
|
|
{
|
|
return lhs < rhs;
|
|
}
|
|
};
|
|
|
|
template <typename Variant, typename Comp>
|
|
class comparer
|
|
{
|
|
public:
|
|
explicit comparer(Variant const& lhs) noexcept
|
|
: lhs_(lhs) {}
|
|
comparer& operator=(comparer const&) = delete;
|
|
// visitor
|
|
template <typename T>
|
|
bool operator()(T const& rhs_content) const
|
|
{
|
|
T const& lhs_content = lhs_.template get_unchecked<T>();
|
|
return Comp()(lhs_content, rhs_content);
|
|
}
|
|
|
|
private:
|
|
Variant const& lhs_;
|
|
};
|
|
|
|
// hashing visitor
|
|
struct hasher
|
|
{
|
|
template <typename T>
|
|
std::size_t operator()(const T& hashable) const
|
|
{
|
|
return std::hash<T>{}(hashable);
|
|
}
|
|
};
|
|
|
|
} // namespace detail
|
|
|
|
struct no_init {};
|
|
|
|
template <typename... Types>
|
|
class variant
|
|
{
|
|
static_assert(sizeof...(Types) > 0, "Template parameter type list of variant can not be empty.");
|
|
static_assert(!detail::disjunction<std::is_reference<Types>...>::value, "Variant can not hold reference types. Maybe use std::reference_wrapper?");
|
|
static_assert(!detail::disjunction<std::is_array<Types>...>::value, "Variant can not hold array types.");
|
|
static_assert(sizeof...(Types) < std::numeric_limits<type_index_t>::max(), "Internal index type must be able to accommodate all alternatives.");
|
|
private:
|
|
static const std::size_t data_size = detail::static_max<sizeof(Types)...>::value;
|
|
static const std::size_t data_align = detail::static_max<alignof(Types)...>::value;
|
|
public:
|
|
struct adapted_variant_tag;
|
|
using types = std::tuple<Types...>;
|
|
private:
|
|
using first_type = typename std::tuple_element<0, types>::type;
|
|
using unwrap_first_type = typename detail::unwrapper<first_type>::value_type;
|
|
using data_type = typename std::aligned_storage<data_size, data_align>::type;
|
|
using helper_type = detail::variant_helper<Types...>;
|
|
|
|
template <typename V, typename T = unwrap_first_type>
|
|
using alternative_ref = typename detail::copy_cvref<V, T>::type;
|
|
|
|
type_index_t type_index;
|
|
#ifdef __clang_analyzer__
|
|
data_type data {};
|
|
#else
|
|
data_type data;
|
|
#endif
|
|
|
|
public:
|
|
VARIANT_INLINE variant() noexcept(std::is_nothrow_default_constructible<first_type>::value)
|
|
: type_index(sizeof...(Types)-1)
|
|
{
|
|
static_assert(std::is_default_constructible<first_type>::value, "First type in variant must be default constructible to allow default construction of variant.");
|
|
new (&data) first_type();
|
|
}
|
|
|
|
VARIANT_INLINE variant(no_init) noexcept
|
|
: type_index(detail::invalid_value) {}
|
|
|
|
// http://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers
|
|
template <typename T, typename Traits = detail::value_traits<T, Types...>,
|
|
typename Enable = typename std::enable_if<Traits::is_valid && !std::is_same<variant<Types...>, typename Traits::value_type>::value>::type >
|
|
VARIANT_INLINE variant(T&& val) noexcept(std::is_nothrow_constructible<typename Traits::target_type, T&&>::value)
|
|
: type_index(Traits::index)
|
|
{
|
|
new (&data) typename Traits::target_type(std::forward<T>(val));
|
|
}
|
|
|
|
VARIANT_INLINE variant(variant<Types...> const& old)
|
|
: type_index(old.type_index)
|
|
{
|
|
helper_type::copy(old.type_index, &old.data, &data);
|
|
}
|
|
|
|
VARIANT_INLINE variant(variant<Types...>&& old)
|
|
noexcept(detail::conjunction<std::is_nothrow_move_constructible<Types>...>::value)
|
|
: type_index(old.type_index)
|
|
{
|
|
helper_type::move(old.type_index, &old.data, &data);
|
|
}
|
|
|
|
private:
|
|
VARIANT_INLINE void copy_assign(variant<Types...> const& rhs)
|
|
{
|
|
helper_type::destroy(type_index, &data);
|
|
type_index = detail::invalid_value;
|
|
helper_type::copy(rhs.type_index, &rhs.data, &data);
|
|
type_index = rhs.type_index;
|
|
}
|
|
|
|
VARIANT_INLINE void move_assign(variant<Types...>&& rhs)
|
|
{
|
|
helper_type::destroy(type_index, &data);
|
|
type_index = detail::invalid_value;
|
|
helper_type::move(rhs.type_index, &rhs.data, &data);
|
|
type_index = rhs.type_index;
|
|
}
|
|
|
|
public:
|
|
VARIANT_INLINE variant<Types...>& operator=(variant<Types...>&& other)
|
|
// note we check for nothrow-constructible, not nothrow-assignable, since
|
|
// move_assign uses move-construction via placement new.
|
|
noexcept(detail::conjunction<std::is_nothrow_move_constructible<Types>...>::value)
|
|
{
|
|
if (this == &other) { // playing safe in release mode, hit assertion in debug.
|
|
assert(false);
|
|
return *this;
|
|
}
|
|
move_assign(std::move(other));
|
|
return *this;
|
|
}
|
|
|
|
VARIANT_INLINE variant<Types...>& operator=(variant<Types...> const& other)
|
|
{
|
|
if (this != &other)
|
|
copy_assign(other);
|
|
return *this;
|
|
}
|
|
|
|
// conversions
|
|
// move-assign
|
|
template <typename T, typename Traits = detail::value_traits<T, Types...>,
|
|
typename Enable = typename std::enable_if<Traits::is_valid && !std::is_same<variant<Types...>, typename Traits::value_type>::value>::type >
|
|
VARIANT_INLINE variant<Types...>& operator=(T&& rhs)
|
|
// not that we check is_nothrow_constructible<T>, not is_nothrow_move_assignable<T>,
|
|
// since we construct a temporary
|
|
noexcept(std::is_nothrow_constructible<typename Traits::target_type, T&&>::value
|
|
&& std::is_nothrow_move_assignable<variant<Types...>>::value)
|
|
{
|
|
variant<Types...> temp(std::forward<T>(rhs));
|
|
move_assign(std::move(temp));
|
|
return *this;
|
|
}
|
|
|
|
// copy-assign
|
|
template <typename T>
|
|
VARIANT_INLINE variant<Types...>& operator=(T const& rhs)
|
|
{
|
|
variant<Types...> temp(rhs);
|
|
copy_assign(temp);
|
|
return *this;
|
|
}
|
|
|
|
template <typename T, typename std::enable_if<
|
|
(detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
|
VARIANT_INLINE bool is() const
|
|
{
|
|
return type_index == detail::direct_type<T, Types...>::index;
|
|
}
|
|
|
|
template <typename T,typename std::enable_if<
|
|
(detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
|
VARIANT_INLINE bool is() const
|
|
{
|
|
return type_index == detail::direct_type<recursive_wrapper<T>, Types...>::index;
|
|
}
|
|
|
|
VARIANT_INLINE bool valid() const
|
|
{
|
|
return type_index != detail::invalid_value;
|
|
}
|
|
|
|
template <typename T, typename... Args>
|
|
VARIANT_INLINE void set(Args&&... args)
|
|
{
|
|
helper_type::destroy(type_index, &data);
|
|
type_index = detail::invalid_value;
|
|
new (&data) T(std::forward<Args>(args)...);
|
|
type_index = detail::direct_type<T, Types...>::index;
|
|
}
|
|
|
|
// get_unchecked<T>()
|
|
template <typename T, typename std::enable_if<
|
|
(detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
|
VARIANT_INLINE T& get_unchecked()
|
|
{
|
|
return *reinterpret_cast<T*>(&data);
|
|
}
|
|
|
|
#ifdef HAS_EXCEPTIONS
|
|
// get<T>()
|
|
template <typename T, typename std::enable_if<
|
|
(detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
|
VARIANT_INLINE T& get()
|
|
{
|
|
if (type_index == detail::direct_type<T, Types...>::index)
|
|
{
|
|
return *reinterpret_cast<T*>(&data);
|
|
}
|
|
else
|
|
{
|
|
throw bad_variant_access("in get<T>()");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
template <typename T, typename std::enable_if<
|
|
(detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
|
VARIANT_INLINE T const& get_unchecked() const
|
|
{
|
|
return *reinterpret_cast<T const*>(&data);
|
|
}
|
|
|
|
#ifdef HAS_EXCEPTIONS
|
|
template <typename T, typename std::enable_if<
|
|
(detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
|
VARIANT_INLINE T const& get() const
|
|
{
|
|
if (type_index == detail::direct_type<T, Types...>::index)
|
|
{
|
|
return *reinterpret_cast<T const*>(&data);
|
|
}
|
|
else
|
|
{
|
|
throw bad_variant_access("in get<T>()");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// get_unchecked<T>() - T stored as recursive_wrapper<T>
|
|
template <typename T, typename std::enable_if<
|
|
(detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
|
VARIANT_INLINE T& get_unchecked()
|
|
{
|
|
return (*reinterpret_cast<recursive_wrapper<T>*>(&data)).get();
|
|
}
|
|
|
|
#ifdef HAS_EXCEPTIONS
|
|
// get<T>() - T stored as recursive_wrapper<T>
|
|
template <typename T, typename std::enable_if<
|
|
(detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
|
VARIANT_INLINE T& get()
|
|
{
|
|
if (type_index == detail::direct_type<recursive_wrapper<T>, Types...>::index)
|
|
{
|
|
return (*reinterpret_cast<recursive_wrapper<T>*>(&data)).get();
|
|
}
|
|
else
|
|
{
|
|
throw bad_variant_access("in get<T>()");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
template <typename T, typename std::enable_if<
|
|
(detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
|
VARIANT_INLINE T const& get_unchecked() const
|
|
{
|
|
return (*reinterpret_cast<recursive_wrapper<T> const*>(&data)).get();
|
|
}
|
|
|
|
#ifdef HAS_EXCEPTIONS
|
|
template <typename T, typename std::enable_if<
|
|
(detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
|
VARIANT_INLINE T const& get() const
|
|
{
|
|
if (type_index == detail::direct_type<recursive_wrapper<T>, Types...>::index)
|
|
{
|
|
return (*reinterpret_cast<recursive_wrapper<T> const*>(&data)).get();
|
|
}
|
|
else
|
|
{
|
|
throw bad_variant_access("in get<T>()");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// get_unchecked<T>() - T stored as std::reference_wrapper<T>
|
|
template <typename T, typename std::enable_if<
|
|
(detail::direct_type<std::reference_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
|
VARIANT_INLINE T& get_unchecked()
|
|
{
|
|
return (*reinterpret_cast<std::reference_wrapper<T>*>(&data)).get();
|
|
}
|
|
|
|
#ifdef HAS_EXCEPTIONS
|
|
// get<T>() - T stored as std::reference_wrapper<T>
|
|
template <typename T, typename std::enable_if<
|
|
(detail::direct_type<std::reference_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
|
VARIANT_INLINE T& get()
|
|
{
|
|
if (type_index == detail::direct_type<std::reference_wrapper<T>, Types...>::index)
|
|
{
|
|
return (*reinterpret_cast<std::reference_wrapper<T>*>(&data)).get();
|
|
}
|
|
else
|
|
{
|
|
throw bad_variant_access("in get<T>()");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
template <typename T, typename std::enable_if<
|
|
(detail::direct_type<std::reference_wrapper<T const>, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
|
VARIANT_INLINE T const& get_unchecked() const
|
|
{
|
|
return (*reinterpret_cast<std::reference_wrapper<T const> const*>(&data)).get();
|
|
}
|
|
|
|
#ifdef HAS_EXCEPTIONS
|
|
template <typename T, typename std::enable_if<
|
|
(detail::direct_type<std::reference_wrapper<T const>, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
|
VARIANT_INLINE T const& get() const
|
|
{
|
|
if (type_index == detail::direct_type<std::reference_wrapper<T const>, Types...>::index)
|
|
{
|
|
return (*reinterpret_cast<std::reference_wrapper<T const> const*>(&data)).get();
|
|
}
|
|
else
|
|
{
|
|
throw bad_variant_access("in get<T>()");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// This function is deprecated because it returns an internal index field.
|
|
// Use which() instead.
|
|
MAPBOX_VARIANT_DEPRECATED VARIANT_INLINE type_index_t get_type_index() const
|
|
{
|
|
return type_index;
|
|
}
|
|
|
|
VARIANT_INLINE int which() const noexcept
|
|
{
|
|
return static_cast<int>(sizeof...(Types) - type_index - 1);
|
|
}
|
|
|
|
template <typename T, typename std::enable_if<
|
|
(detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
|
VARIANT_INLINE static constexpr int which() noexcept
|
|
{
|
|
return static_cast<int>(sizeof...(Types)-detail::direct_type<T, Types...>::index - 1);
|
|
}
|
|
|
|
// visitor
|
|
// unary
|
|
template <typename F, typename V, typename T0 = alternative_ref<V>,
|
|
typename R = detail::result_of_unary_visit<F, T0>>
|
|
VARIANT_INLINE static R visit(V&& v, F&& f)
|
|
{
|
|
return detail::dispatcher<R, Types...>::apply(std::forward<V>(v), std::forward<F>(f));
|
|
}
|
|
|
|
// binary
|
|
template <typename F, typename V, typename T0 = alternative_ref<V>,
|
|
typename R = detail::result_of_binary_visit<F, T0>>
|
|
VARIANT_INLINE static R binary_visit(V&& v0, V&& v1, F&& f)
|
|
{
|
|
return detail::binary_dispatcher<R, Types...>::apply(std::forward<V>(v0),
|
|
std::forward<V>(v1),
|
|
std::forward<F>(f));
|
|
}
|
|
|
|
// match
|
|
// unary
|
|
template <typename... Fs>
|
|
auto VARIANT_INLINE match(Fs&&... fs) const&
|
|
-> decltype(variant::visit(*this, ::mapbox::util::make_visitor(std::forward<Fs>(fs)...)))
|
|
{
|
|
return variant::visit(*this, ::mapbox::util::make_visitor(std::forward<Fs>(fs)...));
|
|
}
|
|
// non-const
|
|
template <typename... Fs>
|
|
auto VARIANT_INLINE match(Fs&&... fs) &
|
|
-> decltype(variant::visit(*this, ::mapbox::util::make_visitor(std::forward<Fs>(fs)...)))
|
|
{
|
|
return variant::visit(*this, ::mapbox::util::make_visitor(std::forward<Fs>(fs)...));
|
|
}
|
|
template <typename... Fs>
|
|
auto VARIANT_INLINE match(Fs&&... fs) &&
|
|
-> decltype(variant::visit(std::move(*this), ::mapbox::util::make_visitor(std::forward<Fs>(fs)...)))
|
|
{
|
|
return variant::visit(std::move(*this), ::mapbox::util::make_visitor(std::forward<Fs>(fs)...));
|
|
}
|
|
|
|
~variant() noexcept // no-throw destructor
|
|
{
|
|
helper_type::destroy(type_index, &data);
|
|
}
|
|
|
|
// comparison operators
|
|
// equality
|
|
VARIANT_INLINE bool operator==(variant const& rhs) const
|
|
{
|
|
assert(valid() && rhs.valid());
|
|
if (this->which() != rhs.which())
|
|
{
|
|
return false;
|
|
}
|
|
detail::comparer<variant, detail::equal_comp> visitor(*this);
|
|
return visit(rhs, visitor);
|
|
}
|
|
|
|
VARIANT_INLINE bool operator!=(variant const& rhs) const
|
|
{
|
|
return !(*this == rhs);
|
|
}
|
|
|
|
// less than
|
|
VARIANT_INLINE bool operator<(variant const& rhs) const
|
|
{
|
|
assert(valid() && rhs.valid());
|
|
if (this->which() != rhs.which())
|
|
{
|
|
return this->which() < rhs.which();
|
|
}
|
|
detail::comparer<variant, detail::less_comp> visitor(*this);
|
|
return visit(rhs, visitor);
|
|
}
|
|
VARIANT_INLINE bool operator>(variant const& rhs) const
|
|
{
|
|
return rhs < *this;
|
|
}
|
|
VARIANT_INLINE bool operator<=(variant const& rhs) const
|
|
{
|
|
return !(*this > rhs);
|
|
}
|
|
VARIANT_INLINE bool operator>=(variant const& rhs) const
|
|
{
|
|
return !(*this < rhs);
|
|
}
|
|
};
|
|
|
|
// unary visitor interface
|
|
template <typename F, typename V>
|
|
auto VARIANT_INLINE apply_visitor(F&& f, V&& v)
|
|
-> decltype(v.visit(std::forward<V>(v), std::forward<F>(f)))
|
|
{
|
|
return v.visit(std::forward<V>(v), std::forward<F>(f));
|
|
}
|
|
|
|
// binary visitor interface
|
|
template <typename F, typename V>
|
|
auto VARIANT_INLINE apply_visitor(F&& f, V&& v0, V&& v1)
|
|
-> decltype(v0.binary_visit(std::forward<V>(v0), std::forward<V>(v1), std::forward<F>(f)))
|
|
{
|
|
return v0.binary_visit(std::forward<V>(v0), std::forward<V>(v1), std::forward<F>(f));
|
|
}
|
|
|
|
// getter interface
|
|
|
|
#ifdef HAS_EXCEPTIONS
|
|
template <typename ResultType, typename T>
|
|
auto get(T& var)->decltype(var.template get<ResultType>())
|
|
{
|
|
return var.template get<ResultType>();
|
|
}
|
|
#endif
|
|
|
|
template <typename ResultType, typename T>
|
|
ResultType& get_unchecked(T& var)
|
|
{
|
|
return var.template get_unchecked<ResultType>();
|
|
}
|
|
|
|
#ifdef HAS_EXCEPTIONS
|
|
template <typename ResultType, typename T>
|
|
auto get(T const& var)->decltype(var.template get<ResultType>())
|
|
{
|
|
return var.template get<ResultType>();
|
|
}
|
|
#endif
|
|
|
|
template <typename ResultType, typename T>
|
|
ResultType const& get_unchecked(T const& var)
|
|
{
|
|
return var.template get_unchecked<ResultType>();
|
|
}
|
|
// variant_size
|
|
template <typename T>
|
|
struct variant_size;
|
|
|
|
//variable templates is c++14
|
|
//template <typename T>
|
|
//constexpr std::size_t variant_size_v = variant_size<T>::value;
|
|
|
|
template <typename T>
|
|
struct variant_size<const T>
|
|
: variant_size<T> {};
|
|
|
|
template <typename T>
|
|
struct variant_size<volatile T>
|
|
: variant_size<T> {};
|
|
|
|
template <typename T>
|
|
struct variant_size<const volatile T>
|
|
: variant_size<T> {};
|
|
|
|
template <typename... Types>
|
|
struct variant_size<variant<Types...>>
|
|
: std::integral_constant<std::size_t, sizeof...(Types)> {};
|
|
|
|
// variant_alternative
|
|
template <std::size_t Index, typename T>
|
|
struct variant_alternative;
|
|
|
|
#if defined(__clang__)
|
|
#if __has_builtin(__type_pack_element)
|
|
#define has_type_pack_element
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(has_type_pack_element)
|
|
template <std::size_t Index, typename ...Types>
|
|
struct variant_alternative<Index, variant<Types...>>
|
|
{
|
|
static_assert(sizeof...(Types) > Index , "Index out of range");
|
|
using type = __type_pack_element<Index, Types...>;
|
|
};
|
|
#else
|
|
template <std::size_t Index, typename First, typename...Types>
|
|
struct variant_alternative<Index, variant<First, Types...>>
|
|
: variant_alternative<Index - 1, variant<Types...>>
|
|
{
|
|
static_assert(sizeof...(Types) > Index -1 , "Index out of range");
|
|
};
|
|
|
|
template <typename First, typename...Types>
|
|
struct variant_alternative<0, variant<First, Types...>>
|
|
{
|
|
using type = First;
|
|
};
|
|
|
|
#endif
|
|
|
|
template <size_t Index, typename T>
|
|
using variant_alternative_t = typename variant_alternative<Index, T>::type;
|
|
|
|
template <size_t Index, typename T>
|
|
struct variant_alternative<Index, const T>
|
|
: std::add_const<variant_alternative<Index, T>> {};
|
|
|
|
template <size_t Index, typename T>
|
|
struct variant_alternative<Index, volatile T>
|
|
: std::add_volatile<variant_alternative<Index, T>> {};
|
|
|
|
template <size_t Index, typename T>
|
|
struct variant_alternative<Index, const volatile T>
|
|
: std::add_cv<variant_alternative<Index, T>> {};
|
|
|
|
} // namespace util
|
|
} // namespace mapbox
|
|
|
|
// hashable iff underlying types are hashable
|
|
namespace std {
|
|
template <typename... Types>
|
|
struct hash< ::mapbox::util::variant<Types...>> {
|
|
std::size_t operator()(const ::mapbox::util::variant<Types...>& v) const noexcept
|
|
{
|
|
return ::mapbox::util::apply_visitor(::mapbox::util::detail::hasher{}, v);
|
|
}
|
|
};
|
|
|
|
}
|
|
|
|
#endif // MAPBOX_UTIL_VARIANT_HPP
|