brintos

brintos / llvm-project-archived public Read only

0
0
Text · 11.7 KiB · 01a9634 Raw
382 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++2010 11// <functional>12 13// template<class F, class... Args>14//   constexpr unspecified bind_back(F&& f, Args&&... args);15 16#include <functional>17 18#include <cassert>19#include <concepts>20#include <tuple>21#include <utility>22 23#include "callable_types.h"24#include "types.h"25 26constexpr void test_basic_bindings() {27  { // Bind arguments, call without arguments28    {29      auto f = std::bind_back(MakeTuple{});30      assert(f() == std::make_tuple());31    }32    {33      auto f = std::bind_back(MakeTuple{}, Elem<1>{});34      assert(f() == std::make_tuple(Elem<1>{}));35    }36    {37      auto f = std::bind_back(MakeTuple{}, Elem<1>{}, Elem<2>{});38      assert(f() == std::make_tuple(Elem<1>{}, Elem<2>{}));39    }40    {41      auto f = std::bind_back(MakeTuple{}, Elem<1>{}, Elem<2>{}, Elem<3>{});42      assert(f() == std::make_tuple(Elem<1>{}, Elem<2>{}, Elem<3>{}));43    }44  }45 46  { // Bind no arguments, call with arguments47    {48      auto f = std::bind_back(MakeTuple{});49      assert(f(Elem<1>{}) == std::make_tuple(Elem<1>{}));50    }51    {52      auto f = std::bind_back(MakeTuple{});53      assert(f(Elem<1>{}, Elem<2>{}) == std::make_tuple(Elem<1>{}, Elem<2>{}));54    }55    {56      auto f = std::bind_back(MakeTuple{});57      assert(f(Elem<1>{}, Elem<2>{}, Elem<3>{}) == std::make_tuple(Elem<1>{}, Elem<2>{}, Elem<3>{}));58    }59  }60 61  { // Bind arguments, call with arguments62    {63      auto f = std::bind_back(MakeTuple{}, Elem<1>{});64      assert(f(Elem<10>{}) == std::make_tuple(Elem<10>{}, Elem<1>{}));65    }66    {67      auto f = std::bind_back(MakeTuple{}, Elem<1>{}, Elem<2>{});68      assert(f(Elem<10>{}) == std::make_tuple(Elem<10>{}, Elem<1>{}, Elem<2>{}));69    }70    {71      auto f = std::bind_back(MakeTuple{}, Elem<1>{}, Elem<2>{}, Elem<3>{});72      assert(f(Elem<10>{}) == std::make_tuple(Elem<10>{}, Elem<1>{}, Elem<2>{}, Elem<3>{}));73    }74 75    {76      auto f = std::bind_back(MakeTuple{}, Elem<1>{});77      assert(f(Elem<10>{}, Elem<11>{}) == std::make_tuple(Elem<10>{}, Elem<11>{}, Elem<1>{}));78    }79    {80      auto f = std::bind_back(MakeTuple{}, Elem<1>{}, Elem<2>{});81      assert(f(Elem<10>{}, Elem<11>{}) == std::make_tuple(Elem<10>{}, Elem<11>{}, Elem<1>{}, Elem<2>{}));82    }83    {84      auto f = std::bind_back(MakeTuple{}, Elem<1>{}, Elem<2>{}, Elem<3>{});85      assert(f(Elem<10>{}, Elem<11>{}) == std::make_tuple(Elem<10>{}, Elem<11>{}, Elem<1>{}, Elem<2>{}, Elem<3>{}));86    }87    {88      auto f = std::bind_back(MakeTuple{}, Elem<1>{}, Elem<2>{}, Elem<3>{});89      assert(f(Elem<10>{}, Elem<11>{}, Elem<12>{}) ==90             std::make_tuple(Elem<10>{}, Elem<11>{}, Elem<12>{}, Elem<1>{}, Elem<2>{}, Elem<3>{}));91    }92  }93 94  { // Basic tests with fundamental types95    int n         = 2;96    int m         = 1;97    int sum       = 0;98    auto add      = [](int x, int y) { return x + y; };99    auto add_n    = [](int a, int b, int c, int d, int e, int f) { return a + b + c + d + e + f; };100    auto add_ref  = [&](int x, int y) -> int& { return sum = x + y; };101    auto add_rref = [&](int x, int y) -> int&& { return std::move(sum = x + y); };102 103    auto a = std::bind_back(add, m, n);104    assert(a() == 3);105 106    auto b = std::bind_back(add_n, m, n, m, m, m, m);107    assert(b() == 7);108 109    auto c = std::bind_back(add_n, n, m);110    assert(c(1, 1, 1, 1) == 7);111 112    auto d = std::bind_back(add_ref, n, m);113    std::same_as<int&> decltype(auto) dresult(d());114    assert(dresult == 3);115 116    auto e = std::bind_back(add_rref, n, m);117    std::same_as<int&&> decltype(auto) eresult(e());118    assert(eresult == 3);119 120    auto f = std::bind_back(add, n);121    assert(f(3) == 5);122 123    auto g = std::bind_back(add, n, 1);124    assert(g() == 3);125 126    auto h = std::bind_back(add_n, 1, 1, 1);127    assert(h(2, 2, 2) == 9);128 129    auto i = std::bind_back(add_ref, n);130    std::same_as<int&> decltype(auto) iresult(i(5));131    assert(iresult == 7);132 133    auto j = std::bind_back(add_rref, m);134    std::same_as<int&&> decltype(auto) jresult(j(4));135    assert(jresult == 5);136  }137}138 139constexpr void test_edge_cases() {140  { // Make sure we don't treat std::reference_wrapper specially.141    auto sub = [](std::reference_wrapper<int> a, std::reference_wrapper<int> b) { return a.get() - b.get(); };142 143    int i  = 1;144    int j  = 2;145    auto f = std::bind_back(sub, std::ref(i));146    assert(f(std::ref(j)) == 1);147  }148 149  { // Make sure we can call a function that's a pointer to a member function.150    struct MemberFunction {151      constexpr int foo(int x, int y) { return x * y; }152    };153 154    MemberFunction value;155    auto fn = std::bind_back(&MemberFunction::foo, 2, 3);156    assert(fn(value) == 6);157  }158 159  { // Make sure we can call a function that's a pointer to a member object.160    struct MemberObject {161      int obj;162    };163 164    MemberObject value{.obj = 3};165    auto fn = std::bind_back(&MemberObject::obj);166    assert(fn(value) == 3);167  }168}169 170constexpr void test_passing_arguments() {171  { // Make sure that we copy the bound arguments into the unspecified-type.172    auto add = [](int x, int y) { return x + y; };173    int n    = 2;174    auto f   = std::bind_back(add, n, 1);175    n        = 100;176    assert(f() == 3);177  }178 179  { // Make sure we pass the bound arguments to the function object180    // with the right value category.181    {182      auto was_copied = [](CopyMoveInfo info) { return info.copy_kind == CopyMoveInfo::copy; };183      CopyMoveInfo info;184      auto f = std::bind_back(was_copied, info);185      assert(f());186    }187 188    {189      auto was_moved = [](CopyMoveInfo info) { return info.copy_kind == CopyMoveInfo::move; };190      CopyMoveInfo info;191      auto f = std::bind_back(was_moved, info);192      assert(std::move(f)());193    }194  }195}196 197constexpr void test_function_objects() {198  { // Make sure we call the correctly cv-ref qualified operator()199    // based on the value category of the bind_back unspecified-type.200    struct X {201      constexpr int operator()() & { return 1; }202      constexpr int operator()() const& { return 2; }203      constexpr int operator()() && { return 3; }204      constexpr int operator()() const&& { return 4; }205    };206 207    auto f  = std::bind_back(X{});208    using F = decltype(f);209    assert(static_cast<F&>(f)() == 1);210    assert(static_cast<const F&>(f)() == 2);211    assert(static_cast<F&&>(f)() == 3);212    assert(static_cast<const F&&>(f)() == 4);213  }214 215  // Make sure the `bind_back` unspecified-type does not model invocable216  // when the call would select a differently-qualified operator().217  //218  // For example, if the call to `operator()() &` is ill-formed, the call to the unspecified-type219  // should be ill-formed and not fall back to the `operator()() const&` overload.220  { // Make sure we delete the & overload when the underlying call isn't valid.221    {222      struct X {223        void operator()() & = delete;224        void operator()() const&;225        void operator()() &&;226        void operator()() const&&;227      };228 229      using F = decltype(std::bind_back(X{}));230      static_assert(!std::invocable<F&>);231      static_assert(std::invocable<const F&>);232      static_assert(std::invocable<F>);233      static_assert(std::invocable<const F>);234    }235 236    // There's no way to make sure we delete the const& overload when the underlying call isn't valid,237    // so we can't check this one.238 239    { // Make sure we delete the && overload when the underlying call isn't valid.240      struct X {241        void operator()() &;242        void operator()() const&;243        void operator()() && = delete;244        void operator()() const&&;245      };246 247      using F = decltype(std::bind_back(X{}));248      static_assert(std::invocable<F&>);249      static_assert(std::invocable<const F&>);250      static_assert(!std::invocable<F>);251      static_assert(std::invocable<const F>);252    }253 254    { // Make sure we delete the const&& overload when the underlying call isn't valid.255      struct X {256        void operator()() &;257        void operator()() const&;258        void operator()() &&;259        void operator()() const&& = delete;260      };261 262      using F = decltype(std::bind_back(X{}));263      static_assert(std::invocable<F&>);264      static_assert(std::invocable<const F&>);265      static_assert(std::invocable<F>);266      static_assert(!std::invocable<const F>);267    }268  }269 270  { // Extra value category tests271    struct X {};272 273    {274      struct Y {275        void operator()(X&&) const&;276        void operator()(X&&) && = delete;277      };278 279      using F = decltype(std::bind_back(Y{}));280      static_assert(std::invocable<F&, X>);281      static_assert(!std::invocable<F, X>);282    }283 284    {285      struct Y {286        void operator()(const X&) const;287        void operator()(X&&) const = delete;288      };289 290      using F = decltype(std::bind_back(Y{}, X{}));291      static_assert(std::invocable<F&>);292      static_assert(!std::invocable<F>);293    }294  }295}296 297constexpr void test_return_type() {298  {   // Test properties of the constructor of the unspecified-type returned by bind_back.299    { // Test move constructor when function is move only.300      MoveOnlyCallable<bool> value(true);301      auto f = std::bind_back(std::move(value), 1);302      assert(f());303      assert(f(1, 2, 3));304 305      auto f1 = std::move(f);306      assert(!f());307      assert(f1());308      assert(f1(1, 2, 3));309 310      using F = decltype(f);311      static_assert(std::is_move_constructible<F>::value);312      static_assert(!std::is_copy_constructible<F>::value);313      static_assert(!std::is_move_assignable<F>::value);314      static_assert(!std::is_copy_assignable<F>::value);315    }316 317    { // Test move constructor when function is copyable but not assignable.318      CopyCallable<bool> value(true);319      auto f = std::bind_back(value, 1);320      assert(f());321      assert(f(1, 2, 3));322 323      auto f1 = std::move(f);324      assert(!f());325      assert(f1());326      assert(f1(1, 2, 3));327 328      auto f2 = std::bind_back(std::move(value), 1);329      assert(f1());330      assert(f2());331      assert(f2(1, 2, 3));332 333      using F = decltype(f);334      static_assert(std::is_move_constructible<F>::value);335      static_assert(std::is_copy_constructible<F>::value);336      static_assert(!std::is_move_assignable<F>::value);337      static_assert(!std::is_copy_assignable<F>::value);338    }339 340    { // Test constructors when function is copy assignable.341      using F = decltype(std::bind_back(std::declval<CopyAssignableWrapper&>(), 1));342      static_assert(std::is_move_constructible<F>::value);343      static_assert(std::is_copy_constructible<F>::value);344      static_assert(std::is_move_assignable<F>::value);345      static_assert(std::is_copy_assignable<F>::value);346    }347 348    { // Test constructors when function is move assignable only.349      using F = decltype(std::bind_back(std::declval<MoveAssignableWrapper>(), 1));350      static_assert(std::is_move_constructible<F>::value);351      static_assert(!std::is_copy_constructible<F>::value);352      static_assert(std::is_move_assignable<F>::value);353      static_assert(!std::is_copy_assignable<F>::value);354    }355  }356 357  { // Make sure bind_back's unspecified type's operator() is SFINAE-friendly.358    using F = decltype(std::bind_back(std::declval<int (*)(int, int)>(), 1));359    static_assert(!std::is_invocable<F>::value);360    static_assert(std::is_invocable<F, int>::value);361    static_assert(!std::is_invocable<F, void*>::value);362    static_assert(!std::is_invocable<F, int, int>::value);363  }364}365 366constexpr bool test() {367  test_basic_bindings();368  test_edge_cases();369  test_passing_arguments();370  test_function_objects();371  test_return_type();372 373  return true;374}375 376int main(int, char**) {377  test();378  static_assert(test());379 380  return 0;381}382