/src/abseil-cpp/absl/functional/function_ref.h
Line | Count | Source |
1 | | // Copyright 2019 The Abseil Authors. |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // https://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | // |
15 | | // ----------------------------------------------------------------------------- |
16 | | // File: function_ref.h |
17 | | // ----------------------------------------------------------------------------- |
18 | | // |
19 | | // This header file defines the `absl::FunctionRef` type for holding a |
20 | | // non-owning reference to an object of any invocable type. This function |
21 | | // reference is typically most useful as a type-erased argument type for |
22 | | // accepting function types that neither take ownership nor copy the type; using |
23 | | // the reference type in this case avoids a copy and an allocation. Best |
24 | | // practices of other non-owning reference-like objects (such as |
25 | | // `absl::string_view`) apply here. |
26 | | // |
27 | | // An `absl::FunctionRef` is similar in usage to a `std::function` but has the |
28 | | // following differences: |
29 | | // |
30 | | // * It doesn't own the underlying object. |
31 | | // * It doesn't have a null or empty state. |
32 | | // * It never performs deep copies or allocations. |
33 | | // * It's much faster and cheaper to construct. |
34 | | // * It's trivially copyable and destructable. |
35 | | // |
36 | | // Generally, `absl::FunctionRef` should not be used as a return value, data |
37 | | // member, or to initialize a `std::function`. Such usages will often lead to |
38 | | // problematic lifetime issues. Once you convert something to an |
39 | | // `absl::FunctionRef` you cannot make a deep copy later. |
40 | | // |
41 | | // This class is suitable for use wherever a "const std::function<>&" |
42 | | // would be used without making a copy. ForEach functions and other versions of |
43 | | // the visitor pattern are a good example of when this class should be used. |
44 | | // |
45 | | // This class is trivial to copy and should be passed by value. |
46 | | #ifndef ABSL_FUNCTIONAL_FUNCTION_REF_H_ |
47 | | #define ABSL_FUNCTIONAL_FUNCTION_REF_H_ |
48 | | |
49 | | #include <cassert> |
50 | | #include <type_traits> |
51 | | #include <utility> |
52 | | |
53 | | #include "absl/base/attributes.h" |
54 | | #include "absl/base/config.h" |
55 | | #include "absl/functional/internal/function_ref.h" |
56 | | #include "absl/meta/type_traits.h" |
57 | | #include "absl/utility/utility.h" |
58 | | |
59 | | namespace absl { |
60 | | ABSL_NAMESPACE_BEGIN |
61 | | |
62 | | // FunctionRef |
63 | | // |
64 | | // Dummy class declaration to allow the partial specialization based on function |
65 | | // types below. |
66 | | template <typename T> |
67 | | class FunctionRef; |
68 | | |
69 | | // FunctionRef |
70 | | // |
71 | | // An `absl::FunctionRef` is a lightweight wrapper to any invocable object with |
72 | | // a compatible signature. Generally, an `absl::FunctionRef` should only be used |
73 | | // as an argument type and should be preferred as an argument over a const |
74 | | // reference to a `std::function`. `absl::FunctionRef` itself does not allocate, |
75 | | // although the wrapped invocable may. |
76 | | // |
77 | | // Example: |
78 | | // |
79 | | // // The following function takes a function callback by const reference |
80 | | // bool Visitor(const std::function<void(my_proto&, |
81 | | // absl::string_view)>& callback); |
82 | | // |
83 | | // // Assuming that the function is not stored or otherwise copied, it can be |
84 | | // // replaced by an `absl::FunctionRef`: |
85 | | // bool Visitor(absl::FunctionRef<void(my_proto&, absl::string_view)> |
86 | | // callback); |
87 | | template <typename R, typename... Args> |
88 | | class ABSL_ATTRIBUTE_VIEW FunctionRef<R(Args...)> { |
89 | | protected: |
90 | | // Used to disable constructors for objects that are not compatible with the |
91 | | // signature of this FunctionRef. |
92 | | template <typename F, typename... U> |
93 | | using EnableIfCompatible = |
94 | | std::enable_if_t<std::is_invocable_r<R, F, U..., Args...>::value>; |
95 | | |
96 | | // Internal constructor to supersede the copying constructor |
97 | | template <typename F> |
98 | | // NOLINTNEXTLINE(google-explicit-constructor) |
99 | | FunctionRef(std::in_place_t, F&& f ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept |
100 | 27.9k | : invoker_(&absl::functional_internal::InvokeObject<F&, R, Args...>) { |
101 | 27.9k | absl::functional_internal::AssertNonNull(f); |
102 | 27.9k | ptr_.obj = &f; |
103 | 27.9k | } absl::FunctionRef<unsigned long (unsigned long)>::FunctionRef<absl::container_internal::HashKey<absl::container_internal::StringHash, std::__1::basic_string_view<char, std::__1::char_traits<char> >, true> >(std::__1::in_place_t, absl::container_internal::HashKey<absl::container_internal::StringHash, std::__1::basic_string_view<char, std::__1::char_traits<char> >, true>&&) Line | Count | Source | 100 | 4 | : invoker_(&absl::functional_internal::InvokeObject<F&, R, Args...>) { | 101 | 4 | absl::functional_internal::AssertNonNull(f); | 102 | 4 | ptr_.obj = &f; | 103 | 4 | } |
float_conversion.cc:absl::FunctionRef<void (absl::Span<unsigned int>)>::FunctionRef<absl::str_format_internal::(anonymous namespace)::BinaryToDecimal::RunConversion(absl::uint128, int, absl::FunctionRef<void (absl::str_format_internal::(anonymous namespace)::BinaryToDecimal)>)::{lambda(absl::Span<unsigned int>)#1}>(std::__1::in_place_t, absl::str_format_internal::(anonymous namespace)::BinaryToDecimal::RunConversion(absl::uint128, int, absl::FunctionRef<void (absl::str_format_internal::(anonymous namespace)::BinaryToDecimal)>)::{lambda(absl::Span<unsigned int>)#1}&&) Line | Count | Source | 100 | 7.39k | : invoker_(&absl::functional_internal::InvokeObject<F&, R, Args...>) { | 101 | 7.39k | absl::functional_internal::AssertNonNull(f); | 102 | 7.39k | ptr_.obj = &f; | 103 | 7.39k | } |
float_conversion.cc:absl::FunctionRef<void (absl::str_format_internal::(anonymous namespace)::BinaryToDecimal)>::FunctionRef<absl::str_format_internal::(anonymous namespace)::FormatFPositiveExpSlow(absl::uint128, int, absl::str_format_internal::(anonymous namespace)::FormatState const&)::$_0>(std::__1::in_place_t, absl::str_format_internal::(anonymous namespace)::FormatFPositiveExpSlow(absl::uint128, int, absl::str_format_internal::(anonymous namespace)::FormatState const&)::$_0&&) Line | Count | Source | 100 | 7.39k | : invoker_(&absl::functional_internal::InvokeObject<F&, R, Args...>) { | 101 | 7.39k | absl::functional_internal::AssertNonNull(f); | 102 | 7.39k | ptr_.obj = &f; | 103 | 7.39k | } |
float_conversion.cc:absl::FunctionRef<void (absl::Span<unsigned int>)>::FunctionRef<absl::str_format_internal::(anonymous namespace)::FractionalDigitGenerator::RunConversion(absl::uint128, int, absl::FunctionRef<void (absl::str_format_internal::(anonymous namespace)::FractionalDigitGenerator)>)::{lambda(absl::Span<unsigned int>)#1}>(std::__1::in_place_t, absl::str_format_internal::(anonymous namespace)::FractionalDigitGenerator::RunConversion(absl::uint128, int, absl::FunctionRef<void (absl::str_format_internal::(anonymous namespace)::FractionalDigitGenerator)>)::{lambda(absl::Span<unsigned int>)#1}&&) Line | Count | Source | 100 | 6.58k | : invoker_(&absl::functional_internal::InvokeObject<F&, R, Args...>) { | 101 | 6.58k | absl::functional_internal::AssertNonNull(f); | 102 | 6.58k | ptr_.obj = &f; | 103 | 6.58k | } |
float_conversion.cc:absl::FunctionRef<void (absl::str_format_internal::(anonymous namespace)::FractionalDigitGenerator)>::FunctionRef<absl::str_format_internal::(anonymous namespace)::FormatFNegativeExpSlow(absl::uint128, int, absl::str_format_internal::(anonymous namespace)::FormatState const&)::$_0>(std::__1::in_place_t, absl::str_format_internal::(anonymous namespace)::FormatFNegativeExpSlow(absl::uint128, int, absl::str_format_internal::(anonymous namespace)::FormatState const&)::$_0&&) Line | Count | Source | 100 | 6.58k | : invoker_(&absl::functional_internal::InvokeObject<F&, R, Args...>) { | 101 | 6.58k | absl::functional_internal::AssertNonNull(f); | 102 | 6.58k | ptr_.obj = &f; | 103 | 6.58k | } |
|
104 | | |
105 | | public: |
106 | | // Constructs a FunctionRef from any invocable type. |
107 | | template <typename F, |
108 | | typename = EnableIfCompatible<std::enable_if_t< |
109 | | !std::is_same_v<FunctionRef, absl::remove_cvref_t<F>>, F&>>> |
110 | | // NOLINTNEXTLINE(google-explicit-constructor) |
111 | | FunctionRef(F&& f ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept |
112 | 27.9k | : FunctionRef(std::in_place, std::forward<F>(f)) {} absl::FunctionRef<unsigned long (unsigned long)>::FunctionRef<absl::container_internal::HashKey<absl::container_internal::StringHash, std::__1::basic_string_view<char, std::__1::char_traits<char> >, true>, void>(absl::container_internal::HashKey<absl::container_internal::StringHash, std::__1::basic_string_view<char, std::__1::char_traits<char> >, true>&&) Line | Count | Source | 112 | 4 | : FunctionRef(std::in_place, std::forward<F>(f)) {} |
float_conversion.cc:absl::FunctionRef<void (absl::Span<unsigned int>)>::FunctionRef<absl::str_format_internal::(anonymous namespace)::BinaryToDecimal::RunConversion(absl::uint128, int, absl::FunctionRef<void (absl::str_format_internal::(anonymous namespace)::BinaryToDecimal)>)::{lambda(absl::Span<unsigned int>)#1}, void>(absl::str_format_internal::(anonymous namespace)::BinaryToDecimal::RunConversion(absl::uint128, int, absl::FunctionRef<void (absl::str_format_internal::(anonymous namespace)::BinaryToDecimal)>)::{lambda(absl::Span<unsigned int>)#1}&&) Line | Count | Source | 112 | 7.39k | : FunctionRef(std::in_place, std::forward<F>(f)) {} |
float_conversion.cc:absl::FunctionRef<void (absl::str_format_internal::(anonymous namespace)::BinaryToDecimal)>::FunctionRef<absl::str_format_internal::(anonymous namespace)::FormatFPositiveExpSlow(absl::uint128, int, absl::str_format_internal::(anonymous namespace)::FormatState const&)::$_0, void>(absl::str_format_internal::(anonymous namespace)::FormatFPositiveExpSlow(absl::uint128, int, absl::str_format_internal::(anonymous namespace)::FormatState const&)::$_0&&) Line | Count | Source | 112 | 7.39k | : FunctionRef(std::in_place, std::forward<F>(f)) {} |
float_conversion.cc:absl::FunctionRef<void (absl::Span<unsigned int>)>::FunctionRef<absl::str_format_internal::(anonymous namespace)::FractionalDigitGenerator::RunConversion(absl::uint128, int, absl::FunctionRef<void (absl::str_format_internal::(anonymous namespace)::FractionalDigitGenerator)>)::{lambda(absl::Span<unsigned int>)#1}, void>(absl::str_format_internal::(anonymous namespace)::FractionalDigitGenerator::RunConversion(absl::uint128, int, absl::FunctionRef<void (absl::str_format_internal::(anonymous namespace)::FractionalDigitGenerator)>)::{lambda(absl::Span<unsigned int>)#1}&&) Line | Count | Source | 112 | 6.58k | : FunctionRef(std::in_place, std::forward<F>(f)) {} |
float_conversion.cc:absl::FunctionRef<void (absl::str_format_internal::(anonymous namespace)::FractionalDigitGenerator)>::FunctionRef<absl::str_format_internal::(anonymous namespace)::FormatFNegativeExpSlow(absl::uint128, int, absl::str_format_internal::(anonymous namespace)::FormatState const&)::$_0, void>(absl::str_format_internal::(anonymous namespace)::FormatFNegativeExpSlow(absl::uint128, int, absl::str_format_internal::(anonymous namespace)::FormatState const&)::$_0&&) Line | Count | Source | 112 | 6.58k | : FunctionRef(std::in_place, std::forward<F>(f)) {} |
|
113 | | |
114 | | // Overload for function pointers. This eliminates a level of indirection that |
115 | | // would happen if the above overload was used (it lets us store the pointer |
116 | | // instead of a pointer to a pointer). |
117 | | // |
118 | | // This overload is also used for references to functions, since references to |
119 | | // functions can decay to function pointers implicitly. |
120 | | template <typename F, typename = EnableIfCompatible<F*>, |
121 | | absl::functional_internal::EnableIf<std::is_function_v<F>> = 0> |
122 | | // NOLINTNEXTLINE(google-explicit-constructor) |
123 | | FunctionRef(F* f ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept |
124 | | : invoker_(&absl::functional_internal::InvokeFunction<F*, R, Args...>) { |
125 | | assert(f != nullptr); |
126 | | ptr_.fun = reinterpret_cast<decltype(ptr_.fun)>(f); |
127 | | } |
128 | | |
129 | | #if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L |
130 | | // Similar to the other overloads, but passes the address of a known callable |
131 | | // `F` at compile time. This allows calling arbitrary functions while avoiding |
132 | | // an indirection. |
133 | | // Needs C++20 as `nontype_t` needs C++20 for `auto` template parameters. |
134 | | template <auto F, typename = EnableIfCompatible<decltype(F)>> |
135 | | FunctionRef(nontype_t<F>) noexcept // NOLINT(google-explicit-constructor) |
136 | | : invoker_(&absl::functional_internal::InvokeFunction<decltype(F), F, R, |
137 | | Args...>) {} |
138 | | |
139 | | template < |
140 | | auto F, typename Obj, |
141 | | typename = EnableIfCompatible<decltype(F), std::remove_reference_t<Obj>&>, |
142 | | absl::functional_internal::EnableIf<!std::is_rvalue_reference_v<Obj&&>> = |
143 | | 0> |
144 | | // NOLINTNEXTLINE(google-explicit-constructor) |
145 | | FunctionRef(nontype_t<F>, Obj&& obj ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept |
146 | | : invoker_(&absl::functional_internal::InvokeObject<Obj&, decltype(F), F, |
147 | | R, Args...>) { |
148 | | ptr_.obj = std::addressof(obj); |
149 | | } |
150 | | |
151 | | template <auto F, typename Obj, |
152 | | typename = EnableIfCompatible<decltype(F), Obj*>> |
153 | | // NOLINTNEXTLINE(google-explicit-constructor) |
154 | | FunctionRef(nontype_t<F>, Obj* obj ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept |
155 | | : invoker_(&absl::functional_internal::InvokePtr<Obj, decltype(F), F, R, |
156 | | Args...>) { |
157 | | ptr_.obj = obj; |
158 | | } |
159 | | #endif |
160 | | |
161 | | using absl_internal_is_view = std::true_type; |
162 | | |
163 | | // Call the underlying object. |
164 | 27.9k | R operator()(Args... args) const { |
165 | 27.9k | return invoker_(ptr_, std::forward<Args>(args)...); |
166 | 27.9k | } Unexecuted instantiation: absl::FunctionRef<void (std::__1::basic_string_view<char, std::__1::char_traits<char> >)>::operator()(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const Unexecuted instantiation: absl::FunctionRef<void (absl::container_internal::ctrl_t const*, void*)>::operator()(absl::container_internal::ctrl_t const*, void*) const absl::FunctionRef<unsigned long (unsigned long)>::operator()(unsigned long) const Line | Count | Source | 164 | 2 | R operator()(Args... args) const { | 165 | 2 | return invoker_(ptr_, std::forward<Args>(args)...); | 166 | 2 | } |
Unexecuted instantiation: absl::FunctionRef<void (void*, void const*)>::operator()(void*, void const*) const absl::FunctionRef<void (absl::Span<unsigned int>)>::operator()(absl::Span<unsigned int>) const Line | Count | Source | 164 | 13.9k | R operator()(Args... args) const { | 165 | 13.9k | return invoker_(ptr_, std::forward<Args>(args)...); | 166 | 13.9k | } |
float_conversion.cc:absl::FunctionRef<void (absl::str_format_internal::(anonymous namespace)::BinaryToDecimal)>::operator()(absl::str_format_internal::(anonymous namespace)::BinaryToDecimal) const Line | Count | Source | 164 | 7.39k | R operator()(Args... args) const { | 165 | 7.39k | return invoker_(ptr_, std::forward<Args>(args)...); | 166 | 7.39k | } |
float_conversion.cc:absl::FunctionRef<void (absl::str_format_internal::(anonymous namespace)::FractionalDigitGenerator)>::operator()(absl::str_format_internal::(anonymous namespace)::FractionalDigitGenerator) const Line | Count | Source | 164 | 6.58k | R operator()(Args... args) const { | 165 | 6.58k | return invoker_(ptr_, std::forward<Args>(args)...); | 166 | 6.58k | } |
|
167 | | |
168 | | private: |
169 | | absl::functional_internal::VoidPtr ptr_; |
170 | | absl::functional_internal::Invoker<R, Args...> invoker_; |
171 | | }; |
172 | | |
173 | | // Allow const qualified function signatures. Since FunctionRef requires |
174 | | // constness anyway we can just make this a no-op. |
175 | | template <typename R, typename... Args> |
176 | | class ABSL_ATTRIBUTE_VIEW |
177 | | FunctionRef<R(Args...) const> : private FunctionRef<R(Args...)> { |
178 | | using Base = FunctionRef<R(Args...)>; |
179 | | |
180 | | template <typename F, typename... U> |
181 | | using EnableIfCompatible = |
182 | | typename Base::template EnableIfCompatible<F, U...>; |
183 | | |
184 | | public: |
185 | | template < |
186 | | typename F, |
187 | | typename = EnableIfCompatible<std::enable_if_t< |
188 | | !std::is_same_v<FunctionRef, absl::remove_cvref_t<F>>, const F&>>> |
189 | | // NOLINTNEXTLINE(google-explicit-constructor) |
190 | | FunctionRef(const F& f ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept |
191 | | : Base(std::in_place_t(), f) {} |
192 | | |
193 | | template <typename F, typename = EnableIfCompatible<F*>, |
194 | | absl::functional_internal::EnableIf<std::is_function_v<F>> = 0> |
195 | | // NOLINTNEXTLINE(google-explicit-constructor) |
196 | | FunctionRef(F* f ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept : Base(f) {} |
197 | | |
198 | | #if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L |
199 | | template <auto F, typename = EnableIfCompatible<decltype(F)>> |
200 | | // NOLINTNEXTLINE(google-explicit-constructor) |
201 | | FunctionRef(nontype_t<F> arg) noexcept : Base(arg) {} |
202 | | |
203 | | template <auto F, typename Obj, |
204 | | typename = EnableIfCompatible<decltype(F), |
205 | | const std::remove_reference_t<Obj>&>, |
206 | | absl::functional_internal::EnableIf< |
207 | | !std::is_rvalue_reference_v<Obj&&>> = 0> |
208 | | // NOLINTNEXTLINE(google-explicit-constructor) |
209 | | FunctionRef(nontype_t<F> arg, |
210 | | Obj&& obj ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept |
211 | | : Base(arg, std::forward<Obj>(obj)) {} |
212 | | |
213 | | template <auto F, typename Obj, |
214 | | typename = EnableIfCompatible<decltype(F), const Obj*>> |
215 | | // NOLINTNEXTLINE(google-explicit-constructor) |
216 | | FunctionRef(nontype_t<F> arg, |
217 | | const Obj* obj ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept |
218 | | : Base(arg, obj) {} |
219 | | #endif |
220 | | |
221 | | using absl_internal_is_view = std::true_type; |
222 | | |
223 | | using Base::operator(); |
224 | | }; |
225 | | |
226 | | template <class F> |
227 | | FunctionRef(F*) -> FunctionRef<F>; |
228 | | |
229 | | #if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L |
230 | | template <auto Func> |
231 | | FunctionRef(nontype_t<Func>) |
232 | | -> FunctionRef<std::remove_pointer_t<decltype(Func)>>; |
233 | | |
234 | | template <class M, class T, M T::* Func, class U> |
235 | | FunctionRef(nontype_t<Func>, U&&) |
236 | | -> FunctionRef<std::enable_if_t<std::is_member_pointer_v<M T::*>, M>>; |
237 | | |
238 | | template <class M, class T, M T::* Func, class U> |
239 | | FunctionRef(nontype_t<Func>, U&&) -> FunctionRef<std::enable_if_t< |
240 | | std::is_object_v<M>, std::invoke_result_t<decltype(Func), U&>()>>; |
241 | | |
242 | | template <class R, class T, class... Args, R (*Func)(T, Args...), class U> |
243 | | FunctionRef(nontype_t<Func>, U&&) -> FunctionRef<R(Args...)>; |
244 | | #endif |
245 | | |
246 | | ABSL_NAMESPACE_END |
247 | | } // namespace absl |
248 | | |
249 | | #endif // ABSL_FUNCTIONAL_FUNCTION_REF_H_ |