userver: userver/engine/task/local_variable.hpp Source File
Loading...
Searching...
No Matches
local_variable.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/engine/task/local_variable.hpp
4/// @brief @copybrief engine::TaskLocalVariable
5
6#include <type_traits>
7
8#include <userver/engine/impl/task_local_storage.hpp>
9
10USERVER_NAMESPACE_BEGIN
11
12namespace engine {
13
14/// @ingroup userver_concurrency
15///
16/// @brief TaskLocalVariable is a per-coroutine variable of arbitrary type.
17///
18/// It is an alternative to `thread_local`, but per-task instead of per-thread.
19///
20/// The order of destruction of task-local variables is inverse to the order of
21/// initialization.
22template <typename T>
23class TaskLocalVariable final {
24 static_assert(!std::is_reference_v<T>);
25 static_assert(!std::is_const_v<T>);
26
27public:
28 /// @brief Get the instance of the variable for the current coroutine.
29 /// Initializes (default constructs) the variable if it was not previously
30 /// initialized.
31 /// @note Must be called from a coroutine, otherwise it is UB.
32 T& operator*();
33
34 /// @overload
35 T* operator->();
36
37 /// @brief Get the variable instance for the current task, or emplace a new
38 /// one with the given arguments.
39 /// @note Must be called from a coroutine, otherwise it is UB.
40 template <typename... Args>
41 T& GetOrEmplace(Args&&... args) {
42 return impl::task_local::GetCurrentStorage()
43 .GetOrEmplace<T, kVariableKind>(impl_.GetKey(), std::forward<Args>(args)...);
44 }
45
46 /// @brief Get the variable instance for the current task.
47 /// @returns the variable or `nullptr` if the variable was not initialized,
48 /// was already destroyed, or is being destroyed right now. That is,
49 /// a non-null result is guaranteed to point to a variable whose
50 /// destruction has not started (the variable is unset before its
51 /// destructor is invoked, as in POSIX `pthread_getspecific`).
52 T* GetOptional() noexcept {
53 return impl::task_local::GetCurrentStorage().GetOptional<T, kVariableKind>(impl_.GetKey());
54 }
55
56private:
57 static constexpr auto kVariableKind = impl::task_local::VariableKind::kNormal;
58
59 impl::task_local::Variable impl_;
60};
61
62template <typename T>
63T& TaskLocalVariable<T>::operator*() {
64 return impl::task_local::GetCurrentStorage().GetOrEmplace<T, kVariableKind>(impl_.GetKey());
65}
66
67template <typename T>
68T* TaskLocalVariable<T>::operator->() {
69 return &(**this);
70}
71
72} // namespace engine
73
74USERVER_NAMESPACE_END