Source code

Revision control

Copy as Markdown

Other Tools

// 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:
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, template<typename...> typename U, typename... Ts>
inline constexpr bool holds_alternative(const U<Ts...> &v) noexcept
{
// Clang 18.1.7 on Ubuntu 24.04 does not disambiguate between this
// and std::holds_alternative if argument type is std::variant<Ts...>
static_assert(std::is_same_v<U<Ts...>, std::variant<Ts...>>,
"Unsupported argument type");
return std::holds_alternative<T, Ts...>(v);
}
} // namespace nostd
OPENTELEMETRY_END_NAMESPACE