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);
100 void InitializeFrom(Storage&& other)
noexcept;
104 template <
typename T, VariableKind Kind>
105 T& GetOrEmplace(Key key) {
106 DataBase*
const old_data = GetGeneric(key);
108 const bool has_existing_variable =
false;
109 return DoEmplace<T, Kind>(key, has_existing_variable);
111 return static_cast<DataImpl<T, Kind>&>(*old_data).Get();
114 template <
typename T, VariableKind Kind>
115 T* GetOptional(Key key)
noexcept {
116 DataBase*
const data = GetGeneric(key);
117 if (!data)
return nullptr;
118 return &
static_cast<DataImpl<T, Kind>&>(*data).Get();
121 template <
typename T, VariableKind Kind>
123 T*
const result = GetOptional<T, Kind>(key);
124 if (!result) ReportVariableNotSet(
typeid(T));
128 template <
typename T, VariableKind Kind,
typename... Args>
129 T& Emplace(Key key, Args&&... args) {
130 DataBase*
const old_data = GetGeneric(key);
131 const bool has_existing_variable = old_data !=
nullptr;
132 auto& result = DoEmplace<T, Kind>(key, has_existing_variable,
133 std::forward<Args>(args)...);
134 if (old_data) old_data->DeleteSelf();
138 template <
typename T, VariableKind Kind>
139 void Erase(Key key)
noexcept {
140 static_assert(Kind == VariableKind::kInherited);
145 DataBase* GetGeneric(Key key)
noexcept;
147 void SetGeneric(Key key, NormalDataBase& node,
bool has_existing_variable);
149 void SetGeneric(Key key, InheritedDataBase& node,
bool has_existing_variable);
151 void EraseInherited(Key key)
noexcept;
154 template <
typename T, VariableKind Kind,
typename... Args>
155 T& DoEmplace(Key key,
bool has_existing_variable, Args&&... args) {
157 std::make_unique<DataImpl<T, Kind>>(key, std::forward<Args>(args)...);
158 SetGeneric(key, *new_data, has_existing_variable);
159 return new_data.release()->Get();
163 utils::FastPimpl<Impl, 40, 8> impl_;
166class Variable
final {
170 Variable(
const Variable&) =
delete;
171 Variable(Variable&&) =
delete;
172 Variable& operator=(
const Variable&) =
delete;
173 Variable& operator=(Variable&&) =
delete;
175 Key GetKey()
const noexcept;
181Storage& GetCurrentStorage()
noexcept;