| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134 |
- //
- // variant.hpp
- // variant
- //
- // Created by Sam Jaffe on 1/30/16.
- // Copyright © 2016 Sam Jaffe. All rights reserved.
- //
- #pragma once
- #include <cstdlib>
- #include <memory>
- #include <utility>
- #include "detail/helper.hpp"
- #include "detail/types.hpp"
- namespace variant {
- template <typename... Ts> class variant {
- public:
- template <size_t I>
- using at = typename std::tuple_element<I, std::tuple<Ts...>>::type;
- private:
- static const constexpr size_t num_types = sizeof...(Ts);
- static const constexpr size_t data_size =
- detail::static_max<sizeof(Ts)...>::value;
- static const constexpr size_t data_align =
- detail::static_max<alignof(Ts)...>::value;
- using data_t = typename std::aligned_storage<data_size, data_align>::type;
- private:
- size_t type_id;
- data_t data;
- public:
- 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() {
- detail::helper<Ts...>::copy(num_types - type_id - 1, &old.data, &data);
- }
- variant(variant && old) : type_id(old.type_id), data() {
- detail::helper<Ts...>::move(num_types - type_id - 1, &old.data, &data);
- old.type_id = invalid_type();
- }
- variant & operator=(variant const & old) {
- detail::helper<Ts...>::destroy(num_types - type_id - 1, &data);
- type_id = old.type_id;
- detail::helper<Ts...>::copy(num_types - type_id - 1, &old.data, &data);
- return *this;
- }
- variant & operator=(variant && old) {
- detail::helper<Ts...>::destroy(num_types - type_id - 1, &data);
- type_id = old.type_id;
- detail::helper<Ts...>::move(num_types - type_id - 1, &old.data, &data);
- old.type_id = invalid_type();
- return *this;
- }
- ~variant() {
- detail::helper<Ts...>::destroy(num_types - type_id - 1, &data);
- }
- 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) {
- // First we destroy the current contents
- detail::helper<Ts...>::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() {
- // It is a dynamic_cast-like behaviour
- if (is<T>()) {
- 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 (is<T>()) {
- 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>>(); }
- private:
- static inline size_t invalid_type() { return 0xFFFFFFFF; }
- template <typename T> static inline size_t get_type_index() {
- return num_types - detail::type_index<T, Ts...>::value - 1;
- }
- };
- }
- namespace std {
- template <size_t I, typename... Ts>
- auto get(variant::variant<Ts...> const & var) ->
- typename variant::variant<Ts...>::template at<I> const & {
- return var.template get<I>();
- }
- template <size_t I, typename... Ts>
- auto get(variant::variant<Ts...> & var) ->
- typename variant::variant<Ts...>::template at<I> & {
- return var.template get<I>();
- }
- }
|