You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
230 lines
5.9 KiB
230 lines
5.9 KiB
// Copyright The OpenTelemetry Authors |
|
// SPDX-License-Identifier: Apache-2.0 |
|
|
|
#pragma once |
|
|
|
// IWYU pragma: private, include "opentelemetry/nostd/variant.h" |
|
|
|
#include "opentelemetry/version.h" |
|
|
|
#include <cstddef> |
|
#include <memory> |
|
#include <utility> |
|
#include <variant> |
|
|
|
OPENTELEMETRY_BEGIN_NAMESPACE |
|
// Standard Type aliases in nostd namespace |
|
namespace nostd |
|
{ |
|
using std::get_if; |
|
using std::monostate; |
|
using std::variant_alternative_t; |
|
|
|
// nostd::variant<...> |
|
template <class... _Types> |
|
using variant = std::variant<_Types...>; |
|
|
|
template <class... _Types> |
|
using variant_size = std::variant_size<_Types...>; |
|
|
|
using monostate = std::monostate; |
|
|
|
#if defined(__APPLE__) && defined(_LIBCPP_USE_AVAILABILITY_APPLE) |
|
// Apple Platforms provide std::bad_variant_access only in newer versions of OS. |
|
// To keep API compatible with any version of OS - we are providing our own |
|
// implementation of nostd::bad_variant_access exception. |
|
# if __EXCEPTIONS |
|
|
|
// nostd::bad_variant_access |
|
class bad_variant_access : public std::exception |
|
{ |
|
public: |
|
virtual const char *what() const noexcept override { return "bad_variant_access"; } |
|
}; |
|
|
|
[[noreturn]] inline void throw_bad_variant_access() |
|
{ |
|
throw bad_variant_access{}; |
|
} |
|
# endif |
|
|
|
# if __EXCEPTIONS |
|
# define THROW_BAD_VARIANT_ACCESS throw_bad_variant_access() |
|
# else |
|
# define THROW_BAD_VARIANT_ACCESS std::terminate() |
|
# endif |
|
|
|
// |
|
// nostd::get<...> for Apple Clang |
|
// |
|
template <typename T, class... Types> |
|
constexpr auto get_type = [](auto &&t) constexpr -> decltype(auto) { |
|
auto v = t; |
|
auto result = std::get_if<T>(&v); // TODO: optimize with std::forward(t) if t is not rvalue |
|
if (result) |
|
{ |
|
return *result; |
|
} |
|
THROW_BAD_VARIANT_ACCESS; |
|
return *result; |
|
}; |
|
|
|
template <std::size_t I, class... Types> |
|
constexpr auto get_index = [](auto &&t) constexpr -> decltype(auto) { |
|
auto v = t; |
|
auto result = std::get_if<I>(&v); // TODO: optimize with std::forward(t) if t is not rvalue |
|
if (result) |
|
{ |
|
return *result; |
|
} |
|
THROW_BAD_VARIANT_ACCESS; |
|
return *result; |
|
}; |
|
|
|
template <std::size_t I, class... Types> |
|
constexpr std::variant_alternative_t<I, std::variant<Types...>> &get(std::variant<Types...> &v) |
|
{ |
|
return get_index<I, Types...>(v); |
|
}; |
|
|
|
template <std::size_t I, class... Types> |
|
constexpr std::variant_alternative_t<I, std::variant<Types...>> &&get(std::variant<Types...> &&v) |
|
{ |
|
return get_index<I, Types...>(std::forward<decltype(v)>(v)); |
|
}; |
|
|
|
template <std::size_t I, class... Types> |
|
constexpr const std::variant_alternative_t<I, std::variant<Types...>> &get( |
|
const std::variant<Types...> &v) |
|
{ |
|
return get_index<I, Types...>(v); |
|
}; |
|
|
|
template <std::size_t I, class... Types> |
|
constexpr const std::variant_alternative_t<I, std::variant<Types...>> &&get( |
|
const std::variant<Types...> &&v) |
|
{ |
|
return get_index<I, Types...>(std::forward<decltype(v)>(v)); |
|
}; |
|
|
|
template <class T, class... Types> |
|
constexpr T &get(std::variant<Types...> &v) |
|
{ |
|
return get_type<T, Types...>(v); |
|
}; |
|
|
|
template <class T, class... Types> |
|
constexpr T /*&&*/ get(std::variant<Types...> &&v) |
|
{ |
|
return get_type<T, Types...>(v); |
|
}; |
|
|
|
template <class T, class... Types> |
|
constexpr const T &get(const std::variant<Types...> &v) |
|
{ |
|
return get_type<T, Types...>(v); |
|
}; |
|
|
|
template <class T, class... Types> |
|
constexpr const T &&get(const std::variant<Types...> &&v) |
|
{ |
|
return get_type<T, Types...>(std::forward<decltype(v)>(v)); |
|
}; |
|
|
|
template <class _Callable, class... _Variants> |
|
constexpr auto visit(_Callable &&_Obj, _Variants &&..._Args) |
|
{ |
|
// Ref: |
|
// https://stackoverflow.com/questions/52310835/xcode-10-call-to-unavailable-function-stdvisit |
|
return std::__variant_detail::__visitation::__variant::__visit_value(_Obj, _Args...); |
|
}; |
|
|
|
#else |
|
using std::bad_variant_access; |
|
|
|
template <std::size_t I, class... Types> |
|
constexpr std::variant_alternative_t<I, std::variant<Types...>> &get(std::variant<Types...> &v) |
|
{ |
|
return std::get<I, Types...>(v); |
|
} |
|
|
|
template <std::size_t I, class... Types> |
|
constexpr std::variant_alternative_t<I, std::variant<Types...>> &&get(std::variant<Types...> &&v) |
|
{ |
|
return std::get<I, Types...>(std::forward<decltype(v)>(v)); |
|
} |
|
|
|
template <std::size_t I, class... Types> |
|
constexpr const std::variant_alternative_t<I, std::variant<Types...>> &get( |
|
const std::variant<Types...> &v) |
|
{ |
|
return std::get<I, Types...>(v); |
|
} |
|
|
|
template <std::size_t I, class... Types> |
|
constexpr const std::variant_alternative_t<I, std::variant<Types...>> &&get( |
|
const std::variant<Types...> &&v) |
|
{ |
|
return std::get<I, Types...>(std::forward<decltype(v)>(v)); |
|
} |
|
|
|
template <class T, class... Types> |
|
constexpr T &get(std::variant<Types...> &v) |
|
{ |
|
return std::get<T, Types...>(v); |
|
} |
|
|
|
template <class T, class... Types> |
|
constexpr T &&get(std::variant<Types...> &&v) |
|
{ |
|
return std::get<T, Types...>(std::forward<decltype(v)>(v)); |
|
} |
|
|
|
template <class T, class... Types> |
|
constexpr const T &get(const std::variant<Types...> &v) |
|
{ |
|
return std::get<T, Types...>(v); |
|
} |
|
|
|
template <class T, class... Types> |
|
constexpr const T &&get(const std::variant<Types...> &&v) |
|
{ |
|
return std::get<T, Types...>(std::forward<decltype(v)>(v)); |
|
} |
|
|
|
template <class _Callable, class... _Variants> |
|
constexpr auto visit(_Callable &&_Obj, _Variants &&..._Args) |
|
{ |
|
return std::visit<_Callable, _Variants...>(static_cast<_Callable &&>(_Obj), |
|
static_cast<_Variants &&>(_Args)...); |
|
} |
|
|
|
#endif |
|
|
|
/* |
|
# if _HAS_CXX20 |
|
template <class _Ret, class _Callable, class... _Variants> |
|
constexpr _Ret visit(_Callable &&_Obj, _Variants &&... _Args) |
|
{ |
|
return std::visit<_Ret, _Callable, _Variants...>( |
|
static_cast<_Callable &&>(_Obj), |
|
static_cast<_Variants &&>(_Args)...); |
|
}; |
|
# endif |
|
*/ |
|
|
|
// nostd::holds_alternative |
|
template <std::size_t I, typename... Ts> |
|
inline constexpr bool holds_alternative(const variant<Ts...> &v) noexcept |
|
{ |
|
return v.index() == I; |
|
} |
|
|
|
template <typename T, typename... Ts> |
|
inline constexpr bool holds_alternative(const variant<Ts...> &v) noexcept |
|
{ |
|
return std::holds_alternative<T, Ts...>(v); |
|
} |
|
|
|
} // namespace nostd |
|
OPENTELEMETRY_END_NAMESPACE
|
|
|