variant.hpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. //
  2. // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
  3. //
  4. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. // Official repository: https://github.com/boostorg/beast
  8. //
  9. #ifndef BOOST_BEAST_DETAIL_VARIANT_HPP
  10. #define BOOST_BEAST_DETAIL_VARIANT_HPP
  11. #include <boost/beast/core/detail/type_traits.hpp>
  12. #include <boost/assert.hpp>
  13. #include <boost/mp11/algorithm.hpp>
  14. namespace boost {
  15. namespace beast {
  16. namespace detail {
  17. // This simple variant gets the job done without
  18. // causing too much trouble with template depth:
  19. //
  20. // * Always allows an empty state I==0
  21. // * emplace() and get() support 1-based indexes only
  22. // * Basic exception guarantee
  23. // * Max 255 types
  24. //
  25. template<class... TN>
  26. class variant
  27. {
  28. detail::aligned_union_t<1, TN...> buf_;
  29. unsigned char i_ = 0;
  30. struct destroy
  31. {
  32. variant& self;
  33. void operator()(mp11::mp_size_t<0>)
  34. {
  35. }
  36. template<class I>
  37. void operator()(I) noexcept
  38. {
  39. using T =
  40. mp11::mp_at_c<variant, I::value - 1>;
  41. detail::launder_cast<T*>(&self.buf_)->~T();
  42. }
  43. };
  44. struct copy
  45. {
  46. variant& self;
  47. variant const& other;
  48. void operator()(mp11::mp_size_t<0>)
  49. {
  50. }
  51. template<class I>
  52. void operator()(I)
  53. {
  54. using T =
  55. mp11::mp_at_c<variant, I::value - 1>;
  56. ::new(&self.buf_) T(
  57. *detail::launder_cast<T const*>(&other.buf_));
  58. self.i_ = I::value;
  59. }
  60. };
  61. struct move
  62. {
  63. variant& self;
  64. variant& other;
  65. void operator()(mp11::mp_size_t<0>)
  66. {
  67. }
  68. template<class I>
  69. void operator()(I)
  70. {
  71. using T =
  72. mp11::mp_at_c<variant, I::value - 1>;
  73. ::new(&self.buf_) T(std::move(
  74. *detail::launder_cast<T*>(&other.buf_)));
  75. detail::launder_cast<T*>(&other.buf_)->~T();
  76. self.i_ = I::value;
  77. }
  78. };
  79. struct equals
  80. {
  81. variant const& self;
  82. variant const& other;
  83. bool operator()(mp11::mp_size_t<0>)
  84. {
  85. return true;
  86. }
  87. template<class I>
  88. bool operator()(I)
  89. {
  90. using T =
  91. mp11::mp_at_c<variant, I::value - 1>;
  92. return
  93. *detail::launder_cast<T const*>(&self.buf_) ==
  94. *detail::launder_cast<T const*>(&other.buf_);
  95. }
  96. };
  97. void destruct()
  98. {
  99. mp11::mp_with_index<
  100. sizeof...(TN) + 1>(
  101. i_, destroy{*this});
  102. i_ = 0;
  103. }
  104. void copy_construct(variant const& other)
  105. {
  106. mp11::mp_with_index<
  107. sizeof...(TN) + 1>(
  108. other.i_, copy{*this, other});
  109. }
  110. void move_construct(variant& other)
  111. {
  112. mp11::mp_with_index<
  113. sizeof...(TN) + 1>(
  114. other.i_, move{*this, other});
  115. other.i_ = 0;
  116. }
  117. public:
  118. variant() = default;
  119. ~variant()
  120. {
  121. destruct();
  122. }
  123. bool
  124. operator==(variant const& other) const
  125. {
  126. if(i_ != other.i_)
  127. return false;
  128. return mp11::mp_with_index<
  129. sizeof...(TN) + 1>(
  130. i_, equals{*this, other});
  131. }
  132. // 0 = empty
  133. unsigned char
  134. index() const
  135. {
  136. return i_;
  137. }
  138. // moved-from object becomes empty
  139. variant(variant&& other) noexcept
  140. {
  141. move_construct(other);
  142. }
  143. variant(variant const& other)
  144. {
  145. copy_construct(other);
  146. }
  147. // moved-from object becomes empty
  148. variant& operator=(variant&& other)
  149. {
  150. if(this != &other)
  151. {
  152. destruct();
  153. move_construct(other);
  154. }
  155. return *this;
  156. }
  157. variant& operator=(variant const& other)
  158. {
  159. if(this != &other)
  160. {
  161. destruct();
  162. copy_construct(other);
  163. }
  164. return *this;
  165. }
  166. template<std::size_t I, class... Args>
  167. void
  168. emplace(Args&&... args) noexcept
  169. {
  170. destruct();
  171. ::new(&buf_) mp11::mp_at_c<variant, I - 1>(
  172. std::forward<Args>(args)...);
  173. i_ = I;
  174. }
  175. template<std::size_t I>
  176. mp11::mp_at_c<variant, I - 1>&
  177. get()
  178. {
  179. BOOST_ASSERT(i_ == I);
  180. return *detail::launder_cast<
  181. mp11::mp_at_c<variant, I - 1>*>(&buf_);
  182. }
  183. template<std::size_t I>
  184. mp11::mp_at_c<variant, I - 1> const&
  185. get() const
  186. {
  187. BOOST_ASSERT(i_ == I);
  188. return *detail::launder_cast<
  189. mp11::mp_at_c<variant, I - 1> const*>(&buf_);
  190. }
  191. void
  192. reset()
  193. {
  194. destruct();
  195. }
  196. };
  197. } // detail
  198. } // beast
  199. } // boost
  200. #endif