LCOV - code coverage report
Current view: top level - deps - variant.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 25 35 71.4 %
Date: 2020-10-15 20:26:03 Functions: 10 35 28.6 %

          Line data    Source code
       1             : // A c++11 variant class
       2             : // source: https://gist.github.com/S6066/f726a37b2b703efea7ee27103e5bec89
       3             : 
       4             : #ifndef variant_h
       5             : #define variant_h
       6             : 
       7             : #include <cassert>
       8             : #include <type_traits>
       9             : #include <utility>
      10             : 
      11             : template <typename...> struct IsOneOf { static constexpr bool value = false; };
      12             : 
      13             : template <typename T, typename S, typename... Ts> struct IsOneOf<T, S, Ts...> {
      14             :     static constexpr bool value = std::is_same<T, S>::value || IsOneOf<T, Ts...>::value;
      15             : };
      16             : 
      17             : #include <type_traits>
      18             : 
      19             : template <typename...> struct IndexOf;
      20             : 
      21             : // Found
      22             : template <class T, class... Rest>
      23             : struct IndexOf<T, T, Rest...> : std::integral_constant<std::size_t, 0u> {};
      24             : 
      25             : // Still searching
      26             : template <class T, class Other, class... Rest>
      27             : struct IndexOf<T, Other, Rest...>
      28             :     : std::integral_constant<std::size_t, 1 + IndexOf<T, Rest...>::value> {};
      29             : 
      30             : namespace Detail {
      31             : 
      32             : template <class... Ts> struct VariantHelper;
      33             : 
      34             : template <class Union, class T, class... Ts> struct VariantHelper<Union, T, Ts...> {
      35             :     inline static void destroy(std::size_t index, Union* data);
      36             :     inline static void move(std::size_t index, Union* oldValue, Union* newValue);
      37             :     inline static void copy(std::size_t index, const Union* oldValue, Union* new_v);
      38             : };
      39             : 
      40             : template <class Union> struct VariantHelper<Union> {
      41           0 :     inline static void destroy(std::size_t index, Union* data) {}
      42             :     inline static void move(std::size_t index, Union* oldValue, Union* newValue) {}
      43           0 :     inline static void copy(std::size_t index, const Union* oldValue, Union* newValue) {}
      44             : };
      45             : 
      46             : } // namespace Detail
      47             : 
      48             : template <class... Ts> class Variant {
      49             : public:
      50             :     static_assert(sizeof...(Ts) > 1, "Variant must have at least 2 different types");
      51             : 
      52             :     Variant() = default;
      53             : 
      54             :     template <class T, class... Args,
      55             :               class = typename std::enable_if<IsOneOf<T, Ts...>::value>::type>
      56           1 :     Variant(const T& t) {
      57           1 :         new (&m_data) T(t);
      58           1 :         m_index = IndexOf<T, void, Ts...>::value;
      59           1 :     }
      60             : 
      61             :     inline ~Variant();
      62             : 
      63             :     inline Variant(const Variant<Ts...>& other);
      64             :     inline Variant(Variant<Ts...>&& other);
      65             : 
      66             :     inline Variant<Ts...>& operator=(const Variant<Ts...>& other);
      67             :     inline Variant<Ts...>& operator=(Variant<Ts...>&& other);
      68             : 
      69             :     template <class T> inline bool is() const;
      70             : 
      71             :     inline bool valid() const;
      72             : 
      73             :     template <class T, class... Args,
      74             :               class = typename std::enable_if<IsOneOf<T, Ts...>::value>::type>
      75             :     inline void set(Args&&... args);
      76             : 
      77             :     template <class T, class = typename std::enable_if<IsOneOf<T, Ts...>::value>::type>
      78             :     inline const T& get() const;
      79             : 
      80             :     template <class T, class = typename std::enable_if<IsOneOf<T, Ts...>::value>::type>
      81             :     inline T& get();
      82             : 
      83             :     inline void reset();
      84             : 
      85             : private:
      86             :     using Data = typename std::aligned_union<0, Ts...>::type;
      87             :     using Helper = Detail::VariantHelper<Data, Ts...>;
      88             : 
      89             :     std::size_t m_index{};
      90             :     Data m_data;
      91             : };
      92             : 
      93             : namespace Detail {
      94             : 
      95             : template <class Union, class T, class... Ts>
      96           6 : void VariantHelper<Union, T, Ts...>::destroy(std::size_t index, Union* data) {
      97           6 :     if (index == 0u)
      98             :         reinterpret_cast<T*>(data)->~T();
      99             : 
     100             :     else {
     101           4 :         --index;
     102           4 :         VariantHelper<Union, Ts...>::destroy(index, data);
     103             :     }
     104           6 : }
     105             : 
     106             : template <class Union, class T, class... Ts>
     107             : void VariantHelper<Union, T, Ts...>::move(std::size_t index, Union* oldValue, Union* newValue) {
     108             :     if (index == 0u)
     109             :         new (newValue) T(std::move(*reinterpret_cast<T*>(oldValue)));
     110             : 
     111             :     else {
     112             :         --index;
     113             :         VariantHelper<Union, Ts...>::move(index, oldValue, newValue);
     114             :     }
     115             : }
     116             : 
     117             : template <class Union, class T, class... Ts>
     118           3 : void VariantHelper<Union, T, Ts...>::copy(std::size_t index, const Union* oldValue,
     119             :                                           Union* newValue) {
     120           3 :     if (index == 0u)
     121           1 :         new (newValue) T(*reinterpret_cast<const T*>(oldValue));
     122             : 
     123             :     else {
     124           2 :         --index;
     125           2 :         VariantHelper<Union, Ts...>::copy(index, oldValue, newValue);
     126             :     }
     127           3 : }
     128             : 
     129             : } // namespace Detail
     130             : 
     131           2 : template <class... Ts> Variant<Ts...>::~Variant() {
     132           2 :     if (valid())
     133           2 :         Helper::destroy(m_index - 1u, &m_data);
     134           2 : }
     135             : 
     136             : template <class... Ts>
     137           1 : Variant<Ts...>::Variant(const Variant<Ts...>& other) : m_index{other.m_index} {
     138           1 :     if (valid())
     139           1 :         Helper::copy(m_index - 1u, &other.m_data, &m_data);
     140           1 : }
     141             : 
     142             : template <class... Ts> Variant<Ts...>::Variant(Variant<Ts...>&& other) : m_index{other.m_index} {
     143             :     if (valid())
     144             :         Helper::move(m_index - 1u, &other.m_data, &m_data);
     145             : }
     146             : 
     147             : template <class... Ts> Variant<Ts...>& Variant<Ts...>::operator=(const Variant<Ts...>& other) {
     148             :     if (valid())
     149             :         Helper::destroy(m_index - 1u, &m_data);
     150             : 
     151             :     m_index = other.m_index;
     152             : 
     153             :     if (valid())
     154             :         Helper::copy(m_index - 1u, &other.m_data, &m_data);
     155             : 
     156             :     return *this;
     157             : }
     158             : 
     159             : template <class... Ts> Variant<Ts...>& Variant<Ts...>::operator=(Variant<Ts...>&& other) {
     160             :     if (valid())
     161             :         Helper::destroy(m_index - 1u, &m_data);
     162             : 
     163             :     m_index = other.m_index;
     164             : 
     165             :     if (valid())
     166             :         Helper::move(m_index - 1u, &other.m_data, &m_data);
     167             : 
     168             :     return *this;
     169             : }
     170             : 
     171           0 : template <class... Ts> template <class T> bool Variant<Ts...>::is() const {
     172           0 :     return m_index == IndexOf<T, void, Ts...>::value;
     173             : }
     174             : 
     175           3 : template <class... Ts> bool Variant<Ts...>::valid() const {
     176           3 :     return m_index != 0u; // void
     177             : }
     178             : 
     179             : template <class... Ts>
     180             : template <class T, class... Args, class>
     181             : void Variant<Ts...>::set(Args&&... args) {
     182             :     if (valid())
     183             :         Helper::destroy(m_index - 1u, &m_data);
     184             : 
     185             :     new (&m_data) T(std::forward<Args>(args)...);
     186             :     m_index = IndexOf<T, void, Ts...>::value;
     187             : }
     188             : 
     189           0 : template <class... Ts> template <class T, class> const T& Variant<Ts...>::get() const {
     190           0 :     assert(valid() && "Uninitialized variant !");
     191             : 
     192           0 :     if (m_index == IndexOf<T, void, Ts...>::value) {
     193           0 :         const T* ptr = reinterpret_cast<const T*>(&m_data);
     194           0 :         return *ptr;
     195             :     }
     196             : 
     197             :     else
     198           0 :         throw std::bad_cast{};
     199             : }
     200             : 
     201             : template <class... Ts> template <class T, class> T& Variant<Ts...>::get() {
     202             :     assert(valid() && "Uninitialized variant !");
     203             : 
     204             :     if (m_index == IndexOf<T, void, Ts...>::value) {
     205             :         T* ptr = reinterpret_cast<T*>(&m_data);
     206             :         return *ptr;
     207             :     }
     208             : 
     209             :     else
     210             :         throw std::bad_cast{};
     211             : }
     212             : 
     213             : template <class... Ts> void Variant<Ts...>::reset() {
     214             :     if (valid())
     215             :         Helper::destroy(m_index - 1u, &m_data);
     216             : 
     217             :     m_index = 0u;
     218             : }
     219             : 
     220             : template <class... Ts> using variant = Variant<Ts...>;
     221             : 
     222             : #endif /* variant_hpp */

Generated by: LCOV version 1.13