brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.5 KiB · 688049c Raw
311 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++17, c++20, c++2310 11// <functional>12 13// template<auto f> constexpr unspecified not_fn() noexcept;14 15#include <functional>16 17#include <bit>18#include <cassert>19#include <concepts>20#include <type_traits>21#include <utility>22 23#include "test_macros.h"24 25class BooleanTestable {26  bool val_;27 28public:29  constexpr explicit BooleanTestable(bool val) : val_(val) {}30  constexpr operator bool() const { return val_; }31  constexpr BooleanTestable operator!() const { return BooleanTestable{!val_}; }32};33 34LIBCPP_STATIC_ASSERT(std::__boolean_testable<BooleanTestable>);35 36class FakeBool {37  int val_;38 39public:40  constexpr FakeBool(int val) : val_(val) {}41  constexpr FakeBool operator!() const { return FakeBool{-val_}; }42  constexpr bool operator==(int other) const { return val_ == other; }43};44 45template <bool IsNoexcept>46struct MaybeNoexceptFn {47  bool operator()() const noexcept(IsNoexcept); // not defined48};49 50template <bool IsNoexcept>51struct MaybeNoexceptNegation {52  bool operator!() noexcept(IsNoexcept); // not defined53};54 55template <bool IsNoexcept>56MaybeNoexceptNegation<IsNoexcept> maybe_noexcept_negation() noexcept {57  return {};58}59 60constexpr void basic_tests() {61  { // Test constant functions62    auto false_fn = std::not_fn<std::false_type{}>();63    assert(false_fn());64 65    auto true_fn = std::not_fn<std::true_type{}>();66    assert(!true_fn());67 68    static_assert(noexcept(std::not_fn<std::false_type{}>()));69    static_assert(noexcept(std::not_fn<std::true_type{}>()));70  }71 72  { // Test function with one argument73    auto is_odd = std::not_fn<[](auto x) { return x % 2 == 0; }>();74    assert(is_odd(1));75    assert(!is_odd(2));76    assert(is_odd(3));77    assert(!is_odd(4));78    assert(is_odd(5));79  }80 81  { // Test function with multiple arguments82    auto at_least_10 = [](auto... vals) { return (vals + ... + 0) >= 10; };83    auto at_most_9   = std::not_fn<at_least_10>();84    assert(at_most_9());85    assert(at_most_9(1));86    assert(at_most_9(1, 2, 3, 4, -1));87    assert(at_most_9(3, 3, 2, 1, -2));88    assert(!at_most_9(10, -1, 2));89    assert(!at_most_9(5, 5));90    static_assert(noexcept(std::not_fn<at_least_10>()));91  }92 93  { // Test function that returns boolean-testable type other than bool94    auto is_product_even = [](auto... vals) { return BooleanTestable{(vals * ... * 1) % 2 == 0}; };95    auto is_product_odd  = std::not_fn<is_product_even>();96    assert(is_product_odd());97    assert(is_product_odd(1, 3, 5, 9));98    assert(is_product_odd(3, 3, 3, 3));99    assert(!is_product_odd(3, 5, 9, 11, 0));100    assert(!is_product_odd(11, 7, 5, 3, 2));101    static_assert(noexcept(std::not_fn<is_product_even>()));102  }103 104  { // Test function that returns non-boolean-testable type105    auto sum         = [](auto... vals) -> FakeBool { return (vals + ... + 0); };106    auto negated_sum = std::not_fn<sum>();107    assert(negated_sum() == 0);108    assert(negated_sum(3) == -3);109    assert(negated_sum(4, 5, 1, 3) == -13);110    assert(negated_sum(4, 2, 5, 6, 1) == -18);111    assert(negated_sum(-1, 3, 2, -8) == 4);112    static_assert(noexcept(std::not_fn<sum>()));113  }114 115  { // Test member pointers116    struct MemberPointerTester {117      bool value = true;118      constexpr bool not_value() const { return !value; }119      constexpr bool value_and(bool other) noexcept { return value && other; }120    };121 122    MemberPointerTester tester;123 124    auto not_mem_object = std::not_fn<&MemberPointerTester::value>();125    assert(!not_mem_object(tester));126    assert(!not_mem_object(std::as_const(tester)));127    static_assert(noexcept(not_mem_object(tester)));128    static_assert(noexcept(not_mem_object(std::as_const(tester))));129 130    auto not_nullary_mem_fn = std::not_fn<&MemberPointerTester::not_value>();131    assert(not_nullary_mem_fn(tester));132    static_assert(!noexcept(not_nullary_mem_fn(tester)));133 134    auto not_unary_mem_fn = std::not_fn<&MemberPointerTester::value_and>();135    assert(not_unary_mem_fn(tester, false));136    static_assert(noexcept(not_unary_mem_fn(tester, false)));137    static_assert(!std::is_invocable_v<decltype(not_unary_mem_fn), const MemberPointerTester&, bool>);138  }139}140 141constexpr void test_perfect_forwarding_call_wrapper() {142  { // Make sure we call the correctly cv-ref qualified operator()143    // based on the value category of the not_fn<NTTP> unspecified-type.144    struct X {145      constexpr FakeBool operator()() & { return 1; }146      constexpr FakeBool operator()() const& { return 2; }147      constexpr FakeBool operator()() && { return 3; }148      constexpr FakeBool operator()() const&& { return 4; }149    };150 151    auto f  = std::not_fn<X{}>();152    using F = decltype(f);153    assert(static_cast<F&>(f)() == -2);154    assert(static_cast<const F&>(f)() == -2);155    assert(static_cast<F&&>(f)() == -2);156    assert(static_cast<const F&&>(f)() == -2);157  }158 159  // Call to `not_fn<NTTP>` unspecified-type's operator() should always result in call to the const& overload of the underlying function object.160  {161    { // Make sure unspecified-type is still callable when we delete the & overload.162      struct X {163        FakeBool operator()() & = delete;164        FakeBool operator()() const&;165        FakeBool operator()() &&;166        FakeBool operator()() const&&;167      };168 169      using F = decltype(std::not_fn<X{}>());170      static_assert(std::invocable<F&>);171      static_assert(std::invocable<const F&>);172      static_assert(std::invocable<F>);173      static_assert(std::invocable<const F>);174    }175 176    { // Make sure unspecified-type is not callable when we delete the const& overload.177      struct X {178        FakeBool operator()() &;179        FakeBool operator()() const& = delete;180        FakeBool operator()() &&;181        FakeBool operator()() const&&;182      };183 184      using F = decltype(std::not_fn<X{}>());185      static_assert(!std::invocable<F&>);186      static_assert(!std::invocable<const F&>);187      static_assert(!std::invocable<F>);188      static_assert(!std::invocable<const F>);189    }190 191    { // Make sure unspecified-type is still callable when we delete the && overload.192      struct X {193        FakeBool operator()() &;194        FakeBool operator()() const&;195        FakeBool operator()() && = delete;196        FakeBool operator()() const&&;197      };198 199      using F = decltype(std::not_fn<X{}>());200      static_assert(std::invocable<F&>);201      static_assert(std::invocable<const F&>);202      static_assert(std::invocable<F>);203      static_assert(std::invocable<const F>);204    }205 206    { // Make sure unspecified-type is still callable when we delete the const&& overload.207      struct X {208        FakeBool operator()() &;209        FakeBool operator()() const&;210        FakeBool operator()() &&;211        FakeBool operator()() const&& = delete;212      };213 214      using F = decltype(std::not_fn<X{}>());215      static_assert(std::invocable<F&>);216      static_assert(std::invocable<const F&>);217      static_assert(std::invocable<F>);218      static_assert(std::invocable<const F>);219    }220  }221 222  { // Test perfect forwarding223    auto f = [](int& val) {224      val = 5;225      return false;226    };227 228    auto not_f = std::not_fn<f>();229    int val    = 0;230    assert(not_f(val));231    assert(val == 5);232 233    using NotF = decltype(not_f);234    static_assert(std::invocable<NotF, int&>);235    static_assert(!std::invocable<NotF, int>);236  }237}238 239constexpr void test_return_type() {240  { // Test constructors and assignment operators241    struct IsPowerOfTwo {242      constexpr bool operator()(unsigned int x) const { return std::has_single_bit(x); }243    };244 245    auto is_not_power_of_2 = std::not_fn<IsPowerOfTwo{}>();246    assert(is_not_power_of_2(5));247    assert(!is_not_power_of_2(4));248 249    auto moved = std::move(is_not_power_of_2);250    assert(moved(5));251    assert(!moved(4));252 253    auto copied = is_not_power_of_2;254    assert(copied(7));255    assert(!copied(8));256 257    moved = std::move(copied);258    assert(copied(9));259    assert(!copied(16));260 261    copied = moved;262    assert(copied(11));263    assert(!copied(32));264  }265 266  { // Make sure `not_fn<NTTP>` unspecified-type's operator() is SFINAE-friendly.267    using F = decltype(std::not_fn<[](int x) { return !x; }>());268    static_assert(!std::is_invocable<F>::value);269    static_assert(std::is_invocable<F, int>::value);270    static_assert(!std::is_invocable<F, void*>::value);271    static_assert(!std::is_invocable<F, int, int>::value);272  }273 274  { // Test noexceptness275    auto always_noexcept = std::not_fn<MaybeNoexceptFn<true>{}>();276    static_assert(noexcept(always_noexcept()));277 278    auto never_noexcept = std::not_fn<MaybeNoexceptFn<false>{}>();279    static_assert(!noexcept(never_noexcept()));280 281    auto always_noexcept_negation = std::not_fn<maybe_noexcept_negation<true>>();282    static_assert(noexcept(always_noexcept_negation()));283 284    auto never_noexcept_negation = std::not_fn<maybe_noexcept_negation<false>>();285    static_assert(!noexcept(never_noexcept_negation()));286  }287 288  { // Test calling volatile wrapper289    using NotFn = decltype(std::not_fn<std::false_type{}>());290    static_assert(!std::invocable<volatile NotFn&>);291    static_assert(!std::invocable<const volatile NotFn&>);292    static_assert(!std::invocable<volatile NotFn>);293    static_assert(!std::invocable<const volatile NotFn>);294  }295}296 297constexpr bool test() {298  basic_tests();299  test_perfect_forwarding_call_wrapper();300  test_return_type();301 302  return true;303}304 305int main(int, char**) {306  test();307  static_assert(test());308 309  return 0;310}311