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()