userver: userver/utils/span.hpp Source File
Loading...
Searching...
No Matches
span.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/utils/span.hpp
4/// @brief @copybrief utils::span
5
6#include <cstddef>
7#include <iterator>
8#include <type_traits>
9
10#include <userver/utils/assert.hpp>
11
12USERVER_NAMESPACE_BEGIN
13
14namespace utils {
15
16namespace impl {
17
18template <typename T>
19struct TypeIdentityImpl final {
20 using type = T;
21};
22
23template <typename T>
24using TypeIdentity = typename TypeIdentityImpl<T>::type;
25
26} // namespace impl
27
28/// A polyfill for std::span from C++20
29template <typename T>
30class span final {
31public:
32 using iterator = T*;
33
34 constexpr span() noexcept : span(nullptr, nullptr) {}
35
36 constexpr span(T* begin, T* end) noexcept : begin_(begin), end_(end) {
37 UASSERT((begin != nullptr && end != nullptr && begin <= end) || (begin == nullptr && end == nullptr));
38 }
39
40 constexpr span(T* begin, std::size_t size) noexcept : begin_(begin), end_(begin + size) {
41 UASSERT(begin != nullptr || size == 0);
42 }
43
44 template <
45 typename Container,
46 typename = std::enable_if_t<
47 // Either Container is lvalue, or this span's elements are const
48 (std::is_lvalue_reference_v<Container> || std::is_const_v<T>)&&
49 // Copy and move constructor fix
50 !std::is_same_v<std::remove_cv_t<std::remove_reference_t<Container>>, span> &&
51 // Container is a range of T
52 std::is_convertible_v<decltype(std::data(std::declval<Container&>())), T*>>>
53 // NOLINTNEXTLINE(cppcoreguidelines-missing-std-forward)
54 constexpr /*implicit*/ span(Container&& cont) noexcept : span(std::data(cont), std::size(cont)) {}
55
56 template <std::size_t Size>
57 constexpr /*implicit*/ span(impl::TypeIdentity<T> (&array)[Size]) noexcept
58 : span(std::data(array), std::size(array)) {}
59
60 constexpr T* begin() const noexcept { return begin_; }
61 constexpr T* end() const noexcept { return end_; }
62
63 constexpr T* data() const noexcept { return begin_; }
64 constexpr std::size_t size() const noexcept { return end_ - begin_; }
65 constexpr bool empty() const noexcept { return size() == 0; }
66
67 constexpr span<T> first(std::size_t count) const noexcept {
68 UASSERT(count <= size());
69 return span{begin_, begin_ + count};
70 }
71
72 constexpr span<T> last(std::size_t count) const noexcept {
73 UASSERT(count <= size());
74 return span{end_ - count, end_};
75 }
76
77 constexpr span<T> subspan(std::size_t offset) const noexcept {
78 UASSERT(offset <= size());
79 return span{begin_ + offset, end_};
80 }
81
82 constexpr span<T> subspan(
83 std::size_t offset, //
84 std::size_t count
85 ) const noexcept {
86 UASSERT(offset + count <= size());
87 return span{begin_ + offset, begin_ + offset + count};
88 }
89
90 constexpr T& operator[](std::size_t index) const noexcept {
91 UASSERT(index < size());
92 return begin_[index];
93 }
94
95private:
96 T* begin_;
97 T* end_;
98};
99
100template <typename Container>
101span(Container&& cont) -> span<std::remove_reference_t<decltype(*std::begin(cont))>>;
102
103/// A polyfill for std::as_bytes from C++20
104template <typename T>
105span<const std::byte> as_bytes(span<T> s) noexcept {
106 const auto* const data = reinterpret_cast<const std::byte*>(s.data());
107 return {data, data + s.size() * sizeof(T)};
108}
109
110/// A polyfill for std::as_writable_bytes from C++20
111template <typename T>
112span<std::byte> as_writable_bytes(span<T> s) noexcept {
113 static_assert(!std::is_const_v<T>);
114 auto* const data = reinterpret_cast<std::byte*>(s.data());
115 return {data, data + s.size() * sizeof(T)};
116}
117
118} // namespace utils
119
120USERVER_NAMESPACE_END
121
122/// @cond
123
124// Boost requires ranges to have a nested constant_iterator alias,
125// but utils::span does not have one.
126namespace boost {
127
128template <typename T, typename Enabler>
129struct range_const_iterator;
130
131template <typename T>
132struct range_const_iterator<USERVER_NAMESPACE::utils::span<T>, void> {
133 using type = typename USERVER_NAMESPACE::utils::span<T>::iterator;
134};
135
136} // namespace boost
137
138/// @endcond