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