| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162 |
- //
- // variant.hpp
- // variant
- //
- // Created by Sam Jaffe on 1/30/16.
- // Copyright © 2016 Sam Jaffe. All rights reserved.
- //
- #ifndef variant_h
- #define variant_h
- #pragma once
- #include <cstdlib>
- #include <utility>
- #include <memory>
- // Max of a list of values
- template <size_t T, size_t... Ts> struct static_max;
- 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;
- };
- // Type index in a list
- template <typename F, typename... Ts> struct type_index;
- 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...> {
- 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)
- {
- if (id == sizeof...(Ts))
- 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)
- {
- if (old_t == sizeof...(Ts))
- 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)
- {
- if (old_t == sizeof...(Ts))
- 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 id, void * data) { }
- inline static void move(size_t old_t, void * old_v, void * new_v) { }
- inline static void copy(size_t old_t, const void * old_v, void * new_v) { }
- };
- template <typename... Ts>
- struct variant {
- private:
- 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;
- }
-
- size_t type_id;
- data_t data;
- public:
- variant() : type_id(invalid_type()) { }
-
- variant(const variant<Ts...>& old) : type_id(old.type_id)
- {
- helper_t::copy(old.type_id, &old.data, &data);
- }
-
- variant(variant<Ts...>&& old) : type_id(old.type_id)
- {
- helper_t::move(old.type_id, &old.data, &data);
- }
-
- // Serves as both the move and the copy asignment operator.
- variant<Ts...>& operator= (variant<Ts...> old)
- {
- std::swap(type_id, old.type_id);
- std::swap(data, old.data);
-
- return *this;
- }
-
- template<typename T>
- bool is() const {
- return (type_id == type_index<T, Ts...>::value);
- }
-
- 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(type_id, &data);
- new (&data) T(std::forward<Args>(args)...);
- type_id = type_index<T, Ts...>::value;
- }
-
- template<typename T>
- T& get()
- {
- // It is a dynamic_cast-like behaviour
- if (type_id == type_index<T, Ts...>::value)
- return *reinterpret_cast<T*>(&data);
- else
- throw std::bad_cast();
- }
-
- template<typename T>
- T const& get() const
- {
- // It is a dynamic_cast-like behaviour
- if (type_id == type_index<T, Ts...>::value)
- return *reinterpret_cast<T const*>(&data);
- else
- throw std::bad_cast();
- }
-
- ~variant() {
- helper_t::destroy(type_id, &data);
- }
- };
- #endif /* variant_h */
|