brintos

brintos / llvm-project-archived public Read only

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