Branch data Line data Source code
1 : : // Copyright (c) 2023 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 : : #include <span.h>
6 : :
7 : : #include <boost/test/unit_test.hpp>
8 : : #include <array>
9 : : #include <set>
10 : : #include <vector>
11 : :
12 : : namespace {
13 : : struct Ignore
14 : : {
15 [ + - + - : 3 : template<typename T> Ignore(T&&) {}
+ - ]
16 : : };
17 : : template<typename T>
18 : 5 : bool Spannable(T&& value, decltype(Span{value})* enable = nullptr)
19 : : {
20 : 5 : return true;
21 : : }
22 : 3 : bool Spannable(Ignore)
23 : : {
24 : 3 : return false;
25 : : }
26 : :
27 : : #if defined(__clang__)
28 : : # pragma clang diagnostic push
29 : : # pragma clang diagnostic ignored "-Wunneeded-member-function"
30 : : # pragma clang diagnostic ignored "-Wunused-member-function"
31 : : #endif
32 : : struct SpannableYes
33 : : {
34 : : int* data();
35 : : size_t size();
36 : : };
37 : : struct SpannableNo
38 : : {
39 : : void* data();
40 : : size_t size();
41 : : };
42 : : #if defined(__clang__)
43 : : # pragma clang diagnostic pop
44 : : #endif
45 : : } // namespace
46 : :
47 : : BOOST_AUTO_TEST_SUITE(span_tests)
48 : :
49 : : // Make sure template Span template deduction guides accurately enable calls to
50 : : // Span constructor overloads that work, and disable calls to constructor overloads that
51 : : // don't work. This makes it is possible to use the Span constructor in a SFINAE
52 : : // contexts like in the Spannable function above to detect whether types are or
53 : : // aren't compatible with Spans at compile time.
54 : : //
55 : : // Previously there was a bug where writing a SFINAE check for vector<bool> was
56 : : // not possible, because in libstdc++ vector<bool> has a data() member
57 : : // returning void*, and the Span template guide ignored the data() return value,
58 : : // so the template substitution would succeed, but the constructor would fail,
59 : : // resulting in a fatal compile error, rather than a SFINAE error that could be
60 : : // handled.
61 [ + - + - : 7 : BOOST_AUTO_TEST_CASE(span_constructor_sfinae)
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- ]
62 : : {
63 [ + - ]: 2 : BOOST_CHECK(Spannable(std::vector<int>{}));
64 [ + - ]: 2 : BOOST_CHECK(!Spannable(std::set<int>{}));
65 [ + - ]: 2 : BOOST_CHECK(!Spannable(std::vector<bool>{}));
66 [ + - ]: 2 : BOOST_CHECK(Spannable(std::array<int, 3>{}));
67 [ + - ]: 2 : BOOST_CHECK(Spannable(Span<int>{}));
68 [ + - ]: 2 : BOOST_CHECK(Spannable("char array"));
69 [ + - ]: 2 : BOOST_CHECK(Spannable(SpannableYes{}));
70 [ + - ]: 2 : BOOST_CHECK(!Spannable(SpannableNo{}));
71 : 1 : }
72 : :
73 : : BOOST_AUTO_TEST_SUITE_END()
|