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 // std::ranges::size 12 13 #include <ranges> 14 15 #include <cassert> 16 #include "test_macros.h" 17 #include "test_iterators.h" 18 19 using RangeSizeT = decltype(std::ranges::size); 20 21 static_assert(!std::is_invocable_v<RangeSizeT, int[]>); 22 static_assert( std::is_invocable_v<RangeSizeT, int[1]>); 23 static_assert( std::is_invocable_v<RangeSizeT, int (&&)[1]>); 24 static_assert( std::is_invocable_v<RangeSizeT, int (&)[1]>); 25 26 struct Incomplete; 27 static_assert(!std::is_invocable_v<RangeSizeT, Incomplete[]>); 28 static_assert(!std::is_invocable_v<RangeSizeT, Incomplete(&)[]>); 29 static_assert(!std::is_invocable_v<RangeSizeT, Incomplete(&&)[]>); 30 31 extern Incomplete array_of_incomplete[42]; 32 static_assert(std::ranges::size(array_of_incomplete) == 42); 33 static_assert(std::ranges::size(std::move(array_of_incomplete)) == 42); 34 static_assert(std::ranges::size(std::as_const(array_of_incomplete)) == 42); 35 static_assert(std::ranges::size(static_cast<const Incomplete(&&)[42]>(array_of_incomplete)) == 42); 36 37 struct SizeMember { 38 constexpr size_t size() { return 42; } 39 }; 40 41 struct StaticSizeMember { 42 constexpr static size_t size() { return 42; } 43 }; 44 45 static_assert(!std::is_invocable_v<RangeSizeT, const SizeMember>); 46 47 struct SizeFunction { 48 friend constexpr size_t size(SizeFunction) { return 42; } 49 }; 50 51 // Make sure the size member is preferred. 52 struct SizeMemberAndFunction { 53 constexpr size_t size() { return 42; } 54 friend constexpr size_t size(SizeMemberAndFunction) { return 0; } 55 }; 56 57 bool constexpr testArrayType() { 58 int a[4]; 59 int b[1]; 60 SizeMember c[4]; 61 SizeFunction d[4]; 62 63 assert(std::ranges::size(a) == 4); 64 ASSERT_SAME_TYPE(decltype(std::ranges::size(a)), size_t); 65 assert(std::ranges::size(b) == 1); 66 ASSERT_SAME_TYPE(decltype(std::ranges::size(b)), size_t); 67 assert(std::ranges::size(c) == 4); 68 ASSERT_SAME_TYPE(decltype(std::ranges::size(c)), size_t); 69 assert(std::ranges::size(d) == 4); 70 ASSERT_SAME_TYPE(decltype(std::ranges::size(d)), size_t); 71 72 return true; 73 } 74 75 struct SizeMemberConst { 76 constexpr size_t size() const { return 42; } 77 }; 78 79 struct SizeMemberSigned { 80 constexpr long size() { return 42; } 81 }; 82 83 bool constexpr testHasSizeMember() { 84 assert(std::ranges::size(SizeMember()) == 42); 85 ASSERT_SAME_TYPE(decltype(std::ranges::size(SizeMember())), size_t); 86 87 const SizeMemberConst sizeMemberConst; 88 assert(std::ranges::size(sizeMemberConst) == 42); 89 90 assert(std::ranges::size(SizeMemberAndFunction()) == 42); 91 92 assert(std::ranges::size(SizeMemberSigned()) == 42); 93 ASSERT_SAME_TYPE(decltype(std::ranges::size(SizeMemberSigned())), long); 94 95 assert(std::ranges::size(StaticSizeMember()) == 42); 96 ASSERT_SAME_TYPE(decltype(std::ranges::size(StaticSizeMember())), size_t); 97 98 return true; 99 } 100 101 struct MoveOnlySizeFunction { 102 MoveOnlySizeFunction() = default; 103 MoveOnlySizeFunction(MoveOnlySizeFunction &&) = default; 104 MoveOnlySizeFunction(MoveOnlySizeFunction const&) = delete; 105 106 friend constexpr size_t size(MoveOnlySizeFunction) { return 42; } 107 }; 108 109 enum EnumSizeFunction { 110 a, b 111 }; 112 113 constexpr size_t size(EnumSizeFunction) { return 42; } 114 115 struct SizeFunctionConst { 116 friend constexpr size_t size(const SizeFunctionConst) { return 42; } 117 }; 118 119 struct SizeFunctionRef { 120 friend constexpr size_t size(SizeFunctionRef&) { return 42; } 121 }; 122 123 struct SizeFunctionConstRef { 124 friend constexpr size_t size(SizeFunctionConstRef const&) { return 42; } 125 }; 126 127 struct SizeFunctionSigned { 128 friend constexpr long size(SizeFunctionSigned) { return 42; } 129 }; 130 131 bool constexpr testHasSizeFunction() { 132 assert(std::ranges::size(SizeFunction()) == 42); 133 ASSERT_SAME_TYPE(decltype(std::ranges::size(SizeFunction())), size_t); 134 static_assert(!std::is_invocable_v<RangeSizeT, MoveOnlySizeFunction>); 135 assert(std::ranges::size(EnumSizeFunction()) == 42); 136 assert(std::ranges::size(SizeFunctionConst()) == 42); 137 138 SizeFunctionRef a; 139 assert(std::ranges::size(a) == 42); 140 141 const SizeFunctionConstRef b; 142 assert(std::ranges::size(b) == 42); 143 144 assert(std::ranges::size(SizeFunctionSigned()) == 42); 145 ASSERT_SAME_TYPE(decltype(std::ranges::size(SizeFunctionSigned())), long); 146 147 return true; 148 } 149 150 struct Empty { }; 151 static_assert(!std::is_invocable_v<RangeSizeT, Empty>); 152 153 struct InvalidReturnTypeMember { 154 Empty size(); 155 }; 156 157 struct InvalidReturnTypeFunction { 158 friend Empty size(InvalidReturnTypeFunction); 159 }; 160 161 struct Convertible { 162 operator size_t(); 163 }; 164 165 struct ConvertibleReturnTypeMember { 166 Convertible size(); 167 }; 168 169 struct ConvertibleReturnTypeFunction { 170 friend Convertible size(ConvertibleReturnTypeFunction); 171 }; 172 173 struct BoolReturnTypeMember { 174 bool size() const; 175 }; 176 177 struct BoolReturnTypeFunction { 178 friend bool size(BoolReturnTypeFunction const&); 179 }; 180 181 static_assert(!std::is_invocable_v<RangeSizeT, InvalidReturnTypeMember>); 182 static_assert(!std::is_invocable_v<RangeSizeT, InvalidReturnTypeFunction>); 183 static_assert( std::is_invocable_v<RangeSizeT, InvalidReturnTypeMember (&)[4]>); 184 static_assert( std::is_invocable_v<RangeSizeT, InvalidReturnTypeFunction (&)[4]>); 185 static_assert(!std::is_invocable_v<RangeSizeT, ConvertibleReturnTypeMember>); 186 static_assert(!std::is_invocable_v<RangeSizeT, ConvertibleReturnTypeFunction>); 187 static_assert(!std::is_invocable_v<RangeSizeT, BoolReturnTypeMember const&>); 188 static_assert(!std::is_invocable_v<RangeSizeT, BoolReturnTypeFunction const&>); 189 190 struct SizeMemberDisabled { 191 size_t size() { return 42; } 192 }; 193 194 template <> 195 inline constexpr bool std::ranges::disable_sized_range<SizeMemberDisabled> = true; 196 197 struct ImproperlyDisabledMember { 198 size_t size() const { return 42; } 199 }; 200 201 // Intentionally disabling "const ConstSizeMemberDisabled". This doesn't disable anything 202 // because T is always uncvrefed before being checked. 203 template <> 204 inline constexpr bool std::ranges::disable_sized_range<const ImproperlyDisabledMember> = true; 205 206 struct SizeFunctionDisabled { 207 friend size_t size(SizeFunctionDisabled) { return 42; } 208 }; 209 210 template <> 211 inline constexpr bool std::ranges::disable_sized_range<SizeFunctionDisabled> = true; 212 213 struct ImproperlyDisabledFunction { 214 friend size_t size(ImproperlyDisabledFunction const&) { return 42; } 215 }; 216 217 template <> 218 inline constexpr bool std::ranges::disable_sized_range<const ImproperlyDisabledFunction> = true; 219 220 static_assert( std::is_invocable_v<RangeSizeT, ImproperlyDisabledMember&>); 221 static_assert( std::is_invocable_v<RangeSizeT, const ImproperlyDisabledMember&>); 222 static_assert(!std::is_invocable_v<RangeSizeT, ImproperlyDisabledFunction&>); 223 static_assert( std::is_invocable_v<RangeSizeT, const ImproperlyDisabledFunction&>); 224 225 // No begin end. 226 struct HasMinusOperator { 227 friend constexpr size_t operator-(HasMinusOperator, HasMinusOperator) { return 2; } 228 }; 229 static_assert(!std::is_invocable_v<RangeSizeT, HasMinusOperator>); 230 231 struct HasMinusBeginEnd { 232 struct sentinel { 233 friend bool operator==(sentinel, forward_iterator<int*>); 234 friend constexpr std::ptrdiff_t operator-(const sentinel, const forward_iterator<int*>) { return 2; } 235 friend constexpr std::ptrdiff_t operator-(const forward_iterator<int*>, const sentinel) { return 2; } 236 }; 237 238 friend constexpr forward_iterator<int*> begin(HasMinusBeginEnd) { return {}; } 239 friend constexpr sentinel end(HasMinusBeginEnd) { return {}; } 240 }; 241 242 struct other_forward_iterator : forward_iterator<int*> { }; 243 244 struct InvalidMinusBeginEnd { 245 struct sentinel { 246 friend bool operator==(sentinel, other_forward_iterator); 247 friend constexpr std::ptrdiff_t operator-(const sentinel, const other_forward_iterator) { return 2; } 248 friend constexpr std::ptrdiff_t operator-(const other_forward_iterator, const sentinel) { return 2; } 249 }; 250 251 friend constexpr other_forward_iterator begin(InvalidMinusBeginEnd) { return {}; } 252 friend constexpr sentinel end(InvalidMinusBeginEnd) { return {}; } 253 }; 254 255 // short is integer-like, but it is not other_forward_iterator's difference_type. 256 static_assert(!std::same_as<other_forward_iterator::difference_type, short>); 257 static_assert(!std::is_invocable_v<RangeSizeT, InvalidMinusBeginEnd>); 258 259 struct RandomAccessRange { 260 struct sentinel { 261 friend bool operator==(sentinel, random_access_iterator<int*>); 262 friend constexpr std::ptrdiff_t operator-(const sentinel, const random_access_iterator<int*>) { return 2; } 263 friend constexpr std::ptrdiff_t operator-(const random_access_iterator<int*>, const sentinel) { return 2; } 264 }; 265 266 constexpr random_access_iterator<int*> begin() { return {}; } 267 constexpr sentinel end() { return {}; } 268 }; 269 270 struct IntPtrBeginAndEnd { 271 int buff[8]; 272 constexpr int* begin() { return buff; } 273 constexpr int* end() { return buff + 8; } 274 }; 275 276 struct DisabledSizeRangeWithBeginEnd { 277 int buff[8]; 278 constexpr int* begin() { return buff; } 279 constexpr int* end() { return buff + 8; } 280 constexpr size_t size() { return 1; } 281 }; 282 283 template <> 284 inline constexpr bool std::ranges::disable_sized_range<DisabledSizeRangeWithBeginEnd> = true; 285 286 struct SizeBeginAndEndMembers { 287 int buff[8]; 288 constexpr int* begin() { return buff; } 289 constexpr int* end() { return buff + 8; } 290 constexpr size_t size() { return 1; } 291 }; 292 293 constexpr bool testRanges() { 294 HasMinusBeginEnd a; 295 assert(std::ranges::size(a) == 2); 296 // Ensure that this is converted to an *unsigned* type. 297 ASSERT_SAME_TYPE(decltype(std::ranges::size(a)), size_t); 298 299 IntPtrBeginAndEnd b; 300 assert(std::ranges::size(b) == 8); 301 302 DisabledSizeRangeWithBeginEnd c; 303 assert(std::ranges::size(c) == 8); 304 305 RandomAccessRange d; 306 assert(std::ranges::size(d) == 2); 307 ASSERT_SAME_TYPE(decltype(std::ranges::size(d)), size_t); 308 309 SizeBeginAndEndMembers e; 310 assert(std::ranges::size(e) == 1); 311 312 return true; 313 } 314 315 // Test ADL-proofing. 316 struct Incomplete; 317 template<class T> struct Holder { T t; }; 318 static_assert(!std::is_invocable_v<RangeSizeT, Holder<Incomplete>*>); 319 static_assert(!std::is_invocable_v<RangeSizeT, Holder<Incomplete>*&>); 320 321 int main(int, char**) { 322 testArrayType(); 323 static_assert(testArrayType()); 324 325 testHasSizeMember(); 326 static_assert(testHasSizeMember()); 327 328 testHasSizeFunction(); 329 static_assert(testHasSizeFunction()); 330 331 testRanges(); 332 static_assert(testRanges()); 333 334 return 0; 335 } 336