span.h
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