Audacity 3.2.0
GlobalVariable.h
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 @file GlobalVariable.h
6
7 Paul Licameli
8
9 **********************************************************************/
10#ifndef __AUDACITY_GLOBAL_VARIABLE__
11#define __AUDACITY_GLOBAL_VARIABLE__
12
13#include <functional>
14#include <memory>
15#include <optional>
16#include <type_traits>
17#include <utility>
18
20
33template <typename Tag, typename Type, auto initializer = nullptr,
34 bool ScopedOnly = true>
36 struct dummy{ explicit dummy(){} };
37public:
39 using stored_type = Type;
40 using mutable_type = std::remove_const_t<Type>;
41
43 static stored_type& Get()
44 {
45 // Force generation of non-inline Assign, in case it needs dllexport linkage
47 return Instance();
48 }
49
51
53 [[nodiscard]]
54 static auto Set( std::conditional_t<ScopedOnly, dummy,
55 mutable_type> replacement) -> std::conditional_t<ScopedOnly, void,
57 {
58 if constexpr (!ScopedOnly)
59 return Assign(std::move(replacement));
60 }
61
63
70 class Scope
71 {
72 public:
73 explicit Scope(mutable_type value)
74 : m_previous{ Assign(std::move(value)) }
75 {}
76 Scope(Scope &&other) = default;
77 Scope &operator=(Scope &&other) = default;
79 {
80 if constexpr (ScopedOnly)
81 Assign(std::move(m_previous));
82 else if (m_previous)
83 Assign(std::move(*m_previous));
84 }
86 void Commit()
87 {
88 static_assert(!ScopedOnly);
89 m_previous.reset();
90 }
91 bool HasValue() const
92 {
93 if constexpr (ScopedOnly)
94 return true;
95 else
96 return m_previous.has_value();
97 }
98
99 private:
100 std::conditional_t<ScopedOnly, mutable_type, std::optional<mutable_type>>
102 };
103
117 struct Initializer { Initializer() { Instance(); } };
118
119private:
121 GlobalVariable() = delete;
122
125 {
126 static_assert(!std::is_reference_v<stored_type>);
127 if constexpr (std::is_convertible_v<
128 decltype(initializer), mutable_type
129 >) {
130 static mutable_type instance{ initializer };
131 return instance;
132 }
133 else if constexpr (initializer != nullptr) {
134 static mutable_type instance{ initializer() };
135 return instance;
136 }
137 else {
138 static mutable_type instance;
139 return instance;
140 }
141 }
142
143 static mutable_type Assign(mutable_type &&replacement)
144 {
145 auto &instance = Instance();
146 auto result = std::move(instance);
147 instance = std::move(replacement);
148 return result;
149 }
150};
151
153template<typename Tag, typename Signature, auto Default = nullptr,
154 auto... Options>
155class GlobalHook : public GlobalVariable<Tag,
156 const std::function<Signature>, Default, Options...
157>
158{
159public:
160 using result_type = typename std::function<Signature>::result_type;
161 using Scope = typename GlobalVariable<Tag,
162 const std::function<Signature>, Default, Options...
163 >::Scope;
164
166
168 template<typename... Arguments>
169 static result_type Call(Arguments &&...arguments)
170 {
171 auto &fn = GlobalHook::Get();
172 if (fn)
173 return fn(std::forward<Arguments>(arguments)...);
174 else if constexpr (std::is_void_v<result_type>)
175 return;
176 else
177 return result_type{};
178 }
179
181 template<typename Derived>
183 // Generic lambda is coerced to the needed pointer-to-function type
184 [](auto &&...args) -> result_type { return
185 std::make_unique<Derived>(std::forward<decltype(args)>(args)...);
186 }
187 }{}};
188
190 template<typename Derived>
192 // Generic lambda is coerced to the needed pointer-to-function type
193 [](auto &&...args) -> result_type { return
194 std::make_shared<Derived>(std::forward<decltype(args)>(args)...);
195 }
196 }{}};
197};
198
201
204template<typename Tag, auto DefaultFunction, auto... Options>
205class DefaultedGlobalHook : public GlobalHook< Tag,
206 std::remove_pointer_t<decltype(DefaultFunction)>, DefaultFunction,
207 Options...
208>
209{
210};
211
212#endif
static const auto fn
Global function-valued variable, adding a convenient Call()
typename std::function< Signature >::result_type result_type
static result_type Call(Arguments &&...arguments)
Null check of the installed function is done for you.
typename GlobalVariable< Tag, const std::function< Signature >, Default, Options... >::Scope Scope
RAII guard for temporary installation of a value; movable.
std::conditional_t< ScopedOnly, mutable_type, std::optional< mutable_type > > m_previous
Scope(mutable_type value)
Scope & operator=(Scope &&other)=default
Scope(Scope &&other)=default
Class template to generate global variables.
GlobalVariable()=delete
Use static functions only. Don't directly construct this.
static mutable_type & Instance()
Generate the static variable.
std::remove_const_t< Type > mutable_type
static mutable_type Assign(mutable_type &&replacement)
static auto Set(std::conditional_t< ScopedOnly, dummy, mutable_type > replacement) -> std::conditional_t< ScopedOnly, void, mutable_type >
Move in a new value, move out and return the previous.
static stored_type & Get()
Get the installed value.
NumericFormatSymbol Default(const NumericConverterType &type)
Returns the default format for the type or empty symbol, if no default symbol is registered.
STL namespace.
Can generate overriding hooks of shared_ptr factories.
Can generate overriding hooks of unique_ptr factories.
Can guarantee that the global variable's lifetime encloses those of other objects of static duration.