Stroika Library
3.0d16
Help-Home
Loading...
Searching...
No Matches
LazyInitialized.h
1
/*
2
* Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3
*/
4
#ifndef _Stroika_Foundation_Execution_LazyInitialized_h_
5
#define _Stroika_Foundation_Execution_LazyInitialized_h_ 1
6
7
#include "Stroika/Foundation/StroikaPreComp.h"
8
9
#include <concepts>
10
#include <functional>
11
#include <mutex>
12
13
#include "Stroika/Foundation/Common/Common.h"
14
15
/*
16
* \note Code-Status: <a href="Code-Status.md#Beta">Beta</a>
17
*/
18
19
namespace
Stroika::Foundation::Execution
{
20
21
/**
22
* \brief value-object, where the value construction is delayed until first needed (can be handy to avoid c++ include/initializer deadly embrace)
23
*
24
* Also can be used to 'lazy initialize' facilities that might be costly to setup, but might never be used.
25
*
26
* Can be used to initialize a static constant object - declared at file scope - dependent on another file-scope data object,
27
* without incurring the pain of static initialization problems (before main). Often this is not needed, if you just
28
* make the dependent objects constexpr. But sometimes you cannot do that.
29
*
30
* LazyInitialized<T> acts mostly like a T (as much as I could figure out how to).
31
*
32
* This object (at least the magic init part) - is fully internally synchronized (though other operations of T itself are in general not).
33
*
34
* This object CAN be constructed before main, and accessed before main (after constructed) - but its up to caller to assure
35
* the 'oneTimeGetter' is safe to call when called.
36
*
37
* @aliases for ConstantProperty, 'virtual constant', VirtualConstant
38
*
39
* \note If you have an object 'obj' which MAYBE a T, or LazyInitialized<T>, you can convert it to type T
40
* with static_cast<T> (obj).
41
*
42
* \par Example Usage
43
* \code
44
* // say not legal to call EVP_md5 til you've initialized openssl, and maybe you never will - but still want to declare but
45
* // not use these constants - or at least declare the constants in a file/module (file scope so constructed before main) and
46
* // initialize openssl from after main starts?
47
* const LazyInitialized<DigestAlgorithm> DigestAlgorithms::kMD5{[] () { return ::EVP_md5 (); }};
48
* \endcode
49
*
50
* \par Example Usage
51
* \code
52
* const LazyInitialized<Sequence<filesystem::path>> Execution::kPath{[] () -> Sequence<filesystem::path> {
53
* if (const char* env_p = std::getenv ("PATH")) {
54
* String pathVar = String::FromNarrowSDKString (env_p);
55
* return pathVar.Tokenize ({':'}).Map<Sequence<filesystem::path>> ([] (auto i) { return i.template As<filesystem::path> (); });
56
* }
57
* return {};
58
* }};
59
* \endcode
60
*
61
* \par Example ALTERNATIVE (use lambda as with LazyInitialize but directly invoke) - but this invoked before main()
62
* \code
63
* const Sequence<filesystem::path> Execution::kPath{[] () -> Sequence<filesystem::path> {
64
* if (const char* env_p = std::getenv ("PATH")) {
65
* String pathVar = String::FromNarrowSDKString (env_p);
66
* return pathVar.Tokenize ({':'}).Map<Sequence<filesystem::path>> ([] (auto i) { return i.template As<filesystem::path> (); });
67
* }
68
* return {};
69
* } ()};
70
* \endcode
71
*
72
* \par Example Usage
73
* \code
74
* inline String kXGetter_ () { return "X"; }
75
* const LazyInitialized<String> kX {kXGetter_};
76
* ...
77
* const String a = kX;
78
* \endcode
79
*
80
* \note it would be HIGHLY DESIRABLE if C++ allowed operator'.' overloading, as accessing one of these
81
* values without assigning to a temporary first - means that you cannot directly call its methods.
82
* That's a bit awkward.
83
*
84
* So if you have a type T, with method m(), and variable of type T t.
85
* Your starter code might be:
86
* T t;
87
* t.m ();
88
* When you replace 'T t' with
89
* ConstantProperty<T> t;
90
* you must call t().m();
91
* OR
92
* you must call t->m();
93
*
94
* \note C++ also only allows one level of automatic operator conversions, so things like comparing
95
* optional<T> {} == LazyInitialized<T,...> {} won't work. To workaround, simply
96
* apply () after the LazyInitialized<> instance.
97
*/
98
template
<
typename
T>
99
class
LazyInitialized
{
100
public
:
101
/**
102
* oneTimeGetter is a function (can be a lambda()) which computes the given value. It is called
103
* just once, and LAZILY, the first time the given VirtualConstant value is required.
104
*
105
* LazyInitialized (ONE TIME GETTER) - is the normal way to use LazyInitialized
106
* LazyInitialized (T) - somewhat pointless, but you can do it....
107
* copy-constructible
108
*/
109
LazyInitialized
() =
delete
;
110
template
<invocable F>
111
constexpr
LazyInitialized
(F&& oneTimeGetter)
112
requires
(convertible_to<invoke_result_t<F>, T>);
113
constexpr
LazyInitialized
(
const
T& v);
114
constexpr
LazyInitialized
(
const
LazyInitialized
&) =
delete
;
115
116
public
:
117
/**
118
*/
119
nonvirtual
LazyInitialized
& operator= (
const
LazyInitialized
&) =
delete
;
120
nonvirtual
LazyInitialized
& operator= (
const
T&);
121
122
public
:
123
/**
124
*/
125
constexpr
~LazyInitialized
();
126
127
public
:
128
/**
129
* A LazyInitialized can be automatically assigned to its underlying base type.
130
* Due to how conversion operators work, this won't always be helpful (like with overloading
131
* or multiple levels of conversions). But when it works (80% of the time) - its helpful.
132
*/
133
nonvirtual
constexpr
operator
const
T ()
const
;
134
135
public
:
136
/**
137
* Just use the function syntax, and you get back the initialized value.
138
*
139
* \par Example Usage
140
* \code
141
* namespace PredefinedInternetMediaType { const inline Execution::LazyInitialized<InternetMediaType> kPNG...
142
*
143
* bool checkIsImage1 = PredefinedInternetMediaType::kPNG().IsA (InternetMediaTypes::Wildcards::kImage);
144
* \endcode
145
*/
146
nonvirtual
const
T
operator()
()
const
;
147
148
public
:
149
/**
150
* Just use the operator-> syntax, and you get back the wrapper objects value (initializing if needed).
151
*
152
* \par Example Usage
153
* \code
154
* namespace PredefinedInternetMediaType { const inline Execution::LazyInitialized<InternetMediaType> kPNG = ...
155
*
156
* bool checkIsImage2 = PredefinedInternetMediaType::kPNG->IsA (InternetMediaTypes::Wildcards::kImage);
157
* \endcode
158
*/
159
nonvirtual T*
operator->
();
160
nonvirtual
const
T*
operator->
()
const
;
161
162
private
:
163
mutable
once_flag fOnceFlag_;
// cannot go in union cuz this 'discriminates' the union
164
// small space savings - don't need both getter and value at same time
165
union
{
166
mutable
T fValue_;
167
mutable
function<T (
void
)> fOneTimeGetter_;
168
};
169
170
private
:
171
nonvirtual T& Getter_ ();
172
nonvirtual
const
T& Getter_ ()
const
;
173
};
174
175
}
176
177
/*
178
********************************************************************************
179
***************************** Implementation Details ***************************
180
********************************************************************************
181
*/
182
#include "LazyInitialized.inl"
183
184
#endif
/*_Stroika_Foundation_Execution_LazyInitialized_h_*/
Stroika::Foundation::Execution::LazyInitialized
value-object, where the value construction is delayed until first needed (can be handy to avoid c++ i...
Definition
LazyInitialized.h:99
Stroika::Foundation::Execution::LazyInitialized::operator()
nonvirtual const T operator()() const
Definition
LazyInitialized.inl:62
Stroika::Foundation::Execution::LazyInitialized::LazyInitialized
LazyInitialized()=delete
Stroika::Foundation::Execution::LazyInitialized::operator->
nonvirtual T * operator->()
Definition
LazyInitialized.inl:67
Stroika::Foundation::Execution
Definition
SDKString.inl:7
Library
Sources
Stroika
Foundation
Execution
LazyInitialized.h
Generated by
1.9.8