olp-cpp-sdk 1.24.0
Loading...
Searching...
No Matches
TaskContext.h
1/*
2 * Copyright (C) 2019-2021 HERE Europe B.V.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * SPDX-License-Identifier: Apache-2.0
17 * License-Filename: LICENSE
18 */
19
20#pragma once
21
22#include <atomic>
23#include <memory>
24#include <mutex>
25#include <utility>
26
27#include <olp/core/client/ApiError.h>
28#include <olp/core/client/CancellationContext.h>
29#include <olp/core/client/CancellationToken.h>
30#include <olp/core/client/Condition.h>
31
32namespace olp {
33namespace client {
34
42class CORE_API TaskContext {
43 public:
56 template <typename Exec, typename Callback>
58 Exec execute_func, Callback callback,
60 TaskContext task;
61 task.SetExecutors(std::move(execute_func), std::move(callback),
62 std::move(context));
63 return task;
64 }
65
70 void Execute() const { impl_->Execute(); }
71
81 std::chrono::milliseconds timeout = std::chrono::seconds(60)) const {
82 return impl_->BlockingCancel(timeout);
83 }
84
90 client::CancellationToken CancelToken() const { return impl_->CancelToken(); }
91
101 bool operator==(const TaskContext& other) const {
102 return impl_ == other.impl_;
103 }
104
105 protected:
107 friend struct TaskContextHash;
108
109 TaskContext() = default;
110
111 template <typename Exec, typename Callback,
112#if defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable >= 201703
113 typename ExecResult =
114 std::invoke_result_t<Exec, client::CancellationContext>
115#else
116 typename ExecResult =
117 typename std::result_of<Exec(client::CancellationContext)>::type
118#endif
119 >
128 void SetExecutors(Exec execute_func, Callback callback,
130 impl_ = std::make_shared<TaskContextImpl<ExecResult>>(
131 std::move(execute_func), std::move(callback), std::move(context));
132 }
133
139 class Impl {
140 public:
141 virtual ~Impl() = default;
142
147 virtual void Execute() = 0;
148
157 virtual bool BlockingCancel(std::chrono::milliseconds timeout) = 0;
158
165 };
166
175 template <typename Response>
176 class TaskContextImpl : public Impl {
177 public:
179 using ExecuteFunc = std::function<Response(client::CancellationContext)>;
181 using UserCallback = std::function<void(Response)>;
182
193 : execute_func_(std::move(execute_func)),
194 callback_(std::move(callback)),
195 context_(std::move(context)),
196 state_{State::PENDING} {}
197
198 ~TaskContextImpl() override{};
199
204 void Execute() override {
205 State expected_state = State::PENDING;
206
207 if (!state_.compare_exchange_strong(expected_state, State::IN_PROGRESS)) {
208 return;
209 }
210
211 // Moving the user callback and function guarantee that they are
212 // executed exactly once
213 ExecuteFunc function = nullptr;
214 UserCallback callback = nullptr;
215
216 {
217 std::lock_guard<std::mutex> lock(mutex_);
218 function = std::move(execute_func_);
219 callback = std::move(callback_);
220 }
221
222 Response user_response =
223 client::ApiError(client::ErrorCode::Cancelled, "Cancelled");
224
225 if (function && !context_.IsCancelled()) {
226 auto response = function(context_);
227 // Cancel could occur during the function execution. In that case,
228 // ignore the response.
229 if (!context_.IsCancelled() ||
230 (!response.IsSuccessful() &&
231 response.GetError().GetErrorCode() == ErrorCode::RequestTimeout)) {
232 user_response = std::move(response);
233 }
234 }
235
236 // Reset the context after the task is finished.
237 context_.ExecuteOrCancelled([]() { return CancellationToken(); });
238
239 if (callback) {
240 callback(std::move(user_response));
241 }
242
243 // Resources need to be released before the notification, else lambas
244 // would have captured resources like network or `TaskScheduler`.
245 function = nullptr;
246 callback = nullptr;
247
248 condition_.Notify();
249 state_.store(State::COMPLETED);
250 }
251
260 bool BlockingCancel(std::chrono::milliseconds timeout) override {
261 if (state_.load() == State::COMPLETED) {
262 return true;
263 }
264
265 // Cancels the operation and waits for the notification.
266 if (!context_.IsCancelled()) {
267 context_.CancelOperation();
268 }
269
270 {
271 std::lock_guard<std::mutex> lock(mutex_);
272 execute_func_ = nullptr;
273 }
274
275 return condition_.Wait(timeout);
276 }
277
284 auto context = context_;
286 [context]() mutable { context.CancelOperation(); });
287 }
288
292 enum class State {
294 PENDING,
296 IN_PROGRESS,
298 COMPLETED
299 };
300
303 std::mutex mutex_;
313 std::atomic<State> state_;
314 };
315
317 std::shared_ptr<Impl> impl_;
318};
319
323struct CORE_API TaskContextHash {
331 size_t operator()(const TaskContext& task_context) const {
332 return std::hash<std::shared_ptr<TaskContext::Impl>>()(task_context.impl_);
333 }
334};
335
336} // namespace client
337} // namespace olp
A wrapper around an internal error or HTTP status code.
Definition ApiError.h:37
A wrapper that manages the cancellation state of an asynchronous operation in a thread-safe way.
Definition CancellationContext.h:40
Cancels service requests.
Definition CancellationToken.h:33
A helper class that allows one thread to call and wait for a notification in the other thread.
Definition Condition.h:35
An implementation helper interface used to declare the Execute, BlockingCancel, and CancelToken funct...
Definition TaskContext.h:139
virtual client::CancellationToken CancelToken()=0
Provides a token to cancel the task.
virtual void Execute()=0
Checks for the cancellation, executes the task, and calls the callback with the result or error.
virtual bool BlockingCancel(std::chrono::milliseconds timeout)=0
Cancels the operation and waits for the notification.
Implements the Impl interface.
Definition TaskContext.h:176
void Execute() override
Checks for the cancellation, executes the task, and calls the callback with the result or error.
Definition TaskContext.h:204
std::function< void(Response)> UserCallback
Consumes the Response instance.
Definition TaskContext.h:181
std::mutex mutex_
Definition TaskContext.h:303
TaskContextImpl(ExecuteFunc execute_func, UserCallback callback, client::CancellationContext context)
Creates the TaskContextImpl instance.
Definition TaskContext.h:191
State
Indicates the state of the request.
Definition TaskContext.h:292
bool BlockingCancel(std::chrono::milliseconds timeout) override
Cancels the operation and waits for the notification.
Definition TaskContext.h:260
client::Condition condition_
The Condition instance.
Definition TaskContext.h:311
ExecuteFunc execute_func_
The ExecuteFunc instance.
Definition TaskContext.h:305
client::CancellationContext context_
The CancellationContext instance.
Definition TaskContext.h:309
std::atomic< State > state_
The State enum of the atomic type.
Definition TaskContext.h:313
UserCallback callback_
The UserCallback instance.
Definition TaskContext.h:307
client::CancellationToken CancelToken() override
Provides a token to cancel the task.
Definition TaskContext.h:283
std::function< Response(client::CancellationContext)> ExecuteFunc
The task that produces the Response instance.
Definition TaskContext.h:179
Encapsulates the execution of an asynchronous task and invocation of a callback in a guaranteed manne...
Definition TaskContext.h:42
std::shared_ptr< Impl > impl_
The Impl instance.
Definition TaskContext.h:317
bool BlockingCancel(std::chrono::milliseconds timeout=std::chrono::seconds(60)) const
Cancels the operation and waits for the notification.
Definition TaskContext.h:80
void SetExecutors(Exec execute_func, Callback callback, client::CancellationContext context)
Sets the executors for the request.
Definition TaskContext.h:128
void Execute() const
Checks for the cancellation, executes the task, and calls the callback with the result or error.
Definition TaskContext.h:70
static TaskContext Create(Exec execute_func, Callback callback, client::CancellationContext context=client::CancellationContext())
Creates the TaskContext instance with the provided task and callback.
Definition TaskContext.h:57
client::CancellationToken CancelToken() const
Provides a token to cancel the task.
Definition TaskContext.h:90
bool operator==(const TaskContext &other) const
Checks whether the values of the TaskContext parameter are the same as the values of the other parame...
Definition TaskContext.h:101
Rules all the other namespaces.
Definition AppleSignInProperties.h:24
A helper for unordered containers.
Definition TaskContext.h:323
size_t operator()(const TaskContext &task_context) const
The hash function for the TaskContext instance.
Definition TaskContext.h:331