Line | Count | Source |
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 | 103k | { |
77 | 103k | size_t size = span.size(); |
78 | 103k | T& back = span.back(); |
79 | 103k | span = span.first(size - 1); |
80 | 103k | return back; |
81 | 103k | } Unexecuted instantiation: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const& SpanPopBack<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const>(std::span<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, 18446744073709551615ul>&) std::vector<unsigned char, std::allocator<unsigned char> > const& SpanPopBack<std::vector<unsigned char, std::allocator<unsigned char> > const>(std::span<std::vector<unsigned char, std::allocator<unsigned char> > const, 18446744073709551615ul>&) Line | Count | Source | 76 | 103k | { | 77 | 103k | size_t size = span.size(); | 78 | 103k | T& back = span.back(); | 79 | 103k | span = span.first(size - 1); | 80 | 103k | return back; | 81 | 103k | } |
Unexecuted instantiation: unsigned char const& SpanPopBack<unsigned char const>(std::span<unsigned char const, 18446744073709551615ul>&) |
82 | | |
83 | | template <typename V> |
84 | | auto MakeByteSpan(const V& v) noexcept |
85 | 128M | { |
86 | 128M | return std::as_bytes(std::span{v}); |
87 | 128M | } auto MakeByteSpan<std::vector<unsigned char, std::allocator<unsigned char> > >(std::vector<unsigned char, std::allocator<unsigned char> > const&) Line | Count | Source | 85 | 22.5M | { | 86 | 22.5M | return std::as_bytes(std::span{v}); | 87 | 22.5M | } |
auto MakeByteSpan<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) Line | Count | Source | 85 | 1.51M | { | 86 | 1.51M | return std::as_bytes(std::span{v}); | 87 | 1.51M | } |
auto MakeByteSpan<prevector<28u, unsigned char, unsigned int, int> >(prevector<28u, unsigned char, unsigned int, int> const&) Line | Count | Source | 85 | 60.4M | { | 86 | 60.4M | return std::as_bytes(std::span{v}); | 87 | 60.4M | } |
auto MakeByteSpan<uint256>(uint256 const&) Line | Count | Source | 85 | 44.3k | { | 86 | 44.3k | return std::as_bytes(std::span{v}); | 87 | 44.3k | } |
auto MakeByteSpan<std::array<unsigned char, 4ul> >(std::array<unsigned char, 4ul> const&) Line | Count | Source | 85 | 17.4M | { | 86 | 17.4M | return std::as_bytes(std::span{v}); | 87 | 17.4M | } |
auto MakeByteSpan<char [12]>(char const (&) [12]) Line | Count | Source | 85 | 12.9M | { | 86 | 12.9M | return std::as_bytes(std::span{v}); | 87 | 12.9M | } |
auto MakeByteSpan<unsigned char [4]>(unsigned char const (&) [4]) Line | Count | Source | 85 | 12.9M | { | 86 | 12.9M | return std::as_bytes(std::span{v}); | 87 | 12.9M | } |
auto MakeByteSpan<prevector<16u, unsigned char, unsigned int, int> >(prevector<16u, unsigned char, unsigned int, int> const&) Line | Count | Source | 85 | 8.38k | { | 86 | 8.38k | return std::as_bytes(std::span{v}); | 87 | 8.38k | } |
auto MakeByteSpan<unsigned char [16]>(unsigned char const (&) [16]) Line | Count | Source | 85 | 177k | { | 86 | 177k | return std::as_bytes(std::span{v}); | 87 | 177k | } |
Unexecuted instantiation: auto MakeByteSpan<std::array<std::byte, 168ul> >(std::array<std::byte, 168ul> const&) auto MakeByteSpan<std::array<std::byte, 8ul> >(std::array<std::byte, 8ul> const&) Line | Count | Source | 85 | 11.0k | { | 86 | 11.0k | return std::as_bytes(std::span{v}); | 87 | 11.0k | } |
auto MakeByteSpan<std::vector<std::byte, std::allocator<std::byte> > >(std::vector<std::byte, std::allocator<std::byte> > const&) Line | Count | Source | 85 | 11.0k | { | 86 | 11.0k | return std::as_bytes(std::span{v}); | 87 | 11.0k | } |
Unexecuted instantiation: auto MakeByteSpan<std::array<unsigned char, 5ul> >(std::array<unsigned char, 5ul> const&) Unexecuted instantiation: auto MakeByteSpan<unsigned char [5]>(unsigned char const (&) [5]) Unexecuted instantiation: auto MakeByteSpan<unsigned char [78]>(unsigned char const (&) [78]) auto MakeByteSpan<leveldb::Slice>(leveldb::Slice const&) Line | Count | Source | 85 | 13.0k | { | 86 | 13.0k | return std::as_bytes(std::span{v}); | 87 | 13.0k | } |
auto MakeByteSpan<std::vector<unsigned char, secure_allocator<unsigned char> > >(std::vector<unsigned char, secure_allocator<unsigned char> > const&) Line | Count | Source | 85 | 88.7k | { | 86 | 88.7k | return std::as_bytes(std::span{v}); | 87 | 88.7k | } |
Unexecuted instantiation: auto MakeByteSpan<unsigned char [384]>(unsigned char const (&) [384]) |
88 | | template <typename V> |
89 | | auto MakeWritableByteSpan(V&& v) noexcept |
90 | 34.3M | { |
91 | 34.3M | return std::as_writable_bytes(std::span{std::forward<V>(v)}); |
92 | 34.3M | } auto MakeWritableByteSpan<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&) Line | Count | Source | 90 | 88.7k | { | 91 | 88.7k | return std::as_writable_bytes(std::span{std::forward<V>(v)}); | 92 | 88.7k | } |
auto MakeWritableByteSpan<uint256&>(uint256&) Line | Count | Source | 90 | 22.1k | { | 91 | 22.1k | return std::as_writable_bytes(std::span{std::forward<V>(v)}); | 92 | 22.1k | } |
auto MakeWritableByteSpan<DataStream&>(DataStream&) Line | Count | Source | 90 | 6.90M | { | 91 | 6.90M | return std::as_writable_bytes(std::span{std::forward<V>(v)}); | 92 | 6.90M | } |
auto MakeWritableByteSpan<std::vector<unsigned char, std::allocator<unsigned char> >&>(std::vector<unsigned char, std::allocator<unsigned char> >&) Line | Count | Source | 90 | 70.0k | { | 91 | 70.0k | return std::as_writable_bytes(std::span{std::forward<V>(v)}); | 92 | 70.0k | } |
auto MakeWritableByteSpan<unsigned char (&) [16]>(unsigned char (&) [16]) Line | Count | Source | 90 | 95.2k | { | 91 | 95.2k | return std::as_writable_bytes(std::span{std::forward<V>(v)}); | 92 | 95.2k | } |
auto MakeWritableByteSpan<std::array<unsigned char, 4ul>&>(std::array<unsigned char, 4ul>&) Line | Count | Source | 90 | 5.54M | { | 91 | 5.54M | return std::as_writable_bytes(std::span{std::forward<V>(v)}); | 92 | 5.54M | } |
auto MakeWritableByteSpan<char (&) [12]>(char (&) [12]) Line | Count | Source | 90 | 5.52M | { | 91 | 5.52M | return std::as_writable_bytes(std::span{std::forward<V>(v)}); | 92 | 5.52M | } |
auto MakeWritableByteSpan<unsigned char (&) [4]>(unsigned char (&) [4]) Line | Count | Source | 90 | 5.52M | { | 91 | 5.52M | return std::as_writable_bytes(std::span{std::forward<V>(v)}); | 92 | 5.52M | } |
auto MakeWritableByteSpan<std::array<unsigned char, 32ul>&>(std::array<unsigned char, 32ul>&) Line | Count | Source | 90 | 10.5M | { | 91 | 10.5M | return std::as_writable_bytes(std::span{std::forward<V>(v)}); | 92 | 10.5M | } |
Unexecuted instantiation: auto MakeWritableByteSpan<std::array<std::byte, 8ul>&>(std::array<std::byte, 8ul>&) Unexecuted instantiation: auto MakeWritableByteSpan<std::array<unsigned char, 5ul>&>(std::array<unsigned char, 5ul>&) Unexecuted instantiation: auto MakeWritableByteSpan<std::array<unsigned char, 20ul>&>(std::array<unsigned char, 20ul>&) Unexecuted instantiation: auto MakeWritableByteSpan<std::array<std::byte, 20ul>&>(std::array<std::byte, 20ul>&) Unexecuted instantiation: auto MakeWritableByteSpan<char (&) [368]>(char (&) [368]) Unexecuted instantiation: auto MakeWritableByteSpan<unsigned char (&) [20]>(unsigned char (&) [20]) Unexecuted instantiation: auto MakeWritableByteSpan<unsigned char (&) [5]>(unsigned char (&) [5]) Unexecuted instantiation: auto MakeWritableByteSpan<unsigned char (&) [384]>(unsigned char (&) [384]) |
93 | | |
94 | | // Helper functions to safely cast basic byte pointers to unsigned char pointers. |
95 | 22.1k | inline unsigned char* UCharCast(char* c) { return reinterpret_cast<unsigned char*>(c); } |
96 | 188k | inline unsigned char* UCharCast(unsigned char* c) { return c; } |
97 | 0 | inline unsigned char* UCharCast(signed char* c) { return reinterpret_cast<unsigned char*>(c); } |
98 | 44.3k | inline unsigned char* UCharCast(std::byte* c) { return reinterpret_cast<unsigned char*>(c); } |
99 | 4.73M | inline const unsigned char* UCharCast(const char* c) { return reinterpret_cast<const unsigned char*>(c); } |
100 | 28.0M | inline const unsigned char* UCharCast(const unsigned char* c) { return c; } |
101 | 0 | inline const unsigned char* UCharCast(const signed char* c) { return reinterpret_cast<const unsigned char*>(c); } |
102 | 541M | 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 | 28.1M | 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()}; } auto UCharSpanCast<char const, 18446744073709551615ul>(std::span<char const, 18446744073709551615ul>) Line | Count | Source | 108 | 22.1k | 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()}; } |
auto UCharSpanCast<std::byte const, 18446744073709551615ul>(std::span<std::byte const, 18446744073709551615ul>) Line | Count | Source | 108 | 11.5k | 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()}; } |
auto UCharSpanCast<unsigned char const, 18446744073709551615ul>(std::span<unsigned char const, 18446744073709551615ul>) Line | Count | Source | 108 | 27.9M | 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()}; } |
auto UCharSpanCast<unsigned char, 18446744073709551615ul>(std::span<unsigned char, 18446744073709551615ul>) Line | Count | Source | 108 | 177k | 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()}; } |
auto UCharSpanCast<unsigned char const, 8ul>(std::span<unsigned char const, 8ul>) Line | Count | Source | 108 | 22.1k | 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 | 28.1M | template <typename V> constexpr auto MakeUCharSpan(const V& v) -> decltype(UCharSpanCast(std::span{v})) { return UCharSpanCast(std::span{v}); } Unexecuted instantiation: decltype (UCharSpanCast(std::span{{parm#1}})) MakeUCharSpan<std::span<char const, 18446744073709551615ul> >(std::span<char const, 18446744073709551615ul> const&) decltype (UCharSpanCast(std::span{{parm#1}})) MakeUCharSpan<std::span<std::byte const, 18446744073709551615ul> >(std::span<std::byte const, 18446744073709551615ul> const&) Line | Count | Source | 111 | 11.0k | template <typename V> constexpr auto MakeUCharSpan(const V& v) -> decltype(UCharSpanCast(std::span{v})) { return UCharSpanCast(std::span{v}); } |
Unexecuted instantiation: decltype (UCharSpanCast(std::span{{parm#1}})) MakeUCharSpan<std::basic_string_view<char, std::char_traits<char> > >(std::basic_string_view<char, std::char_traits<char> > const&) decltype (UCharSpanCast(std::span{{parm#1}})) MakeUCharSpan<std::span<unsigned char const, 18446744073709551615ul> >(std::span<unsigned char const, 18446744073709551615ul> const&) Line | Count | Source | 111 | 5.01M | template <typename V> constexpr auto MakeUCharSpan(const V& v) -> decltype(UCharSpanCast(std::span{v})) { return UCharSpanCast(std::span{v}); } |
decltype (UCharSpanCast(std::span{{parm#1}})) MakeUCharSpan<std::vector<unsigned char, std::allocator<unsigned char> > >(std::vector<unsigned char, std::allocator<unsigned char> > const&) Line | Count | Source | 111 | 17.9M | template <typename V> constexpr auto MakeUCharSpan(const V& v) -> decltype(UCharSpanCast(std::span{v})) { return UCharSpanCast(std::span{v}); } |
decltype (UCharSpanCast(std::span{{parm#1}})) MakeUCharSpan<DataStream>(DataStream const&) Line | Count | Source | 111 | 449 | template <typename V> constexpr auto MakeUCharSpan(const V& v) -> decltype(UCharSpanCast(std::span{v})) { return UCharSpanCast(std::span{v}); } |
decltype (UCharSpanCast(std::span{{parm#1}})) MakeUCharSpan<uint256>(uint256 const&) Line | Count | Source | 111 | 4.47M | template <typename V> constexpr auto MakeUCharSpan(const V& v) -> decltype(UCharSpanCast(std::span{v})) { return UCharSpanCast(std::span{v}); } |
decltype (UCharSpanCast(std::span{{parm#1}})) MakeUCharSpan<CScript>(CScript const&) Line | Count | Source | 111 | 443k | template <typename V> constexpr auto MakeUCharSpan(const V& v) -> decltype(UCharSpanCast(std::span{v})) { return UCharSpanCast(std::span{v}); } |
decltype (UCharSpanCast(std::span{{parm#1}})) MakeUCharSpan<std::span<unsigned char, 18446744073709551615ul> >(std::span<unsigned char, 18446744073709551615ul> const&) Line | Count | Source | 111 | 177k | template <typename V> constexpr auto MakeUCharSpan(const V& v) -> decltype(UCharSpanCast(std::span{v})) { return UCharSpanCast(std::span{v}); } |
decltype (UCharSpanCast(std::span{{parm#1}})) MakeUCharSpan<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) Line | Count | Source | 111 | 22.1k | template <typename V> constexpr auto MakeUCharSpan(const V& v) -> decltype(UCharSpanCast(std::span{v})) { return UCharSpanCast(std::span{v}); } |
decltype (UCharSpanCast(std::span{{parm#1}})) MakeUCharSpan<unsigned char [8]>(unsigned char const (&) [8]) Line | Count | Source | 111 | 22.1k | template <typename V> constexpr auto MakeUCharSpan(const V& v) -> decltype(UCharSpanCast(std::span{v})) { return UCharSpanCast(std::span{v}); } |
Unexecuted instantiation: decltype (UCharSpanCast(std::span{{parm#1}})) MakeUCharSpan<XOnlyPubKey>(XOnlyPubKey const&) |
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 |