1 | //===----------------------------------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | // UNSUPPORTED: c++03, c++11, c++14, c++17 |
10 | |
11 | // <iterator> |
12 | // template <class C> constexpr auto ssize(const C& c) |
13 | // -> common_type_t<ptrdiff_t, make_signed_t<decltype(c.size())>>; // C++20 |
14 | // template <class T, ptrdiff_t> constexpr ptrdiff_t ssize(const T (&array)[N]) noexcept; // C++20 |
15 | |
16 | #include <array> |
17 | #include <cassert> |
18 | #include <cstdint> |
19 | #include <initializer_list> |
20 | #include <iterator> |
21 | #include <limits> |
22 | #include <list> |
23 | #include <string_view> |
24 | #include <type_traits> |
25 | #include <vector> |
26 | |
27 | #include "test_macros.h" |
28 | |
29 | // Ignore warning about std::numeric_limits comparisons being tautological. |
30 | TEST_GCC_DIAGNOSTIC_IGNORED("-Wtype-limits" ) |
31 | |
32 | struct short_container { |
33 | std::uint16_t size() const { return 60000; } // not noexcept |
34 | }; |
35 | |
36 | template<typename C> |
37 | void test_container(C& c) |
38 | { |
39 | // Can't say noexcept here because the container might not be |
40 | static_assert( std::is_signed_v<decltype(std::ssize(c))>, "" ); |
41 | assert ( std::ssize(c) == static_cast<decltype(std::ssize(c))>(c.size())); |
42 | } |
43 | |
44 | template<typename C> |
45 | void test_const_container(const C& c) |
46 | { |
47 | // Can't say noexcept here because the container might not be |
48 | static_assert( std::is_signed_v<decltype(std::ssize(c))>, "" ); |
49 | assert ( std::ssize(c) == static_cast<decltype(std::ssize(c))>(c.size())); |
50 | } |
51 | |
52 | template<typename T> |
53 | void test_const_container(const std::initializer_list<T>& c) |
54 | { |
55 | LIBCPP_ASSERT_NOEXCEPT(std::ssize(c)); // our std::ssize is conditionally noexcept |
56 | static_assert( std::is_signed_v<decltype(std::ssize(c))>, "" ); |
57 | assert ( std::ssize(c) == static_cast<decltype(std::ssize(c))>(c.size())); |
58 | } |
59 | |
60 | template<typename T> |
61 | void test_container(std::initializer_list<T>& c) |
62 | { |
63 | LIBCPP_ASSERT_NOEXCEPT(std::ssize(c)); // our std::ssize is conditionally noexcept |
64 | static_assert( std::is_signed_v<decltype(std::ssize(c))>, "" ); |
65 | assert ( std::ssize(c) == static_cast<decltype(std::ssize(c))>(c.size())); |
66 | } |
67 | |
68 | template<typename T, std::size_t Sz> |
69 | void test_const_array(const T (&array)[Sz]) |
70 | { |
71 | ASSERT_NOEXCEPT(std::ssize(array)); |
72 | static_assert( std::is_signed_v<decltype(std::ssize(array))>, "" ); |
73 | assert ( std::ssize(array) == Sz ); |
74 | } |
75 | |
76 | int main(int, char**) |
77 | { |
78 | std::vector<int> v; v.push_back(x: 1); |
79 | std::list<int> l; l.push_back(x: 2); |
80 | std::array<int, 1> a; a[0] = 3; |
81 | std::initializer_list<int> il = { 4 }; |
82 | using SSize = std::common_type_t<std::ptrdiff_t, std::make_signed_t<std::size_t>>; |
83 | test_container ( c&: v ); |
84 | ASSERT_SAME_TYPE(SSize, decltype(std::ssize(v))); |
85 | test_container ( c&: l ); |
86 | ASSERT_SAME_TYPE(SSize, decltype(std::ssize(l))); |
87 | test_container ( c&: a ); |
88 | ASSERT_SAME_TYPE(SSize, decltype(std::ssize(a))); |
89 | test_container ( c&: il ); |
90 | ASSERT_SAME_TYPE(SSize, decltype(std::ssize(il))); |
91 | |
92 | test_const_container ( c: v ); |
93 | test_const_container ( c: l ); |
94 | test_const_container ( c: a ); |
95 | test_const_container ( c: il ); |
96 | |
97 | std::string_view sv{"ABC" }; |
98 | test_container ( c&: sv ); |
99 | ASSERT_SAME_TYPE(SSize, decltype(std::ssize(sv))); |
100 | test_const_container ( c: sv ); |
101 | |
102 | static constexpr int arrA [] { 1, 2, 3 }; |
103 | ASSERT_SAME_TYPE(std::ptrdiff_t, decltype(std::ssize(arrA))); |
104 | static_assert( std::is_signed_v<decltype(std::ssize(arrA))>, "" ); |
105 | test_const_array ( array: arrA ); |
106 | |
107 | // From P1227R2: |
108 | // Note that the code does not just return the std::make_signed variant of |
109 | // the container's size() method, because it's conceivable that a container |
110 | // might choose to represent its size as a uint16_t, supporting up to |
111 | // 65,535 elements, and it would be a disaster for std::ssize() to turn a |
112 | // size of 60,000 into a size of -5,536. |
113 | |
114 | short_container sc; |
115 | // is the return type signed? Is it big enough to hold 60K? |
116 | // is the "signed version" of sc.size() too small? |
117 | static_assert( std::is_signed_v< decltype(std::ssize(cont: sc))>, "" ); |
118 | static_assert( std::numeric_limits< decltype(std::ssize(cont: sc))>::max() > 60000, "" ); |
119 | static_assert( std::numeric_limits<std::make_signed_t<decltype(std:: size(cont: sc))>>::max() < 60000, "" ); |
120 | assert (std::ssize(sc) == 60000); |
121 | LIBCPP_ASSERT_NOT_NOEXCEPT(std::ssize(sc)); |
122 | |
123 | return 0; |
124 | } |
125 | |