1/*
2 * Copyright (c) 2021 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 FOUNDATION_ACE_FRAMEWORKS_BASE_THREAD_CANCELABEL_CALLBACK_H
17#define FOUNDATION_ACE_FRAMEWORKS_BASE_THREAD_CANCELABEL_CALLBACK_H
18
19#include <atomic>
20#include <functional>
21#include <future>
22
23#include "base/memory/referenced.h"
24#include "base/utils/macros.h"
25
26namespace OHOS::Ace {
27
28using std::chrono_literals::operator""s;
29using std::chrono_literals::operator""ms;
30
31using TaskThread = uint32_t;
32constexpr TaskThread PLATFORM_TASK = 0;
33constexpr TaskThread MAIN_TASK = 1;
34constexpr TaskThread BACKGROUND_TASK = 1 << 1;
35constexpr TaskThread UNDEFINED_TASK = 1 << 2;
36
37template<class>
38class CancelableCallback;
39
40template<class... V>
41class CancelableCallback<void(V...)> final {
42public:
43    using FunctionType = std::function<void(V...)>;
44
45    CancelableCallback() = default;
46    explicit CancelableCallback(const FunctionType& callback)
47        : impl_(callback ? Referenced::MakeRefPtr<Callback>(callback) : nullptr)
48    {}
49    explicit CancelableCallback(FunctionType&& callback)
50        : impl_(callback ? Referenced::MakeRefPtr<Callback>(std::move(callback)) : nullptr)
51    {}
52    CancelableCallback(const FunctionType& callback, TaskThread taskThread)
53        : impl_(callback ? Referenced::MakeRefPtr<Callback>(callback) : nullptr), taskThread_(taskThread)
54    {}
55    CancelableCallback(FunctionType&& callback, TaskThread taskThread)
56        : impl_(callback ? Referenced::MakeRefPtr<Callback>(std::move(callback)) : nullptr), taskThread_(taskThread)
57    {}
58    ~CancelableCallback() = default;
59
60    void SetTaskThreadType(TaskThread taskThread) {}
61
62    TaskThread GetTaskThreadType() const
63    {
64        return MAIN_TASK;
65    }
66
67    void Reset(const FunctionType& callback, bool needCancel = true, bool waitUntilCompleted = false);
68    void Reset(FunctionType&& callback, bool needCancel = true, bool waitUntilCompleted = false);
69    bool WaitUntilComplete(std::chrono::milliseconds timeoutMs = 0ms);
70    bool Cancel(bool waitUntilCompleted = false);
71    void operator()(V&&... values) const;
72    operator bool() const
73    {
74        return impl_ && impl_->callback_;
75    }
76
77private:
78    enum : int32_t {
79        READY,
80        CANCELED,
81        RUNNING,
82        COMPLETED,
83    };
84
85    struct Callback final : public Referenced {
86        explicit Callback(const FunctionType& callback) : callback_(callback) {}
87        explicit Callback(FunctionType&& callback) : callback_(std::move(callback)) {}
88        ~Callback() override
89        {
90            int32_t status = status_.load(std::memory_order_relaxed);
91            ACE_DCHECK(status != RUNNING);
92            if (status == READY) {
93                promise_.set_value(CANCELED);
94            }
95        }
96
97        FunctionType callback_;
98        std::atomic<int32_t> status_ { READY };
99        std::promise<int32_t> promise_;
100        std::shared_future<int32_t> future_ { promise_.get_future() };
101    };
102
103    RefPtr<Callback> impl_;
104    TaskThread taskThread_ = MAIN_TASK;
105};
106
107template<class... V>
108void CancelableCallback<void(V...)>::Reset(
109    const CancelableCallback<void(V...)>::FunctionType& callback, bool needCancel, bool waitUntilCompleted)
110{
111    if (needCancel) {
112        Cancel(waitUntilCompleted);
113    }
114    impl_ = callback ? Referenced::MakeRefPtr<Callback>(callback) : nullptr;
115}
116
117template<class... V>
118void CancelableCallback<void(V...)>::Reset(
119    CancelableCallback<void(V...)>::FunctionType&& callback, bool needCancel, bool waitUntilCompleted)
120{
121    if (needCancel) {
122        Cancel(waitUntilCompleted);
123    }
124    impl_ = callback ? Referenced::MakeRefPtr<Callback>(std::move(callback)) : nullptr;
125}
126
127template<class... V>
128bool CancelableCallback<void(V...)>::WaitUntilComplete(std::chrono::milliseconds timeoutMs)
129{
130    RefPtr<Callback> impl(std::move(impl_));
131    if (!impl) {
132        return false;
133    }
134
135    switch (impl->status_.load(std::memory_order_relaxed)) {
136        case READY:
137        case RUNNING: {
138            std::shared_future<int32_t> future(impl->future_);
139            if (timeoutMs != 0ms && std::future_status::timeout == future.wait_for(timeoutMs)) {
140                CancelableCallback avatar(*this);
141                avatar.impl_ = impl;
142                avatar.Cancel(true);
143            }
144            impl.Reset();
145            return future.get() == COMPLETED;
146        }
147        case COMPLETED:
148            return true;
149        case CANCELED:
150        default:
151            return false;
152    }
153}
154
155template<class... V>
156bool CancelableCallback<void(V...)>::Cancel(bool waitUntilCompleted)
157{
158    RefPtr<Callback> impl(std::move(impl_));
159    if (!impl) {
160        return true;
161    }
162
163    int32_t status = READY;
164    if (impl->status_.compare_exchange_strong(status, CANCELED, std::memory_order_relaxed)) {
165        impl->promise_.set_value(CANCELED);
166        return true;
167    } else if (status == CANCELED) {
168        return true;
169    }
170
171    if (waitUntilCompleted && status == RUNNING) {
172        std::shared_future<int32_t> future(impl->future_);
173        impl.Reset();
174        status = future.get();
175        ACE_DCHECK(status == COMPLETED);
176    }
177    return false;
178}
179
180template<class... V>
181void CancelableCallback<void(V...)>::operator()(V&&... values) const
182{
183    RefPtr<Callback> impl(std::move(impl_));
184    if (!impl) {
185        return;
186    }
187
188    int32_t status = READY;
189    if (impl->status_.compare_exchange_strong(status, RUNNING, std::memory_order_relaxed)) {
190        impl->callback_(std::forward<V>(values)...);
191        impl->status_.store(COMPLETED);
192        impl->promise_.set_value(COMPLETED);
193    }
194}
195
196} // namespace OHOS::Ace
197
198#endif // FOUNDATION_ACE_FRAMEWORKS_BASE_THREAD_CANCELABEL_CALLBACK_H
199