ALib C++ Framework
by
Library Version: 2605 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
declaration.hpp
Go to the documentation of this file.
1//==================================================================================================
2/// \file
3/// This header-file is part of module \alib_variables of the \aliblong.
4///
5/// Copyright 2013-2026 A-Worx GmbH, Germany.
6/// Published under #"mainpage_license".
7//==================================================================================================
8ALIB_EXPORT namespace alib { namespace variables {
9
10class Configuration;
11class Variable;
12
13namespace detail { class Entry; }
14
15//==================================================================================================
16/// \par Introduction
17/// This data record is used as an alternative (and often preferred) method to declare and optionally
18/// already define an #"Variable;ALib Variable".
19/// The record contains the following information:
20/// - The variables' name,
21/// - the variables' type name,
22/// - an optional defaultValue, and
23/// - optional comments.
24///
25/// The latter may be used by an external configuration file to place human-readable comments next
26/// to each configuration entry.
27///
28/// With a #"%var Declaration" instance in place, constructors
29/// #"Variable(Configuration& cfg, const Declaration* )", as well as methods
30/// #"Declare(const Declaration*)", and
31/// #"Try(const Declaration*)" can be used.
32///
33/// Nevertheless, as we will see below, a much nicer option exists.
34///
35/// \par Placeholders
36/// All fields support placeholders \c "%1", \c "%2" ... \c "%N", which are replaced with optional
37/// constructors of class #"%Variable", some of its overloaded methods #"Declare(TEnum);Declare"
38/// and with this classes' static method #".Get".-
39///
40/// This allows defining a series of variables whose name, description, default value and
41/// comments are dependent on runtime information. For example, the text logging types of
42/// camp \alib_alox, have an own name. Now this name fills the placeholders within the variable
43/// declarations that each logger creates. This way, one resourced declaration is copied
44/// to be used by one or more loggers.
45///
46/// \par String Data Allocation
47/// The nature of this type's contained string data is "static" and "read only". Consequently
48/// this classes' members are simple \alib strings, without a own string buffer. The class relies
49/// on the fact that the lifecycle of the string data is permanent, just like C++ string literals
50/// that you might pass to the constructor, or like externalized resource strings, which is described
51/// in the next sections, are.<br>
52/// A little challenge arises when placeholders are used: Here, new string data has to be
53/// allocated. For this, the convenience method #"Configuration::StoreDeclaration;*" is
54/// available. The method not only copies the data into the internal #"MonoAllocator",
55/// but it also checks if a corresponding replaced record was previously already stored. In this
56/// case no next copy is generated, but the old one is re-used.
57/// In the sample of \alox loggers above this means: The repeated creation and deletion of a
58/// logger with the same name generates only one declaration.
59///
60/// If a programmer provides self-generated variable names in combination with declarations,
61/// it has to be ensured that these variable names survive the lifecycle of the declaration.
62/// \note This is not true for the variable names of declared variables. They are duly copied,
63/// allocated, disposed, and recycled by class #"%Configuration".
64///
65///
66/// \par Enum Records
67/// This type inherits class #"ERSerializable" and is enabled to be read from
68/// (externalized) resource data associated with C++ enumerations.
69/// The record associated with an enum element used for construction must be of this type itself.
70/// Consequently, equipping enum type \b MyEnum is performed like this:
71///
72/// ALIB_ENUMS_ASSIGN_RECORD( MyEnum, alib::variables::Declaration )
73///
74/// (For more information, see #"alib_enums_records;ALib Enum Records".)
75///
76/// \par Resourced Enums
77/// Besides defining the enum record type, a custom enum has to have a specialization of the
78/// type traits #"ResourcedTraits".
79/// This is an exception to similar types found across \alib.
80/// Usually, a C++ enum type can be equipped with enum records and then optionally be resourced.
81/// The reason for this exception is that enum records of this type do load fields #"DefaultValue" and
82/// #"Comments" <em>indirectly</em> from resources by adding postfixes <b>_D</b>, respectively <b>_C</b>
83/// to the variable's resource name, along with the variable's underlying enumeration element's
84/// integral value.
85/// This way, both values are loaded from separated resource strings, which has the following
86/// advantages:
87/// - The values may contain the separation character used.
88/// - The values can be manipulated within the (externalized) resources more easily.
89///
90/// \note What was said here does not mean that #"%var Declaration" instances have to be resourced.
91/// The point is that only if declarations are to be associated with C++ enums, which
92/// list the available variables, then this second step of resourcing the enums has
93/// to be made!
94///
95/// With these prerequisites in place, variables can be declared very conveniently by passing just
96/// a C++ enum element of custom enum type to one of the following methods:
97/// - Static method #"Declaration::Get(TEnum);*"
98/// - #"Variable::Variable(Configuration&, TEnum)"
99/// - #"Variable::Variable(Configuration&, TEnum, const Box)"
100/// - #"Variable::Declare(TEnum);*"
101/// - #"Variable::Declare(TEnum, const Box&)"
102/// - #"variables::CampVariable(camp::Camp&, TEnum)"
103/// - #"variables::CampVariable(camp::Camp&, TEnum, const Box)"
104///
105/// Furthermore, a whole set of variables can be declared by passing just the enum type itself
106/// to method
107/// - #"Configuration::PreloadVariables;*".
108///
109/// This is usually done with bootstrap which makes all variables seamlessly available at least
110/// with a resourced default value, or overwritten by configuration files, CLI arguments or
111/// command lines. Usually the using code does not care and just accesses a variables
112/// value through the enumeration.
113///
114/// The resource data has to provide only three values in the following order:
115/// 1. The enum element value (this is mandatory with every resourced enum record).
116/// 2. Base class's field #"ERSerializable::EnumElementName;*".
117/// \note The field #"ERSerializable::MinimumRecognitionLength;*" is not read from the string,
118/// but set to fixed value \c 0.
119/// 3. The typename.
120///
121/// As already noted above, fields #"DefaultValue" and #"Comments" can be defined in two separate
122/// resource strings named like the variable's resource itself with concatenated postfixes
123/// <b>_D</b>, respectively <b>_C</b> and the variable's underlying enumeration element's
124/// integral value. Both resources are optional and not mandatory to be existent.
125///
126/// A sample of variable resources is given with the
127/// #"alib_ns_strings_propertyformatter_map_sample;documentation of class PropertyFormatter".
128///
129/// This makes it very convenient to have all attributes of a variable, including their name
130/// managed independently from the program code and allows localizing variable names to other
131/// languages. Of course, this applies to such variables only which become externalized.
132/// Therefore, this library likewise allows declaring and use variables without providing
133/// an instance of this type.
134///
135/// \par Reference Documentation
136/// \I{CLANGDUMMY}
137//==================================================================================================
140 friend class alib::variables::Variable;
141
142 protected:
143 /// The type of the variable. Corresponds to what is defined with macros
144 /// #"ALIB_VARIABLES_DEFINE_TYPE" and ALIB_VARIABLES_REGISTER_TYPE.<br>
145 /// Built-in types are listed with chapter #"alib_variables_types_builtin" of the Programmer's
146 /// Manual.
148
149 /// The default value provided as an C++ string that may have to be parsed when imported into
150 /// a variable definition. If set, the variable becomes automatically defined with
151 /// #"Priority::DefaultValues" when declared passing this instance.
152 /// @see Method #"DefaultValue".
154
155 /// The configuration variable's comments.
156 /// \note
157 /// If the type trait #"ResourcedTraits" is specialized for an
158 /// enumeration, this field is interpreted as a resource name to load the
159 /// description/comments from.
161
162 public:
163 /// Default constructor.
164 Declaration() =default;
165
166 /// Constructor usually used with static variable declarations (declarations that are not
167 /// using enumeration types associated with #"alib_enums_records;ALib Enum Records" of this
168 /// type).
169 ///
170 /// If used however to define an enum record during bootstrap of software (by user code
171 /// that omits the preferred option of parsing resourced strings to create such records), then
172 /// each parameter of type #"%^String" passed, has to be of "static nature".
173 /// This means, that string buffers and their contents are deemed to survive the life-cycle of
174 /// an application. Usually, C++ string literals are passed in such situation.
175 ///
176 /// @param pName Value for the inherited field #"ERSerializable::EnumElementName;*".
177 /// @param pTypeName Value for field #".typeName".
178 /// @param pDefaultValue Value for field #".defaultValue".
179 /// @param pComments Value for field #".comments".
180 Declaration( const String& pName, const String& pTypeName,
181 const String& pDefaultValue, const String& pComments )
182 : ERSerializable(pName )
183 , typeName (pTypeName )
184 , defaultValue (pDefaultValue )
185 , comments (pComments ) {}
186
187 /// Implementation of #"EnumRecordPrototype::Parse;*".
188 /// \note Field #"ERSerializable::MinimumRecognitionLength;*" is not read from the
189 /// string, but set to fixed value \c 0.
191 void Parse();
192
193 /// Static method that accepts an element of a C++ enum type equipped with
194 /// #"alib_enums_records;ALib Enum Records" of this type, that contains the declaration data.
195 ///
196 /// In the case that a specialization of type trait #"ResourcedTraits"
197 /// exists for the enumeration, #"DefaultValue" and #"Comments" are interpreted as a resource
198 /// name and are loaded with this method - separately from the resource pool.
199 ///
200 /// @tparam TEnum The custom enum type that is associated with variable declarations.
201 /// @param element The desired variable (aka element of type \p{TEnum}.
202 /// @return The resourced declaration associated with the given enumeration \p{element} of type
203 /// \p{TEnum}.
204 template<typename TEnum>
205 requires (EnumRecords<TEnum>::template AreOfType<Declaration>())
206 static const Declaration* Get(TEnum element) {
207 // get enum record singleton
208 const Declaration* result= &enumrecords::GetRecord(element);
209
210 // if resourced, check for default value and comments
211 #if ALIB_RESOURCES
212 if constexpr( resources::HasResources<TEnum>) {
213 NString128 resName;
214 resName << resources::ResourcedTraits<TEnum>::Name() << "_D";
215 integer codePos = resName.Length() - 1;
216
217 // note: we need to do cast the const away. This is OK. We just did not have the
218 // possibility to get the resourced values right away with the record.
219 resName << UnderlyingIntegral( element );
220 const_cast<Declaration*>(result)->defaultValue = ResourcedType<TEnum>::Get( resName ALIB_DBG( , false ) );
221
222 resName[codePos] = 'C';
223 const_cast<Declaration*>(result)->comments = ResourcedType<TEnum>::Get( resName ALIB_DBG( , false ) );
224 }
225 #endif
226
227 return result;
228 }
229
230 /// Returns this configuration variable's type.
231 /// @return The name of this variable.
232 const String& TypeName() const { return typeName; }
233
234 /// Returns this configuration variable's name.
235 /// @return The name of this variable.
236 const String& Name() const { return EnumElementName; }
237
238 /// The default value provided as a C++ string (not escaped).
239 /// If provided, the variable becomes automatically defined with
240 /// #"Priority::DefaultValues".
241 ///
242 /// @return The contents of field #"defaultValue".
243 const String& DefaultValue() const { return defaultValue; }
244
245 /// Returns this configuration variable's comments.
246 /// @return The comments of this variable.
247 const String& Comments() const { return comments; }
248
249}; // struct Declaration
250
251} // namespace alib::[config]
252
253/// Type alias in namespace #"%alib".
255
256} // namespace [alib]
#define ALIB_DLL
#define ALIB_EXPORT
#define ALIB_DBG(...)
constexpr integer Length() const
Definition string.hpp:300
static const Declaration * Get(TEnum element)
const String & Comments() const
const String & DefaultValue() const
Declaration()=default
Default constructor.
const String & TypeName() const
const String & Name() const
Declaration(const String &pName, const String &pTypeName, const String &pDefaultValue, const String &pComments)
const RecordsTraits< TEnum >::Type & GetRecord(TEnum element)
Definition records.hpp:182
Definition alox.cpp:14
lang::integer integer
Type alias in namespace #"%alib".
Definition integers.hpp:149
enumrecords::EnumRecords< TEnum > EnumRecords
Type alias in namespace #"%alib".
Definition records.hpp:475
strings::TString< character > String
Type alias in namespace #"%alib".
Definition string.hpp:2165
NLocalString< 128 > NString128
Type alias name for #"TLocalString;TLocalString<nchar,128>".
variables::Declaration Declaration
Type alias in namespace #"%alib".
String EnumElementName
The name of the enum element.
Definition records.hpp:423
ERSerializable() noexcept=default
Defaulted constructor leaving the record undefined.
static const String & Get()