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