|
|
@@ -11,191 +11,165 @@
|
|
|
#pragma once
|
|
|
|
|
|
#include <cstdlib>
|
|
|
-#include <utility>
|
|
|
#include <memory>
|
|
|
+#include <utility>
|
|
|
|
|
|
// Max of a list of values
|
|
|
template <size_t T, size_t... Ts> struct static_max;
|
|
|
|
|
|
-template <size_t T>
|
|
|
-struct static_max<T> {
|
|
|
+template <size_t T> struct static_max<T> {
|
|
|
static const constexpr size_t value = T;
|
|
|
};
|
|
|
|
|
|
-template <size_t T1, size_t T2, size_t... Ts>
|
|
|
-struct static_max<T1, T2, Ts...> {
|
|
|
- static const constexpr size_t value = T1 > T2 ? static_max<T1, Ts...>::value : static_max<T2, Ts...>::value;
|
|
|
+template <size_t T1, size_t T2, size_t... Ts> struct static_max<T1, T2, Ts...> {
|
|
|
+ static const constexpr size_t value =
|
|
|
+ T1 > T2 ? static_max<T1, Ts...>::value : static_max<T2, Ts...>::value;
|
|
|
};
|
|
|
|
|
|
// Type index in a list
|
|
|
template <typename F, typename... Ts> struct type_index;
|
|
|
|
|
|
-template <typename F>
|
|
|
-struct type_index<F> {};
|
|
|
+template <typename F> struct type_index<F> {};
|
|
|
|
|
|
template <typename F, typename T, typename... Ts>
|
|
|
struct type_index<F, T, Ts...> {
|
|
|
static const constexpr size_t value = type_index<F, Ts...>::value;
|
|
|
};
|
|
|
|
|
|
-template <typename F, typename... Ts>
|
|
|
-struct type_index<F, F, Ts...> {
|
|
|
+template <typename F, typename... Ts> struct type_index<F, F, Ts...> {
|
|
|
static const constexpr size_t value = sizeof...(Ts);
|
|
|
};
|
|
|
|
|
|
template <typename... Ts> struct variant_helper;
|
|
|
|
|
|
-template<typename F, typename... Ts>
|
|
|
-struct variant_helper<F, Ts...> {
|
|
|
- inline static void destroy(size_t id, void * data)
|
|
|
- {
|
|
|
+template <typename F, typename... Ts> struct variant_helper<F, Ts...> {
|
|
|
+ inline static void destroy(size_t id, void * data) {
|
|
|
if (id == sizeof...(Ts))
|
|
|
- reinterpret_cast<F*>(data)->~F();
|
|
|
+ reinterpret_cast<F *>(data)->~F();
|
|
|
else
|
|
|
variant_helper<Ts...>::destroy(id, data);
|
|
|
}
|
|
|
-
|
|
|
- inline static void move(size_t old_t, void * old_v, void * new_v)
|
|
|
- {
|
|
|
+
|
|
|
+ inline static void move(size_t old_t, void * old_v, void * new_v) {
|
|
|
if (old_t == sizeof...(Ts))
|
|
|
- new (new_v) F(std::move(*reinterpret_cast<F*>(old_v)));
|
|
|
+ new (new_v) F(std::move(*reinterpret_cast<F *>(old_v)));
|
|
|
else
|
|
|
variant_helper<Ts...>::move(old_t, old_v, new_v);
|
|
|
}
|
|
|
-
|
|
|
- inline static void copy(size_t old_t, const void * old_v, void * new_v)
|
|
|
- {
|
|
|
+
|
|
|
+ inline static void copy(size_t old_t, const void * old_v, void * new_v) {
|
|
|
if (old_t == sizeof...(Ts))
|
|
|
- new (new_v) F(*reinterpret_cast<const F*>(old_v));
|
|
|
+ new (new_v) F(*reinterpret_cast<const F *>(old_v));
|
|
|
else
|
|
|
variant_helper<Ts...>::copy(old_t, old_v, new_v);
|
|
|
- }
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
-template<> struct variant_helper<> {
|
|
|
- inline static void destroy(size_t, void *) { }
|
|
|
- inline static void move(size_t, void *, void *) { }
|
|
|
- inline static void copy(size_t, const void *, void *) { }
|
|
|
+template <> struct variant_helper<> {
|
|
|
+ inline static void destroy(size_t, void *) {}
|
|
|
+ inline static void move(size_t, void *, void *) {}
|
|
|
+ inline static void copy(size_t, const void *, void *) {}
|
|
|
};
|
|
|
|
|
|
-template <typename... Ts>
|
|
|
-struct variant {
|
|
|
+template <typename... Ts> struct variant {
|
|
|
private:
|
|
|
static const constexpr size_t num_types = sizeof...(Ts);
|
|
|
static const constexpr size_t data_size = static_max<sizeof(Ts)...>::value;
|
|
|
static const constexpr size_t data_align = static_max<alignof(Ts)...>::value;
|
|
|
-
|
|
|
+
|
|
|
using data_t = typename std::aligned_storage<data_size, data_align>::type;
|
|
|
-
|
|
|
+
|
|
|
using helper_t = variant_helper<Ts...>;
|
|
|
-
|
|
|
- static inline size_t invalid_type() {
|
|
|
- return 0xFFFFFFFF;
|
|
|
- }
|
|
|
-
|
|
|
- template <typename T>
|
|
|
- static inline size_t get_type_index() {
|
|
|
+
|
|
|
+ static inline size_t invalid_type() { return 0xFFFFFFFF; }
|
|
|
+
|
|
|
+ template <typename T> static inline size_t get_type_index() {
|
|
|
return num_types - type_index<T, Ts...>::value - 1;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
size_t type_id;
|
|
|
data_t data;
|
|
|
+
|
|
|
public:
|
|
|
template <size_t I>
|
|
|
using at = typename std::tuple_element<I, std::tuple<Ts...>>::type;
|
|
|
-
|
|
|
- variant() : type_id(invalid_type()), data() { }
|
|
|
-
|
|
|
+
|
|
|
+ variant() : type_id(invalid_type()), data() {}
|
|
|
+
|
|
|
template <typename T>
|
|
|
variant(T const & value) : type_id(invalid_type()), data() {
|
|
|
set<T>(value);
|
|
|
}
|
|
|
-
|
|
|
- variant(const variant<Ts...>& old) : type_id(old.type_id), data() {
|
|
|
+
|
|
|
+ variant(const variant<Ts...> & old) : type_id(old.type_id), data() {
|
|
|
helper_t::copy(num_types - type_id - 1, &old.data, &data);
|
|
|
}
|
|
|
-
|
|
|
- variant(variant&& old) : type_id(old.type_id), data() {
|
|
|
+
|
|
|
+ variant(variant && old) : type_id(old.type_id), data() {
|
|
|
helper_t::move(num_types - type_id - 1, &old.data, &data);
|
|
|
old.type_id = invalid_type();
|
|
|
}
|
|
|
-
|
|
|
- variant& operator=(variant const & old) {
|
|
|
+
|
|
|
+ variant & operator=(variant const & old) {
|
|
|
helper_t::destroy(num_types - type_id - 1, &data);
|
|
|
type_id = old.type_id;
|
|
|
helper_t::copy(num_types - type_id - 1, &old.data, &data);
|
|
|
return *this;
|
|
|
}
|
|
|
|
|
|
- variant& operator=(variant&& old) {
|
|
|
+ variant & operator=(variant && old) {
|
|
|
helper_t::destroy(num_types - type_id - 1, &data);
|
|
|
type_id = old.type_id;
|
|
|
helper_t::move(num_types - type_id - 1, &old.data, &data);
|
|
|
old.type_id = invalid_type();
|
|
|
return *this;
|
|
|
}
|
|
|
-
|
|
|
- template<typename T>
|
|
|
- inline bool is() const {
|
|
|
+
|
|
|
+ template <typename T> inline bool is() const {
|
|
|
return (type_id == get_type_index<T>());
|
|
|
}
|
|
|
-
|
|
|
- inline bool valid() const {
|
|
|
- return (type_id != invalid_type());
|
|
|
- }
|
|
|
-
|
|
|
- template<typename T, typename... Args>
|
|
|
- void set(Args&&... args)
|
|
|
- {
|
|
|
+
|
|
|
+ inline bool valid() const { return (type_id != invalid_type()); }
|
|
|
+
|
|
|
+ template <typename T, typename... Args> void set(Args &&... args) {
|
|
|
// First we destroy the current contents
|
|
|
helper_t::destroy(num_types - type_id - 1, &data);
|
|
|
new (&data) T(std::forward<Args>(args)...);
|
|
|
type_id = get_type_index<T>();
|
|
|
}
|
|
|
-
|
|
|
- template<typename T>
|
|
|
- T& get()
|
|
|
- {
|
|
|
+
|
|
|
+ template <typename T> T & get() {
|
|
|
// It is a dynamic_cast-like behaviour
|
|
|
if (is<T>())
|
|
|
- return *reinterpret_cast<T*>(&data);
|
|
|
+ return *reinterpret_cast<T *>(&data);
|
|
|
else
|
|
|
throw std::bad_cast();
|
|
|
}
|
|
|
-
|
|
|
- template<typename T>
|
|
|
- T const& get() const
|
|
|
- {
|
|
|
+
|
|
|
+ template <typename T> T const & get() const {
|
|
|
// It is a dynamic_cast-like behaviour
|
|
|
if (is<T>())
|
|
|
- return *reinterpret_cast<T const*>(&data);
|
|
|
+ return *reinterpret_cast<T const *>(&data);
|
|
|
else
|
|
|
throw std::bad_cast();
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
size_t index() const { return type_id; }
|
|
|
-
|
|
|
- template <size_t I>
|
|
|
- auto get() const -> at<I> const & {
|
|
|
- return get<at<I>>();
|
|
|
- }
|
|
|
|
|
|
- template <size_t I>
|
|
|
- auto get() -> at<I> & {
|
|
|
- return get<at<I>>();
|
|
|
- }
|
|
|
+ template <size_t I> auto get() const -> at<I> const & { return get<at<I>>(); }
|
|
|
|
|
|
- ~variant() {
|
|
|
- helper_t::destroy(num_types - type_id - 1, &data);
|
|
|
- }
|
|
|
+ template <size_t I> auto get() -> at<I> & { return get<at<I>>(); }
|
|
|
+
|
|
|
+ ~variant() { helper_t::destroy(num_types - type_id - 1, &data); }
|
|
|
};
|
|
|
|
|
|
namespace std {
|
|
|
template <size_t I, typename... Ts>
|
|
|
- auto get(variant<Ts...> const & var) -> typename variant<Ts...>::template at<I> const & {
|
|
|
+ auto get(variant<Ts...> const & var) ->
|
|
|
+ typename variant<Ts...>::template at<I> const & {
|
|
|
return var.template get<I>();
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
template <size_t I, typename... Ts>
|
|
|
auto get(variant<Ts...> & var) -> typename variant<Ts...>::template at<I> & {
|
|
|
return var.template get<I>();
|