9#include <userver/utils/fast_pimpl.hpp>
11USERVER_NAMESPACE_BEGIN
13namespace engine::impl::task_local {
15using Key = std::size_t;
17enum class VariableKind { kNormal, kInherited };
21 using Deleter =
void (*)(DataBase&)
noexcept;
23 void DeleteSelf()
noexcept;
26 explicit DataBase(Deleter deleter);
29 const Deleter deleter_;
32class NormalDataBase :
public DataBase {
34 template <
typename Derived>
35 NormalDataBase(std::in_place_type_t<Derived>, Key )
36 : DataBase([](DataBase& base)
noexcept {
37 delete &
static_cast<Derived&>(base);
41class InheritedDataBase :
public DataBase {
43 void AddRef()
noexcept;
45 Key GetKey()
const noexcept;
48 template <
typename Derived>
49 InheritedDataBase(std::in_place_type_t<Derived>, Key key)
50 : DataBase([](DataBase& base)
noexcept {
52 if (--
static_cast<InheritedDataBase&>(base).ref_counter_ == 0) {
53 delete &
static_cast<Derived&>(base);
59 std::atomic<std::size_t> ref_counter_{1};
63template <VariableKind Kind>
64using ConditionalDataBase =
65 std::conditional_t<Kind == VariableKind::kInherited, InheritedDataBase,
68template <
typename T, VariableKind Kind>
69class DataImpl
final :
public ConditionalDataBase<Kind> {
70 using Base = ConditionalDataBase<Kind>;
73 template <
typename... Args>
74 explicit DataImpl(Key key, Args&&... args)
75 : Base(std::in_place_type<DataImpl>, key),
76 variable_(std::forward<Args>(args)...) {}
78 T& Get()
noexcept {
return variable_; }
84[[noreturn]]
void ReportVariableNotSet(
const std::type_info& type);
90 Storage(Storage&&) =
delete;
91 Storage& operator=(Storage&&) =
delete;
96 void InheritFrom(Storage& other);
101 void InheritNodeIfExists(Storage& other, Key key);
105 void InitializeFrom(Storage&& other)
noexcept;
109 template <
typename T, VariableKind Kind>
110 T& GetOrEmplace(Key key) {
111 DataBase*
const old_data = GetGeneric(key);
113 const bool has_existing_variable =
false;
114 return DoEmplace<T, Kind>(key, has_existing_variable);
116 return static_cast<DataImpl<T, Kind>&>(*old_data).Get();
119 template <
typename T, VariableKind Kind>
120 T* GetOptional(Key key)
noexcept {
121 DataBase*
const data = GetGeneric(key);
122 if (!data)
return nullptr;
123 return &
static_cast<DataImpl<T, Kind>&>(*data).Get();
126 template <
typename T, VariableKind Kind>
128 T*
const result = GetOptional<T, Kind>(key);
129 if (!result) ReportVariableNotSet(
typeid(T));
133 template <
typename T, VariableKind Kind,
typename... Args>
134 T& Emplace(Key key, Args&&... args) {
135 DataBase*
const old_data = GetGeneric(key);
136 const bool has_existing_variable = old_data !=
nullptr;
137 auto& result = DoEmplace<T, Kind>(key, has_existing_variable,
138 std::forward<Args>(args)...);
139 if (old_data) old_data->DeleteSelf();
143 template <
typename T, VariableKind Kind>
144 void Erase(Key key)
noexcept {
145 static_assert(Kind == VariableKind::kInherited);
150 DataBase* GetGeneric(Key key)
noexcept;
152 void SetGeneric(Key key, NormalDataBase& node,
bool has_existing_variable);
154 void SetGeneric(Key key, InheritedDataBase& node,
bool has_existing_variable);
156 void EraseInherited(Key key)
noexcept;
158 void InheritNode(InheritedDataBase&);
161 template <
typename T, VariableKind Kind,
typename... Args>
162 T& DoEmplace(Key key,
bool has_existing_variable, Args&&... args) {
164 std::make_unique<DataImpl<T, Kind>>(key, std::forward<Args>(args)...);
165 SetGeneric(key, *new_data, has_existing_variable);
166 return new_data.release()->Get();
170 utils::FastPimpl<Impl, 40, 8> impl_;
173class Variable
final {
177 Variable(
const Variable&) =
delete;
178 Variable(Variable&&) =
delete;
179 Variable& operator=(
const Variable&) =
delete;
180 Variable& operator=(Variable&&) =
delete;
182 Key GetKey()
const noexcept;
188Storage& GetCurrentStorage()
noexcept;
190struct InternalTag
final {
191 explicit InternalTag() =
default;