variant.h 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. // Copyright The OpenTelemetry Authors
  2. // SPDX-License-Identifier: Apache-2.0
  3. #pragma once
  4. // IWYU pragma: private, include "opentelemetry/nostd/variant.h"
  5. #include "opentelemetry/version.h"
  6. #include <cstddef>
  7. #include <memory>
  8. #include <utility>
  9. #include <variant>
  10. OPENTELEMETRY_BEGIN_NAMESPACE
  11. // Standard Type aliases in nostd namespace
  12. namespace nostd
  13. {
  14. using std::get_if;
  15. using std::monostate;
  16. using std::variant_alternative_t;
  17. // nostd::variant<...>
  18. template <class... _Types>
  19. using variant = std::variant<_Types...>;
  20. template <class... _Types>
  21. using variant_size = std::variant_size<_Types...>;
  22. using monostate = std::monostate;
  23. #if defined(__APPLE__) && defined(_LIBCPP_USE_AVAILABILITY_APPLE)
  24. // Apple Platforms provide std::bad_variant_access only in newer versions of OS.
  25. // To keep API compatible with any version of OS - we are providing our own
  26. // implementation of nostd::bad_variant_access exception.
  27. # if __EXCEPTIONS
  28. // nostd::bad_variant_access
  29. class bad_variant_access : public std::exception
  30. {
  31. public:
  32. virtual const char *what() const noexcept override { return "bad_variant_access"; }
  33. };
  34. [[noreturn]] inline void throw_bad_variant_access()
  35. {
  36. throw bad_variant_access{};
  37. }
  38. # endif
  39. # if __EXCEPTIONS
  40. # define THROW_BAD_VARIANT_ACCESS throw_bad_variant_access()
  41. # else
  42. # define THROW_BAD_VARIANT_ACCESS std::terminate()
  43. # endif
  44. //
  45. // nostd::get<...> for Apple Clang
  46. //
  47. template <typename T, class... Types>
  48. constexpr auto get_type = [](auto &&t) constexpr -> decltype(auto) {
  49. auto v = t;
  50. auto result = std::get_if<T>(&v); // TODO: optimize with std::forward(t) if t is not rvalue
  51. if (result)
  52. {
  53. return *result;
  54. }
  55. THROW_BAD_VARIANT_ACCESS;
  56. return *result;
  57. };
  58. template <std::size_t I, class... Types>
  59. constexpr auto get_index = [](auto &&t) constexpr -> decltype(auto) {
  60. auto v = t;
  61. auto result = std::get_if<I>(&v); // TODO: optimize with std::forward(t) if t is not rvalue
  62. if (result)
  63. {
  64. return *result;
  65. }
  66. THROW_BAD_VARIANT_ACCESS;
  67. return *result;
  68. };
  69. template <std::size_t I, class... Types>
  70. constexpr std::variant_alternative_t<I, std::variant<Types...>> &get(std::variant<Types...> &v)
  71. {
  72. return get_index<I, Types...>(v);
  73. };
  74. template <std::size_t I, class... Types>
  75. constexpr std::variant_alternative_t<I, std::variant<Types...>> &&get(std::variant<Types...> &&v)
  76. {
  77. return get_index<I, Types...>(std::forward<decltype(v)>(v));
  78. };
  79. template <std::size_t I, class... Types>
  80. constexpr const std::variant_alternative_t<I, std::variant<Types...>> &get(
  81. const std::variant<Types...> &v)
  82. {
  83. return get_index<I, Types...>(v);
  84. };
  85. template <std::size_t I, class... Types>
  86. constexpr const std::variant_alternative_t<I, std::variant<Types...>> &&get(
  87. const std::variant<Types...> &&v)
  88. {
  89. return get_index<I, Types...>(std::forward<decltype(v)>(v));
  90. };
  91. template <class T, class... Types>
  92. constexpr T &get(std::variant<Types...> &v)
  93. {
  94. return get_type<T, Types...>(v);
  95. };
  96. template <class T, class... Types>
  97. constexpr T /*&&*/ get(std::variant<Types...> &&v)
  98. {
  99. return get_type<T, Types...>(v);
  100. };
  101. template <class T, class... Types>
  102. constexpr const T &get(const std::variant<Types...> &v)
  103. {
  104. return get_type<T, Types...>(v);
  105. };
  106. template <class T, class... Types>
  107. constexpr const T &&get(const std::variant<Types...> &&v)
  108. {
  109. return get_type<T, Types...>(std::forward<decltype(v)>(v));
  110. };
  111. template <class _Callable, class... _Variants>
  112. constexpr auto visit(_Callable &&_Obj, _Variants &&..._Args)
  113. {
  114. // Ref:
  115. // https://stackoverflow.com/questions/52310835/xcode-10-call-to-unavailable-function-stdvisit
  116. return std::__variant_detail::__visitation::__variant::__visit_value(_Obj, _Args...);
  117. };
  118. #else
  119. using std::bad_variant_access;
  120. template <std::size_t I, class... Types>
  121. constexpr std::variant_alternative_t<I, std::variant<Types...>> &get(std::variant<Types...> &v)
  122. {
  123. return std::get<I, Types...>(v);
  124. }
  125. template <std::size_t I, class... Types>
  126. constexpr std::variant_alternative_t<I, std::variant<Types...>> &&get(std::variant<Types...> &&v)
  127. {
  128. return std::get<I, Types...>(std::forward<decltype(v)>(v));
  129. }
  130. template <std::size_t I, class... Types>
  131. constexpr const std::variant_alternative_t<I, std::variant<Types...>> &get(
  132. const std::variant<Types...> &v)
  133. {
  134. return std::get<I, Types...>(v);
  135. }
  136. template <std::size_t I, class... Types>
  137. constexpr const std::variant_alternative_t<I, std::variant<Types...>> &&get(
  138. const std::variant<Types...> &&v)
  139. {
  140. return std::get<I, Types...>(std::forward<decltype(v)>(v));
  141. }
  142. template <class T, class... Types>
  143. constexpr T &get(std::variant<Types...> &v)
  144. {
  145. return std::get<T, Types...>(v);
  146. }
  147. template <class T, class... Types>
  148. constexpr T &&get(std::variant<Types...> &&v)
  149. {
  150. return std::get<T, Types...>(std::forward<decltype(v)>(v));
  151. }
  152. template <class T, class... Types>
  153. constexpr const T &get(const std::variant<Types...> &v)
  154. {
  155. return std::get<T, Types...>(v);
  156. }
  157. template <class T, class... Types>
  158. constexpr const T &&get(const std::variant<Types...> &&v)
  159. {
  160. return std::get<T, Types...>(std::forward<decltype(v)>(v));
  161. }
  162. template <class _Callable, class... _Variants>
  163. constexpr auto visit(_Callable &&_Obj, _Variants &&..._Args)
  164. {
  165. return std::visit<_Callable, _Variants...>(static_cast<_Callable &&>(_Obj),
  166. static_cast<_Variants &&>(_Args)...);
  167. }
  168. #endif
  169. /*
  170. # if _HAS_CXX20
  171. template <class _Ret, class _Callable, class... _Variants>
  172. constexpr _Ret visit(_Callable &&_Obj, _Variants &&... _Args)
  173. {
  174. return std::visit<_Ret, _Callable, _Variants...>(
  175. static_cast<_Callable &&>(_Obj),
  176. static_cast<_Variants &&>(_Args)...);
  177. };
  178. # endif
  179. */
  180. // nostd::holds_alternative
  181. template <std::size_t I, typename... Ts>
  182. inline constexpr bool holds_alternative(const variant<Ts...> &v) noexcept
  183. {
  184. return v.index() == I;
  185. }
  186. template <typename T, typename... Ts>
  187. inline constexpr bool holds_alternative(const variant<Ts...> &v) noexcept
  188. {
  189. return std::holds_alternative<T, Ts...>(v);
  190. }
  191. } // namespace nostd
  192. OPENTELEMETRY_END_NAMESPACE