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