1 // Copyright 2021 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef LIB_STDCOMPAT_INTERNAL_FUNCTIONAL_H_
6 #define LIB_STDCOMPAT_INTERNAL_FUNCTIONAL_H_
7
8 #include <cstddef>
9 #include <functional>
10
11 #include "../type_traits.h"
12 #include "../utility.h"
13
14 namespace cpp17 {
15 namespace internal {
16
17 // Definitions for the invoke functions in internal/type_traits.h.
18 // These collectively implement INVOKE from [func.require] ¶ 1.
19 template <typename MemFn, typename Class, typename T, typename... Args>
20 constexpr auto invoke(MemFn Class::*f, T&& obj, Args&&... args)
21 -> std::enable_if_t<invoke_pmf_base<MemFn, Class, T>,
22 decltype((std::forward<T>(obj).*f)(std::forward<Args>(args)...))> {
23 return (std::forward<T>(obj).*f)(std::forward<Args>(args)...);
24 }
25
26 template <typename MemFn, typename Class, typename T, typename... Args>
27 constexpr auto invoke(MemFn Class::*f, T&& obj, Args&&... args)
28 -> std::enable_if_t<invoke_pmf_refwrap<MemFn, Class, T>,
29 decltype((obj.get().*f)(std::forward<Args>(args)...))> {
30 return (obj.get().*f)(std::forward<Args>(args)...);
31 }
32
33 template <typename MemFn, typename Class, typename T, typename... Args>
34 constexpr auto invoke(MemFn Class::*f, T&& obj, Args&&... args)
35 -> std::enable_if_t<invoke_pmf_other<MemFn, Class, T>,
36 decltype(((*std::forward<T>(obj)).*f)(std::forward<Args>(args)...))> {
37 return (*std::forward<T>(obj).*f)(std::forward<Args>(args)...);
38 }
39
40 template <typename MemObj, typename Class, typename T>
41 constexpr auto invoke(MemObj Class::*f, T&& obj)
42 -> std::enable_if_t<invoke_pmd_base<MemObj, Class, T>, decltype(std::forward<T>(obj).*f)> {
43 return std::forward<T>(obj).*f;
44 }
45
46 template <typename MemObj, typename Class, typename T>
47 constexpr auto invoke(MemObj Class::*f, T&& obj)
48 -> std::enable_if_t<invoke_pmd_refwrap<MemObj, Class, T>, decltype(obj.get().*f)> {
49 return obj.get().*f;
50 }
51
52 template <typename MemObj, typename Class, typename T>
53 constexpr auto invoke(MemObj Class::*f, T&& obj)
54 -> std::enable_if_t<invoke_pmd_other<MemObj, Class, T>, decltype((*std::forward<T>(obj)).*f)> {
55 return (*std::forward<T>(obj)).*f;
56 }
57
58 template <typename F, typename... Args>
59 constexpr auto invoke(F&& f, Args&&... args)
60 -> decltype(std::forward<F>(f)(std::forward<Args>(args)...)) {
61 return std::forward<F>(f)(std::forward<Args>(args)...);
62 }
63
64 } // namespace internal
65 } // namespace cpp17
66
67 namespace cpp20 {
68 namespace internal {
69
70 template <typename Invocable, typename BoundTuple, std::size_t... Is, typename... CallArgs>
decltype(auto)71 constexpr decltype(auto) invoke_with_bound(Invocable&& invocable, BoundTuple&& bound_args,
72 std::index_sequence<Is...>, CallArgs&&... call_args) {
73 return ::cpp17::internal::invoke(std::forward<Invocable>(invocable),
74 std::get<Is>(std::forward<BoundTuple>(bound_args))...,
75 std::forward<CallArgs>(call_args)...);
76 }
77
78 template <typename FD, typename... BoundArgs>
79 class front_binder {
80 using bound_indices = std::index_sequence_for<BoundArgs...>;
81
82 public:
83 template <typename F, typename... Args>
front_binder(cpp17::in_place_t,F && f,Args &&...args)84 explicit constexpr front_binder(cpp17::in_place_t, F&& f, Args&&... args) noexcept(
85 cpp17::conjunction_v<std::is_nothrow_constructible<FD, F>,
86 std::is_nothrow_constructible<BoundArgs, Args>...>)
87 : fd_(std::forward<F>(f)), bound_args_(std::forward<Args>(args)...) {
88 // [func.bind.front] ¶ 2
89 static_assert(cpp17::is_constructible_v<FD, F>,
90 "Must be able to construct decayed callable type.");
91 static_assert(cpp17::is_move_constructible_v<FD>, "Callable type must be move-constructible.");
92 static_assert(cpp17::conjunction_v<std::is_constructible<BoundArgs, Args>...>,
93 "Must be able to construct decayed bound argument types.");
94 static_assert(cpp17::conjunction_v<std::is_move_constructible<BoundArgs>...>,
95 "Bound argument types must be move-constructible.");
96 }
97
98 constexpr front_binder(const front_binder&) = default;
99 constexpr front_binder& operator=(const front_binder&) = default;
100 constexpr front_binder(front_binder&&) noexcept = default;
101 constexpr front_binder& operator=(front_binder&&) noexcept = default;
102
103 template <typename... CallArgs>
104 constexpr cpp17::invoke_result_t<FD&, BoundArgs&..., CallArgs&&...>
operator()105 operator()(CallArgs&&... call_args) & noexcept(
106 cpp17::is_nothrow_invocable_v<FD&, BoundArgs&..., CallArgs&&...>) {
107 return invoke_with_bound(fd_, bound_args_, bound_indices(),
108 std::forward<CallArgs>(call_args)...);
109 }
110
111 template <typename... CallArgs>
112 constexpr cpp17::invoke_result_t<const FD&, const BoundArgs&..., CallArgs&&...>
operator()113 operator()(CallArgs&&... call_args) const& noexcept(
114 cpp17::is_nothrow_invocable_v<const FD&, const BoundArgs&..., CallArgs&&...>) {
115 return invoke_with_bound(fd_, bound_args_, bound_indices(),
116 std::forward<CallArgs>(call_args)...);
117 }
118
119 template <typename... CallArgs>
120 constexpr cpp17::invoke_result_t<FD&&, BoundArgs&&..., CallArgs&&...>
operator()121 operator()(CallArgs&&... call_args) && noexcept(
122 cpp17::is_nothrow_invocable_v<FD&&, BoundArgs&&..., CallArgs&&...>) {
123 return invoke_with_bound(std::move(fd_), std::move(bound_args_), bound_indices(),
124 std::forward<CallArgs>(call_args)...);
125 }
126
127 template <typename... CallArgs>
128 constexpr cpp17::invoke_result_t<const FD&&, const BoundArgs&&..., CallArgs&&...>
operator()129 operator()(CallArgs&&... call_args) const&& noexcept(
130 cpp17::is_nothrow_invocable_v<const FD&&, const BoundArgs&&..., CallArgs&&...>) {
131 return invoke_with_bound(std::move(fd_), std::move(bound_args_), bound_indices(),
132 std::forward<CallArgs>(call_args)...);
133 }
134
135 private:
136 FD fd_;
137 std::tuple<BoundArgs...> bound_args_;
138 };
139
140 template <typename F, typename... BoundArgs>
141 using front_binder_t = front_binder<std::decay_t<F>, std::decay_t<BoundArgs>...>;
142
143 } // namespace internal
144 } // namespace cpp20
145
146 #endif // LIB_STDCOMPAT_INTERNAL_FUNCTIONAL_H_
147