/*
* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef META_BASE_CAPTURE_HEADER
#define META_BASE_CAPTURE_HEADER
#include
#include
META_BEGIN_NAMESPACE()
namespace Details {
/**
* @brief Generic capture conversion.
*/
template
Type&& CaptureWrap(Type&& obj)
{
return BASE_NS::forward(obj);
}
/**
* @brief Helper to keep wrap type info.
*/
template
struct CaptureWrapper {
T value;
};
/**
* @brief Capture conversion for shared_ptr.
*/
template
CaptureWrapper> CaptureWrap(BASE_NS::shared_ptr p)
{
return { p };
}
/**
* @brief Capture conversion for weak_ptr.
*/
template
CaptureWrapper> CaptureWrap(BASE_NS::weak_ptr p)
{
return { BASE_NS::move(p) };
}
/**
* @brief Helper to keep unwrapped type info.
*/
template
struct CaptureUnWrapper {
T value;
bool valid { true };
};
/**
* @brief Generic unwrap function that is called before the object is passed to the actual target function.
* This should be overloaded for wrapped types.
*/
template
CaptureUnWrapper CaptureUnWrap(Type&& obj)
{
return CaptureUnWrapper { BASE_NS::forward(obj) };
}
/**
* @brief Capture conversion for wrapped type to shared_ptr.
*/
template
CaptureUnWrapper> CaptureUnWrap(const CaptureWrapper>& p)
{
auto v = p.value.lock();
return CaptureUnWrapper> { v, v != nullptr };
}
/**
* @brief Invokes a captured function.
* @tparam Check Decides if captured parameters should be valid before func is invoked.
*/
template
struct CaptureCallImpl {
template
static auto Call(Func& func, Other&&... other, Args&&... args)
{
if constexpr (Check) {
if ((false || ... || !args.valid)) {
using type = decltype(func(args.value..., BASE_NS::forward(other)...));
if constexpr (BASE_NS::is_same_v) {
return;
} else {
return type {};
}
}
}
return func(args.value..., BASE_NS::forward(other)...);
}
};
template
auto CaptureImpl(Lambda func, Args&&... args)
{
return [f = BASE_NS::move(func), args...](auto&&... other) {
return CaptureCallImpl::Call(
f, BASE_NS::forward(other)..., CaptureUnWrap(args)...);
};
}
} // namespace Details
/**
* @brief Replaces all shared pointers provided as args into weak pointers to avoid extending
* lifetime of the pointed resources. The provided func is wrapped into capture call which first
* locks back all weak pointers created from shared pointers and then calls the func.
*
* @param func Callable which will be wrapped into capture call.
* @param args Arguments list which will be passed to the func as parameters when the capture call will have place.
* All shared pointers in it will be replaced by weak pointers.
* @return Capture call which will not extend the lifetime of resources pointed by shared pointers provided as args.
*/
template
decltype(auto) Capture(Lambda func, Args&&... args)
{
return Details::CaptureImpl(BASE_NS::move(func), Details::CaptureWrap(BASE_NS::forward(args))...);
}
/**
* @brief Wraps func into capture call which checks first if all shared pointers created from weak pointers points
* to the valid resources, and if the condition is met executes the func.
* If this condition is not met, capture call will return the default object.
*
* @param func Callable which will be wrapped into capture call.
* @param args Arguments list which will be passed to the func as parameters when the capture call will have place.
* All shared pointers in it will be replaced by weak pointers.
* @return Capture call which will not extend the lifetime of resources pointed by shared pointers provided as args,
* and which will validate all resources before func call will have place.
*
* @see Capture
*/
template
decltype(auto) CaptureSafe(Lambda func, Args&&... args)
{
return Details::CaptureImpl(BASE_NS::move(func), Details::CaptureWrap(BASE_NS::forward(args))...);
}
template
void AssureCaptureTypeAndNoCapture()
{
using fp = Ret (*)(Args...);
static_assert(BASE_NS::is_convertible_v, "Type mismatch or lambda capture");
}
META_END_NAMESPACE()
#endif