blob: 5d17a70bebe1c4d1ef1264c5a9f90f893f07af84 [file] [log] [blame]
Victor Boiviefd954fc2021-06-29 09:21:11 +02001/*
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
19namespace webrtc {
20
21namespace invoke_internal {
22
23// Helper struct and alias to deduce the class type from a member function
24// pointer or member object pointer.
25template <typename DecayedF>
26struct member_pointer_class {};
27
28template <typename ReturnT, typename ClassT>
29struct member_pointer_class<ReturnT ClassT::*> {
30 using type = ClassT;
31};
32
33template <typename DecayedF>
34using member_pointer_class_t = typename member_pointer_class<DecayedF>::type;
35
36// Utility struct to detect specializations of std::reference_wrapper.
37template <typename T>
38struct is_reference_wrapper : std::false_type {};
39
40template <typename T>
41struct 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.
45template <typename F>
46const bool& IsMemFunPtr =
47 std::is_member_function_pointer<std::decay_t<F>>::value;
48
49template <typename F>
50const bool& IsMemObjPtr = std::is_member_object_pointer<std::decay_t<F>>::value;
51
52template <typename F,
53 typename T,
54 typename MemPtrClass = member_pointer_class_t<std::decay_t<F>>>
55const bool& IsMemPtrToBaseOf =
56 std::is_base_of<MemPtrClass, std::decay_t<T>>::value;
57
58template <typename T>
59const bool& IsRefWrapper = is_reference_wrapper<std::decay_t<T>>::value;
60
61template <bool B>
62using 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
68template <typename F,
69 typename T1,
70 typename... Args,
71 EnableIf<IsMemFunPtr<F> && IsMemPtrToBaseOf<F, T1>> = true>
72constexpr 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
80template <typename F,
81 typename T1,
82 typename... Args,
83 EnableIf<IsMemFunPtr<F> && IsRefWrapper<T1>> = true>
84constexpr 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
92template <typename F,
93 typename T1,
94 typename... Args,
95 EnableIf<IsMemFunPtr<F> && !IsMemPtrToBaseOf<F, T1> &&
96 !IsRefWrapper<T1>> = true>
97constexpr 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
105template <typename F,
106 typename T1,
107 EnableIf<IsMemObjPtr<F> && IsMemPtrToBaseOf<F, T1>> = true>
108constexpr 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
116template <typename F,
117 typename T1,
118 EnableIf<IsMemObjPtr<F> && IsRefWrapper<T1>> = true>
119constexpr 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
127template <typename F,
128 typename T1,
129 EnableIf<IsMemObjPtr<F> && !IsMemPtrToBaseOf<F, T1> &&
130 !IsRefWrapper<T1>> = true>
131constexpr 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
139template <typename F, typename... Args>
140constexpr 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
154template <typename F, typename... Args>
155constexpr 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_