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