xref: /aosp_15_r20/external/webrtc/rtc_base/containers/invoke.h (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
2  *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 // This implementation is borrowed from Chromium.
12 
13 #ifndef RTC_BASE_CONTAINERS_INVOKE_H_
14 #define RTC_BASE_CONTAINERS_INVOKE_H_
15 
16 #include <type_traits>
17 #include <utility>
18 
19 namespace webrtc {
20 
21 namespace invoke_internal {
22 
23 // Helper struct and alias to deduce the class type from a member function
24 // pointer or member object pointer.
25 template <typename DecayedF>
26 struct member_pointer_class {};
27 
28 template <typename ReturnT, typename ClassT>
29 struct member_pointer_class<ReturnT ClassT::*> {
30   using type = ClassT;
31 };
32 
33 template <typename DecayedF>
34 using member_pointer_class_t = typename member_pointer_class<DecayedF>::type;
35 
36 // Utility struct to detect specializations of std::reference_wrapper.
37 template <typename T>
38 struct is_reference_wrapper : std::false_type {};
39 
40 template <typename T>
41 struct is_reference_wrapper<std::reference_wrapper<T>> : std::true_type {};
42 
43 // Small helpers used below in invoke_internal::invoke to make the SFINAE more
44 // concise.
45 template <typename F>
46 const bool& IsMemFunPtr =
47     std::is_member_function_pointer<std::decay_t<F>>::value;
48 
49 template <typename F>
50 const bool& IsMemObjPtr = std::is_member_object_pointer<std::decay_t<F>>::value;
51 
52 template <typename F,
53           typename T,
54           typename MemPtrClass = member_pointer_class_t<std::decay_t<F>>>
55 const bool& IsMemPtrToBaseOf =
56     std::is_base_of<MemPtrClass, std::decay_t<T>>::value;
57 
58 template <typename T>
59 const bool& IsRefWrapper = is_reference_wrapper<std::decay_t<T>>::value;
60 
61 template <bool B>
62 using EnableIf = std::enable_if_t<B, bool>;
63 
64 // Invokes a member function pointer on a reference to an object of a suitable
65 // type. Covers bullet 1 of the INVOKE definition.
66 //
67 // Reference: https://wg21.link/func.require#1.1
68 template <typename F,
69           typename T1,
70           typename... Args,
71           EnableIf<IsMemFunPtr<F> && IsMemPtrToBaseOf<F, T1>> = true>
72 constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1, Args&&... args) {
73   return (std::forward<T1>(t1).*f)(std::forward<Args>(args)...);
74 }
75 
76 // Invokes a member function pointer on a std::reference_wrapper to an object of
77 // a suitable type. Covers bullet 2 of the INVOKE definition.
78 //
79 // Reference: https://wg21.link/func.require#1.2
80 template <typename F,
81           typename T1,
82           typename... Args,
83           EnableIf<IsMemFunPtr<F> && IsRefWrapper<T1>> = true>
84 constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1, Args&&... args) {
85   return (t1.get().*f)(std::forward<Args>(args)...);
86 }
87 
88 // Invokes a member function pointer on a pointer-like type to an object of a
89 // suitable type. Covers bullet 3 of the INVOKE definition.
90 //
91 // Reference: https://wg21.link/func.require#1.3
92 template <typename F,
93           typename T1,
94           typename... Args,
95           EnableIf<IsMemFunPtr<F> && !IsMemPtrToBaseOf<F, T1> &&
96                    !IsRefWrapper<T1>> = true>
97 constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1, Args&&... args) {
98   return ((*std::forward<T1>(t1)).*f)(std::forward<Args>(args)...);
99 }
100 
101 // Invokes a member object pointer on a reference to an object of a suitable
102 // type. Covers bullet 4 of the INVOKE definition.
103 //
104 // Reference: https://wg21.link/func.require#1.4
105 template <typename F,
106           typename T1,
107           EnableIf<IsMemObjPtr<F> && IsMemPtrToBaseOf<F, T1>> = true>
108 constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1) {
109   return std::forward<T1>(t1).*f;
110 }
111 
112 // Invokes a member object pointer on a std::reference_wrapper to an object of
113 // a suitable type. Covers bullet 5 of the INVOKE definition.
114 //
115 // Reference: https://wg21.link/func.require#1.5
116 template <typename F,
117           typename T1,
118           EnableIf<IsMemObjPtr<F> && IsRefWrapper<T1>> = true>
119 constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1) {
120   return t1.get().*f;
121 }
122 
123 // Invokes a member object pointer on a pointer-like type to an object of a
124 // suitable type. Covers bullet 6 of the INVOKE definition.
125 //
126 // Reference: https://wg21.link/func.require#1.6
127 template <typename F,
128           typename T1,
129           EnableIf<IsMemObjPtr<F> && !IsMemPtrToBaseOf<F, T1> &&
130                    !IsRefWrapper<T1>> = true>
131 constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1) {
132   return (*std::forward<T1>(t1)).*f;
133 }
134 
135 // Invokes a regular function or function object. Covers bullet 7 of the INVOKE
136 // definition.
137 //
138 // Reference: https://wg21.link/func.require#1.7
139 template <typename F, typename... Args>
140 constexpr decltype(auto) InvokeImpl(F&& f, Args&&... args) {
141   return std::forward<F>(f)(std::forward<Args>(args)...);
142 }
143 
144 }  // namespace invoke_internal
145 
146 // Implementation of C++17's std::invoke. This is not based on implementation
147 // referenced in original std::invoke proposal, but rather a manual
148 // implementation, so that it can be constexpr.
149 //
150 // References:
151 // - https://wg21.link/n4169#implementability
152 // - https://en.cppreference.com/w/cpp/utility/functional/invoke
153 // - https://wg21.link/func.invoke
154 template <typename F, typename... Args>
155 constexpr decltype(auto) invoke(F&& f, Args&&... args) {
156   return invoke_internal::InvokeImpl(std::forward<F>(f),
157                                      std::forward<Args>(args)...);
158 }
159 
160 }  // namespace webrtc
161 
162 #endif  // RTC_BASE_CONTAINERS_INVOKE_H_
163