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
27 public:
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.
38 /// @returns the variable or `nullptr` if variable was not initialized.
39 T* GetOptional() noexcept {
40 return impl::task_local::GetCurrentStorage().GetOptional<T, kVariableKind>(
41 impl_.GetKey());
42 }
43
44 private:
45 static constexpr auto kVariableKind = impl::task_local::VariableKind::kNormal;
46
47 impl::task_local::Variable impl_;
48};
49
50template <typename T>
51T& TaskLocalVariable<T>::operator*() {
52 return impl::task_local::GetCurrentStorage().GetOrEmplace<T, kVariableKind>(
53 impl_.GetKey());
54}
55
56template <typename T>
57T* TaskLocalVariable<T>::operator->() {
58 return &(**this);
59}
60
61} // namespace engine
62
63USERVER_NAMESPACE_END