LCOV - code coverage report
Current view: top level - src - span.h (source / functions) Coverage Total Hit
Test: total_coverage.info Lines: 100.0 % 12 12
Test Date: 2025-03-28 05:06:44 Functions: 97.2 % 71 69
Branches: 75.0 % 8 6

             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
        

Generated by: LCOV version 2.0-1