Branch data Line data Source code
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 : 254279 : T& SpanPopBack(std::span<T>& span)
76 : : {
77 : 254279 : size_t size = span.size();
78 : 254279 : T& back = span.back();
79 : 254279 : span = span.first(size - 1);
80 : 254279 : return back;
81 : : }
82 : :
83 : : template <typename V>
84 [ + + ]: 35327923 : auto MakeByteSpan(const V& v) noexcept
85 : : {
86 : 35327923 : return std::as_bytes(std::span{v});
87 : : }
88 : : template <typename V>
89 : 6264575 : auto MakeWritableByteSpan(V&& v) noexcept
90 : : {
91 : 6264575 : 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 [ + - ]: 1397245 : 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 [ + - ]: 8821204 : 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 [ + + ]: 8825574 : 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
|