/ src / test / span_tests.cpp
span_tests.cpp
 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      template<typename T> Ignore(T&&) {}
16  };
17  template<typename T>
18  bool Spannable(T&& value, decltype(Span{value})* enable = nullptr)
19  {
20      return true;
21  }
22  bool Spannable(Ignore)
23  {
24      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  BOOST_AUTO_TEST_CASE(span_constructor_sfinae)
62  {
63      BOOST_CHECK(Spannable(std::vector<int>{}));
64      BOOST_CHECK(!Spannable(std::set<int>{}));
65      BOOST_CHECK(!Spannable(std::vector<bool>{}));
66      BOOST_CHECK(Spannable(std::array<int, 3>{}));
67      BOOST_CHECK(Spannable(Span<int>{}));
68      BOOST_CHECK(Spannable("char array"));
69      BOOST_CHECK(Spannable(SpannableYes{}));
70      BOOST_CHECK(!Spannable(SpannableNo{}));
71  }
72  
73  BOOST_AUTO_TEST_SUITE_END()