gnunet-android

GNUnet for Android
Log | Files | Refs | README

span.h (7855B)


      1 // Copyright 2017 The BoringSSL Authors
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //     https://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 #ifndef OPENSSL_HEADER_SSL_SPAN_H
     16 #define OPENSSL_HEADER_SSL_SPAN_H
     17 
     18 #include <openssl/base.h>   // IWYU pragma: export
     19 
     20 #if !defined(BORINGSSL_NO_CXX)
     21 
     22 extern "C++" {
     23 
     24 #include <stdlib.h>
     25 
     26 #include <algorithm>
     27 #include <string_view>
     28 #include <type_traits>
     29 
     30 #if __has_include(<version>)
     31 #include <version>
     32 #endif
     33 
     34 #if defined(__cpp_lib_ranges) && __cpp_lib_ranges >= 201911L
     35 #include <ranges>
     36 BSSL_NAMESPACE_BEGIN
     37 template <typename T>
     38 class Span;
     39 BSSL_NAMESPACE_END
     40 
     41 // Mark `Span` as satisfying the `view` and `borrowed_range` concepts. This
     42 // should be done before the definition of `Span`, so that any inlined calls to
     43 // range functionality use the correct specializations.
     44 template <typename T>
     45 inline constexpr bool std::ranges::enable_view<bssl::Span<T>> = true;
     46 template <typename T>
     47 inline constexpr bool std::ranges::enable_borrowed_range<bssl::Span<T>> = true;
     48 #endif
     49 
     50 BSSL_NAMESPACE_BEGIN
     51 
     52 template <typename T>
     53 class Span;
     54 
     55 namespace internal {
     56 template <typename T>
     57 class SpanBase {
     58   // Put comparison operator implementations into a base class with const T, so
     59   // they can be used with any type that implicitly converts into a Span.
     60   static_assert(std::is_const<T>::value,
     61                 "Span<T> must be derived from SpanBase<const T>");
     62 
     63   friend bool operator==(Span<T> lhs, Span<T> rhs) {
     64     return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
     65   }
     66 
     67   friend bool operator!=(Span<T> lhs, Span<T> rhs) { return !(lhs == rhs); }
     68 };
     69 
     70 // Heuristically test whether C is a container type that can be converted into
     71 // a Span<T> by checking for data() and size() member functions.
     72 template <typename C, typename T>
     73 using EnableIfContainer = std::enable_if_t<
     74     std::is_convertible_v<decltype(std::declval<C>().data()), T *> &&
     75     std::is_integral_v<decltype(std::declval<C>().size())>>;
     76 
     77 }  // namespace internal
     78 
     79 // A Span<T> is a non-owning reference to a contiguous array of objects of type
     80 // |T|. Conceptually, a Span is a simple a pointer to |T| and a count of
     81 // elements accessible via that pointer. The elements referenced by the Span can
     82 // be mutated if |T| is mutable.
     83 //
     84 // A Span can be constructed from container types implementing |data()| and
     85 // |size()| methods. If |T| is constant, construction from a container type is
     86 // implicit. This allows writing methods that accept data from some unspecified
     87 // container type:
     88 //
     89 // // Foo views data referenced by v.
     90 // void Foo(bssl::Span<const uint8_t> v) { ... }
     91 //
     92 // std::vector<uint8_t> vec;
     93 // Foo(vec);
     94 //
     95 // For mutable Spans, conversion is explicit:
     96 //
     97 // // FooMutate mutates data referenced by v.
     98 // void FooMutate(bssl::Span<uint8_t> v) { ... }
     99 //
    100 // FooMutate(bssl::Span<uint8_t>(vec));
    101 //
    102 // You can also use C++17 class template argument deduction to construct Spans
    103 // in order to deduce the type of the Span automatically.
    104 //
    105 // FooMutate(bssl::Span(vec));
    106 //
    107 // Note that Spans have value type sematics. They are cheap to construct and
    108 // copy, and should be passed by value whenever a method would otherwise accept
    109 // a reference or pointer to a container or array.
    110 template <typename T>
    111 class Span : private internal::SpanBase<const T> {
    112  public:
    113   static const size_t npos = static_cast<size_t>(-1);
    114 
    115   using element_type = T;
    116   using value_type = std::remove_cv_t<T>;
    117   using size_type = size_t;
    118   using difference_type = ptrdiff_t;
    119   using pointer = T *;
    120   using const_pointer = const T *;
    121   using reference = T &;
    122   using const_reference = const T &;
    123   using iterator = T *;
    124   using const_iterator = const T *;
    125 
    126   constexpr Span() : Span(nullptr, 0) {}
    127   constexpr Span(T *ptr, size_t len) : data_(ptr), size_(len) {}
    128 
    129   template <size_t N>
    130   constexpr Span(T (&array)[N]) : Span(array, N) {}
    131 
    132   template <typename C, typename = internal::EnableIfContainer<C, T>,
    133             typename = std::enable_if_t<std::is_const<T>::value, C>>
    134   constexpr Span(const C &container)
    135       : data_(container.data()), size_(container.size()) {}
    136 
    137   template <typename C, typename = internal::EnableIfContainer<C, T>,
    138             typename = std::enable_if_t<!std::is_const<T>::value, C>>
    139   constexpr explicit Span(C &container)
    140       : data_(container.data()), size_(container.size()) {}
    141 
    142   constexpr T *data() const { return data_; }
    143   constexpr size_t size() const { return size_; }
    144   constexpr bool empty() const { return size_ == 0; }
    145 
    146   constexpr iterator begin() const { return data_; }
    147   constexpr const_iterator cbegin() const { return data_; }
    148   constexpr iterator end() const { return data_ + size_; }
    149   constexpr const_iterator cend() const { return end(); }
    150 
    151   constexpr T &front() const {
    152     if (size_ == 0) {
    153       abort();
    154     }
    155     return data_[0];
    156   }
    157   constexpr T &back() const {
    158     if (size_ == 0) {
    159       abort();
    160     }
    161     return data_[size_ - 1];
    162   }
    163 
    164   constexpr T &operator[](size_t i) const {
    165     if (i >= size_) {
    166       abort();
    167     }
    168     return data_[i];
    169   }
    170   T &at(size_t i) const { return (*this)[i]; }
    171 
    172   constexpr Span subspan(size_t pos = 0, size_t len = npos) const {
    173     if (pos > size_) {
    174       // absl::Span throws an exception here. Note std::span and Chromium
    175       // base::span additionally forbid pos + len being out of range, with a
    176       // special case at npos/dynamic_extent, while absl::Span::subspan clips
    177       // the span. For now, we align with absl::Span in case we switch to it in
    178       // the future.
    179       abort();
    180     }
    181     return Span(data_ + pos, std::min(size_ - pos, len));
    182   }
    183 
    184   constexpr Span first(size_t len) const {
    185     if (len > size_) {
    186       abort();
    187     }
    188     return Span(data_, len);
    189   }
    190 
    191   constexpr Span last(size_t len) const {
    192     if (len > size_) {
    193       abort();
    194     }
    195     return Span(data_ + size_ - len, len);
    196   }
    197 
    198  private:
    199   T *data_;
    200   size_t size_;
    201 };
    202 
    203 template <typename T>
    204 const size_t Span<T>::npos;
    205 
    206 template <typename T>
    207 Span(T *, size_t) -> Span<T>;
    208 template <typename T, size_t size>
    209 Span(T (&array)[size]) -> Span<T>;
    210 template <
    211     typename C,
    212     typename T = std::remove_pointer_t<decltype(std::declval<C>().data())>,
    213     typename = internal::EnableIfContainer<C, T>>
    214 Span(C &) -> Span<T>;
    215 
    216 template <typename T>
    217 constexpr Span<T> MakeSpan(T *ptr, size_t size) {
    218   return Span<T>(ptr, size);
    219 }
    220 
    221 template <typename C>
    222 constexpr auto MakeSpan(C &c) -> decltype(MakeSpan(c.data(), c.size())) {
    223   return MakeSpan(c.data(), c.size());
    224 }
    225 
    226 template <typename T, size_t N>
    227 constexpr Span<T> MakeSpan(T (&array)[N]) {
    228   return Span<T>(array, N);
    229 }
    230 
    231 template <typename T>
    232 constexpr Span<const T> MakeConstSpan(T *ptr, size_t size) {
    233   return Span<const T>(ptr, size);
    234 }
    235 
    236 template <typename C>
    237 constexpr auto MakeConstSpan(const C &c)
    238     -> decltype(MakeConstSpan(c.data(), c.size())) {
    239   return MakeConstSpan(c.data(), c.size());
    240 }
    241 
    242 template <typename T, size_t size>
    243 constexpr Span<const T> MakeConstSpan(T (&array)[size]) {
    244   return array;
    245 }
    246 
    247 inline Span<const uint8_t> StringAsBytes(std::string_view s) {
    248   return MakeConstSpan(reinterpret_cast<const uint8_t *>(s.data()), s.size());
    249 }
    250 
    251 inline std::string_view BytesAsStringView(bssl::Span<const uint8_t> b) {
    252   return std::string_view(reinterpret_cast<const char *>(b.data()), b.size());
    253 }
    254 
    255 BSSL_NAMESPACE_END
    256 
    257 }  // extern C++
    258 
    259 #endif  // !defined(BORINGSSL_NO_CXX)
    260 
    261 #endif  // OPENSSL_HEADER_SSL_SPAN_H