span.h raw

   1  // Copyright (c) 2018-present The Bitcoin Core developers
   2  // Distributed under the MIT software license, see the accompanying
   3  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
   4  
   5  #ifndef BITCOIN_SPAN_H
   6  #define BITCOIN_SPAN_H
   7  
   8  #include <cassert>
   9  #include <cstddef>
  10  #include <span>
  11  #include <type_traits>
  12  #include <utility>
  13  
  14  /** A span is an object that can refer to a contiguous sequence of objects.
  15   *
  16   * Things to be aware of when writing code that deals with spans:
  17   *
  18   * - Similar to references themselves, spans are subject to reference lifetime
  19   *   issues. The user is responsible for making sure the objects pointed to by
  20   *   a span live as long as the span is used. For example:
  21   *
  22   *       std::vector<int> vec{1,2,3,4};
  23   *       std::span<int> sp(vec);
  24   *       vec.push_back(5);
  25   *       printf("%i\n", sp.front()); // UB!
  26   *
  27   *   may exhibit undefined behavior, as increasing the size of a vector may
  28   *   invalidate references.
  29   *
  30   * - One particular pitfall is that spans can be constructed from temporaries,
  31   *   but this is unsafe when the span is stored in a variable, outliving the
  32   *   temporary. For example, this will compile, but exhibits undefined behavior:
  33   *
  34   *       std::span<const int> sp(std::vector<int>{1, 2, 3});
  35   *       printf("%i\n", sp.front()); // UB!
  36   *
  37   *   The lifetime of the vector ends when the statement it is created in ends.
  38   *   Thus the span is left with a dangling reference, and using it is undefined.
  39   *
  40   * - Due to spans automatic creation from range-like objects (arrays, and data
  41   *   types that expose a data() and size() member function), functions that
  42   *   accept a span as input parameter can be called with any compatible
  43   *   range-like object. For example, this works:
  44   *
  45   *       void Foo(std::span<const int> arg);
  46   *
  47   *       Foo(std::vector<int>{1, 2, 3}); // Works
  48   *
  49   *   This is very useful in cases where a function truly does not care about the
  50   *   container, and only about having exactly a range of elements. However it
  51   *   may also be surprising to see automatic conversions in this case.
  52   *
  53   *   When a function accepts a span with a mutable element type, it will not
  54   *   accept temporaries; only variables or other references. For example:
  55   *
  56   *       void FooMut(std::span<int> arg);
  57   *
  58   *       FooMut(std::vector<int>{1, 2, 3}); // Does not compile
  59   *       std::vector<int> baz{1, 2, 3};
  60   *       FooMut(baz); // Works
  61   *
  62   *   This is similar to how functions that take (non-const) lvalue references
  63   *   as input cannot accept temporaries. This does not work either:
  64   *
  65   *       void FooVec(std::vector<int>& arg);
  66   *       FooVec(std::vector<int>{1, 2, 3}); // Does not compile
  67   *
  68   *   The idea is that if a function accepts a mutable reference, a meaningful
  69   *   result will be present in that variable after the call. Passing a temporary
  70   *   is useless in that context.
  71   */
  72  
  73  /** Pop the last element off a span, and return a reference to that element. */
  74  template <typename T>
  75  T& SpanPopBack(std::span<T>& span)
  76  {
  77      size_t size = span.size();
  78      T& back = span.back();
  79      span = span.first(size - 1);
  80      return back;
  81  }
  82  
  83  template <typename V>
  84  auto MakeByteSpan(const V& v) noexcept
  85  {
  86      return std::as_bytes(std::span{v});
  87  }
  88  template <typename V>
  89  auto MakeWritableByteSpan(V&& v) noexcept
  90  {
  91      return std::as_writable_bytes(std::span{std::forward<V>(v)});
  92  }
  93  
  94  // Helper functions to safely cast basic byte pointers to unsigned char pointers.
  95  inline unsigned char* UCharCast(char* c) { return reinterpret_cast<unsigned char*>(c); }
  96  inline unsigned char* UCharCast(unsigned char* c) { return c; }
  97  inline unsigned char* UCharCast(signed char* c) { return reinterpret_cast<unsigned char*>(c); }
  98  inline unsigned char* UCharCast(std::byte* c) { return reinterpret_cast<unsigned char*>(c); }
  99  inline const unsigned char* UCharCast(const char* c) { return reinterpret_cast<const unsigned char*>(c); }
 100  inline const unsigned char* UCharCast(const unsigned char* c) { return c; }
 101  inline const unsigned char* UCharCast(const signed char* c) { return reinterpret_cast<const unsigned char*>(c); }
 102  inline const unsigned char* UCharCast(const std::byte* c) { return reinterpret_cast<const unsigned char*>(c); }
 103  // Helper concept for the basic byte types.
 104  template <typename B>
 105  concept BasicByte = requires { UCharCast(std::span<B>{}.data()); };
 106  
 107  // Helper function to safely convert a span to a span<[const] unsigned char>.
 108  template <typename T, size_t N> constexpr auto UCharSpanCast(std::span<T, N> s) { return std::span<std::remove_pointer_t<decltype(UCharCast(s.data()))>, N>{UCharCast(s.data()), s.size()}; }
 109  
 110  /** Like the std::span constructor, but for (const) unsigned char member types only. Only works for (un)signed char containers. */
 111  template <typename V> constexpr auto MakeUCharSpan(const V& v) -> decltype(UCharSpanCast(std::span{v})) { return UCharSpanCast(std::span{v}); }
 112  template <typename V> constexpr auto MakeWritableUCharSpan(V&& v) -> decltype(UCharSpanCast(std::span{std::forward<V>(v)})) { return UCharSpanCast(std::span{std::forward<V>(v)}); }
 113  
 114  #endif // BITCOIN_SPAN_H
 115