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.
274 lines
8.3 KiB
274 lines
8.3 KiB
// Copyright The OpenTelemetry Authors |
|
// SPDX-License-Identifier: Apache-2.0 |
|
|
|
#pragma once |
|
|
|
// Try to use either `std::span` or `gsl::span` |
|
#if defined(OPENTELEMETRY_STL_VERSION) |
|
# if OPENTELEMETRY_STL_VERSION >= 2020 |
|
# include <array> |
|
# include <cstddef> |
|
# include <iterator> |
|
# include <type_traits> |
|
|
|
/** |
|
* @brief Clang 14.0.0 with libc++ do not support implicitly construct a span |
|
* for a range. We just use our fallback version. |
|
* |
|
*/ |
|
# if !defined(OPENTELEMETRY_OPTION_USE_STD_SPAN) && defined(_LIBCPP_VERSION) |
|
# if _LIBCPP_VERSION <= 14000 |
|
# define OPENTELEMETRY_OPTION_USE_STD_SPAN 0 |
|
# endif |
|
# endif |
|
# ifndef OPENTELEMETRY_OPTION_USE_STD_SPAN |
|
# define OPENTELEMETRY_OPTION_USE_STD_SPAN 1 |
|
# endif |
|
# if OPENTELEMETRY_OPTION_USE_STD_SPAN |
|
# include "opentelemetry/std/span.h" |
|
# endif |
|
# endif /* OPENTELEMETRY_STL_VERSION >= 2020 */ |
|
#endif /* OPENTELEMETRY_STL_VERSION */ |
|
|
|
// Fallback to `nostd::span` if necessary |
|
#if !defined(OPENTELEMETRY_HAVE_SPAN) |
|
# include <array> |
|
# include <cassert> |
|
# include <cstddef> |
|
# include <exception> |
|
# include <iterator> |
|
# include <type_traits> |
|
|
|
# include "opentelemetry/nostd/utility.h" |
|
# include "opentelemetry/version.h" |
|
|
|
OPENTELEMETRY_BEGIN_NAMESPACE |
|
namespace nostd |
|
{ |
|
constexpr size_t dynamic_extent = static_cast<size_t>(-1); |
|
|
|
template <class T, size_t Extent = dynamic_extent> |
|
class span; |
|
|
|
namespace detail |
|
{ |
|
/** |
|
* Helper class to resolve overloaded constructors |
|
*/ |
|
template <class T> |
|
struct is_specialized_span_convertible : std::false_type |
|
{}; |
|
|
|
template <class T, size_t N> |
|
struct is_specialized_span_convertible<std::array<T, N>> : std::true_type |
|
{}; |
|
|
|
template <class T, size_t N> |
|
struct is_specialized_span_convertible<T[N]> : std::true_type |
|
{}; |
|
|
|
template <class T, size_t Extent> |
|
struct is_specialized_span_convertible<span<T, Extent>> : std::true_type |
|
{}; |
|
} // namespace detail |
|
|
|
/** |
|
* Back port of std::span. |
|
* |
|
* See https://en.cppreference.com/w/cpp/container/span for interface documentation. |
|
* |
|
* Note: This provides a subset of the methods available on std::span. |
|
* |
|
* Note: The std::span API specifies error cases to have undefined behavior, so this implementation |
|
* chooses to terminate or assert rather than throw exceptions. |
|
*/ |
|
template <class T, size_t Extent> |
|
class span |
|
{ |
|
public: |
|
static constexpr size_t extent = Extent; |
|
|
|
// This arcane code is how we make default-construction result in an SFINAE error |
|
// with C++11 when Extent != 0 as specified by the std::span API. |
|
// |
|
// See https://stackoverflow.com/a/10309720/4447365 |
|
template <bool B = Extent == 0, typename std::enable_if<B>::type * = nullptr> |
|
span() noexcept : data_{nullptr} |
|
{} |
|
|
|
span(T *data, size_t count) noexcept : data_{data} |
|
{ |
|
if (count != Extent) |
|
{ |
|
std::terminate(); |
|
} |
|
} |
|
|
|
span(T *first, T *last) noexcept : data_{first} |
|
{ |
|
if (std::distance(first, last) != Extent) |
|
{ |
|
std::terminate(); |
|
} |
|
} |
|
|
|
template <size_t N, typename std::enable_if<Extent == N>::type * = nullptr> |
|
span(T (&array)[N]) noexcept : data_{array} |
|
{} |
|
|
|
template <size_t N, typename std::enable_if<Extent == N>::type * = nullptr> |
|
span(std::array<T, N> &array) noexcept : data_{array.data()} |
|
{} |
|
|
|
template <size_t N, typename std::enable_if<Extent == N>::type * = nullptr> |
|
span(const std::array<T, N> &array) noexcept : data_{array.data()} |
|
{} |
|
|
|
template < |
|
class C, |
|
typename std::enable_if<!detail::is_specialized_span_convertible<C>::value && |
|
std::is_convertible<typename std::remove_pointer<decltype(nostd::data( |
|
std::declval<C &>()))>::type (*)[], |
|
T (*)[]>::value && |
|
std::is_convertible<decltype(nostd::size(std::declval<const C &>())), |
|
size_t>::value>::type * = nullptr> |
|
span(C &c) noexcept(noexcept(nostd::data(c), nostd::size(c))) : data_{nostd::data(c)} |
|
{ |
|
if (nostd::size(c) != Extent) |
|
{ |
|
std::terminate(); |
|
} |
|
} |
|
|
|
template < |
|
class C, |
|
typename std::enable_if<!detail::is_specialized_span_convertible<C>::value && |
|
std::is_convertible<typename std::remove_pointer<decltype(nostd::data( |
|
std::declval<const C &>()))>::type (*)[], |
|
T (*)[]>::value && |
|
std::is_convertible<decltype(nostd::size(std::declval<const C &>())), |
|
size_t>::value>::type * = nullptr> |
|
span(const C &c) noexcept(noexcept(nostd::data(c), nostd::size(c))) : data_{nostd::data(c)} |
|
{ |
|
if (nostd::size(c) != Extent) |
|
{ |
|
std::terminate(); |
|
} |
|
} |
|
|
|
template <class U, |
|
size_t N, |
|
typename std::enable_if<N == Extent && |
|
std::is_convertible<U (*)[], T (*)[]>::value>::type * = nullptr> |
|
span(const span<U, N> &other) noexcept : data_{other.data()} |
|
{} |
|
|
|
span(const span &) noexcept = default; |
|
|
|
span &operator=(const span &) noexcept = default; |
|
|
|
bool empty() const noexcept { return Extent == 0; } |
|
|
|
T *data() const noexcept { return data_; } |
|
|
|
size_t size() const noexcept { return Extent; } |
|
|
|
T &operator[](size_t index) const noexcept |
|
{ |
|
assert(index < Extent); |
|
return data_[index]; |
|
} |
|
|
|
T *begin() const noexcept { return data_; } |
|
|
|
T *end() const noexcept { return data_ + Extent; } |
|
|
|
private: |
|
T *data_; |
|
}; |
|
|
|
template <class T> |
|
class span<T, dynamic_extent> |
|
{ |
|
public: |
|
static constexpr size_t extent = dynamic_extent; |
|
|
|
span() noexcept : extent_{0}, data_{nullptr} {} |
|
|
|
span(T *data, size_t count) noexcept : extent_{count}, data_{data} {} |
|
|
|
span(T *first, T *last) noexcept |
|
: extent_{static_cast<size_t>(std::distance(first, last))}, data_{first} |
|
{ |
|
assert(first <= last); |
|
} |
|
|
|
template <size_t N> |
|
span(T (&array)[N]) noexcept : extent_{N}, data_{array} |
|
{} |
|
|
|
template <size_t N> |
|
span(std::array<T, N> &array) noexcept : extent_{N}, data_{array.data()} |
|
{} |
|
|
|
template <size_t N> |
|
span(const std::array<T, N> &array) noexcept : extent_{N}, data_{array.data()} |
|
{} |
|
|
|
template < |
|
class C, |
|
typename std::enable_if<!detail::is_specialized_span_convertible<C>::value && |
|
std::is_convertible<typename std::remove_pointer<decltype(nostd::data( |
|
std::declval<C &>()))>::type (*)[], |
|
T (*)[]>::value && |
|
std::is_convertible<decltype(nostd::size(std::declval<const C &>())), |
|
size_t>::value>::type * = nullptr> |
|
span(C &c) noexcept(noexcept(nostd::data(c), nostd::size(c))) |
|
: extent_{nostd::size(c)}, data_{nostd::data(c)} |
|
{} |
|
|
|
template < |
|
class C, |
|
typename std::enable_if<!detail::is_specialized_span_convertible<C>::value && |
|
std::is_convertible<typename std::remove_pointer<decltype(nostd::data( |
|
std::declval<const C &>()))>::type (*)[], |
|
T (*)[]>::value && |
|
std::is_convertible<decltype(nostd::size(std::declval<const C &>())), |
|
size_t>::value>::type * = nullptr> |
|
span(const C &c) noexcept(noexcept(nostd::data(c), nostd::size(c))) |
|
: extent_{nostd::size(c)}, data_{nostd::data(c)} |
|
{} |
|
|
|
template <class U, |
|
size_t N, |
|
typename std::enable_if<std::is_convertible<U (*)[], T (*)[]>::value>::type * = nullptr> |
|
span(const span<U, N> &other) noexcept : extent_{other.size()}, data_{other.data()} |
|
{} |
|
|
|
span(const span &) noexcept = default; |
|
|
|
span &operator=(const span &) noexcept = default; |
|
|
|
bool empty() const noexcept { return extent_ == 0; } |
|
|
|
T *data() const noexcept { return data_; } |
|
|
|
size_t size() const noexcept { return extent_; } |
|
|
|
T &operator[](size_t index) const noexcept |
|
{ |
|
assert(index < extent_); |
|
return data_[index]; |
|
} |
|
|
|
T *begin() const noexcept { return data_; } |
|
|
|
T *end() const noexcept { return data_ + extent_; } |
|
|
|
private: |
|
size_t extent_; |
|
T *data_; |
|
}; |
|
} // namespace nostd |
|
OPENTELEMETRY_END_NAMESPACE |
|
#endif
|
|
|