1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
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 * http://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 #ifndef META_BASE_CAPTURE_HEADER
17 #define META_BASE_CAPTURE_HEADER
18
19 #include <base/containers/shared_ptr.h>
20
21 #include <meta/base/namespace.h>
22
META_BEGIN_NAMESPACE()23 META_BEGIN_NAMESPACE()
24
25 namespace Details {
26
27 /**
28 * @brief Generic capture conversion.
29 */
30 template<typename Type>
31 Type&& CaptureWrap(Type&& obj)
32 {
33 return BASE_NS::forward<Type>(obj);
34 }
35
36 /**
37 * @brief Helper to keep wrap type info.
38 */
39 template<typename T>
40 struct CaptureWrapper {
41 T value;
42 };
43
44 /**
45 * @brief Capture conversion for shared_ptr.
46 */
47 template<typename Type>
48 CaptureWrapper<BASE_NS::weak_ptr<Type>> CaptureWrap(BASE_NS::shared_ptr<Type> p)
49 {
50 return { p };
51 }
52
53 /**
54 * @brief Capture conversion for weak_ptr.
55 */
56 template<typename Type>
57 CaptureWrapper<BASE_NS::weak_ptr<Type>> CaptureWrap(BASE_NS::weak_ptr<Type> p)
58 {
59 return { BASE_NS::move(p) };
60 }
61
62 /**
63 * @brief Helper to keep unwrapped type info.
64 */
65 template<typename T>
66 struct CaptureUnWrapper {
67 T value;
68 bool valid { true };
69 };
70
71 /**
72 * @brief Generic unwrap function that is called before the object is passed to the actual target function.
73 * This should be overloaded for wrapped types.
74 */
75 template<typename Type>
76 CaptureUnWrapper<Type> CaptureUnWrap(Type&& obj)
77 {
78 return CaptureUnWrapper<Type> { BASE_NS::forward<Type>(obj) };
79 }
80
81 /**
82 * @brief Capture conversion for wrapped type to shared_ptr.
83 */
84 template<typename Type>
85 CaptureUnWrapper<BASE_NS::shared_ptr<Type>> CaptureUnWrap(const CaptureWrapper<BASE_NS::weak_ptr<Type>>& p)
86 {
87 auto v = p.value.lock();
88 return CaptureUnWrapper<BASE_NS::shared_ptr<Type>> { v, v != nullptr };
89 }
90
91 /**
92 * @brief Invokes a captured function.
93 * @tparam Check Decides if captured parameters should be valid before func is invoked.
94 */
95 template<bool Check, typename... Other>
96 struct CaptureCallImpl {
97 template<typename Func, typename... Args>
98 static auto Call(Func& func, Other&&... other, Args&&... args)
99 {
100 if constexpr (Check) {
101 if ((false || ... || !args.valid)) {
102 using type = decltype(func(args.value..., BASE_NS::forward<decltype(other)>(other)...));
103 if constexpr (BASE_NS::is_same_v<type, void>) {
104 return;
105 } else {
106 return type {};
107 }
108 }
109 }
110 return func(args.value..., BASE_NS::forward<decltype(other)>(other)...);
111 }
112 };
113
114 template<bool Check, typename Lambda, typename... Args>
115 auto CaptureImpl(Lambda func, Args&&... args)
116 {
117 return [f = BASE_NS::move(func), args...](auto&&... other) {
118 return CaptureCallImpl<Check, decltype(other)...>::Call(
119 f, BASE_NS::forward<decltype(other)>(other)..., CaptureUnWrap(args)...);
120 };
121 }
122
123 } // namespace Details
124
125 /**
126 * @brief Replaces all shared pointers provided as args into weak pointers to avoid extending
127 * lifetime of the pointed resources. The provided func is wrapped into capture call which first
128 * locks back all weak pointers created from shared pointers and then calls the func.
129 *
130 * @param func Callable which will be wrapped into capture call.
131 * @param args Arguments list which will be passed to the func as parameters when the capture call will have place.
132 * All shared pointers in it will be replaced by weak pointers.
133 * @return Capture call which will not extend the lifetime of resources pointed by shared pointers provided as args.
134 */
135 template<typename Lambda, typename... Args>
decltype(auto)136 decltype(auto) Capture(Lambda func, Args&&... args)
137 {
138 return Details::CaptureImpl<false>(BASE_NS::move(func), Details::CaptureWrap(BASE_NS::forward<Args>(args))...);
139 }
140
141 /**
142 * @brief Wraps func into capture call which checks first if all shared pointers created from weak pointers points
143 * to the valid resources, and if the condition is met executes the func.
144 * If this condition is not met, capture call will return the default object.
145 *
146 * @param func Callable which will be wrapped into capture call.
147 * @param args Arguments list which will be passed to the func as parameters when the capture call will have place.
148 * All shared pointers in it will be replaced by weak pointers.
149 * @return Capture call which will not extend the lifetime of resources pointed by shared pointers provided as args,
150 * and which will validate all resources before func call will have place.
151 *
152 * @see Capture
153 */
154 template<typename Lambda, typename... Args>
decltype(auto)155 decltype(auto) CaptureSafe(Lambda func, Args&&... args)
156 {
157 return Details::CaptureImpl<true>(BASE_NS::move(func), Details::CaptureWrap(BASE_NS::forward<Args>(args))...);
158 }
159
160 template<typename Lambda, typename Ret, typename... Args>
AssureCaptureTypeAndNoCapture()161 void AssureCaptureTypeAndNoCapture()
162 {
163 using fp = Ret (*)(Args...);
164 static_assert(BASE_NS::is_convertible_v<Lambda, fp>, "Type mismatch or lambda capture");
165 }
166
167 META_END_NAMESPACE()
168
169 #endif
170