ALib C++ Library
Library Version: 2402 R1
Documentation generated by doxygen
Loading...
Searching...
No Matches
propertyformatters.hpp
Go to the documentation of this file.
1/** ************************************************************************************************
2 * \file
3 * This header file is part of sub-namespace #alib::lang::format of module \alib_basecamp of
4 * the \aliblong.
5 *
6 * \emoji :copyright: 2013-2024 A-Worx GmbH, Germany.
7 * Published under \ref mainpage_license "Boost Software License".
8 **************************************************************************************************/
9#ifndef HPP_ALIB_LANG_FORMAT_PROPERTY_FORMATTERS
10#define HPP_ALIB_LANG_FORMAT_PROPERTY_FORMATTERS
11
12#if !defined(HPP_ALIB) && !defined(ALIB_DOX)
13# include "alib/alib.hpp"
14#endif
15
16ALIB_ASSERT_MODULE(STRINGS)
18
19#if ALIB_CONFIGURATION
20
21#if !defined(HPP_ALIB_LANG_FORMAT_PROPERTY_FORMATTER)
23#endif
24#if !defined(HPP_ALIB_LANG_FORMAT_EXCEPTIONS)
26#endif
27
28#if !defined(HPP_ALIB_CONFIG_CONFIGURATION)
30#endif
31
32#if !defined(HPP_ALIB_CAMP_MESSAGE_REPORT)
34#endif
35
36#if !defined(_GLIBCXX_UNORDERED_MAP) && !defined(_UNORDERED_MAP_)
37# include <unordered_map>
38#endif
39namespace alib { namespace lang::format {
40
41
42/** ************************************************************************************************
43 * # Introduction # {#alib_ns_strings_propertyformatter_map_overview}
44 *
45 * This template class provides a map of \alib{lang::format;PropertyFormatter} objects that use
46 * format strings which are defined by variables of a \alib{config;Configuration}.
47 *
48 * The use case is about having different versions of how an object is formatted and
49 * to have these versions configurable to end users through the \alib configuration system.
50 *
51\I{################################################################################################}
52 * # Sample # {#alib_ns_strings_propertyformatter_map_sample}
53 * The concept is best explained by a code sample. From the documentation of class
54 * \alib{lang::format;PropertyFormatter}, we are using the sample setup:
55 *
56 * \snippet "DOX_ALIB_STRINGS.cpp" DOX_ALIB_STRINGS_PROPERTY_FORMATTER_1
57 * \snippet "DOX_ALIB_STRINGS.cpp" DOX_ALIB_STRINGS_PROPERTY_FORMATTER_2
58 * \snippet "DOX_ALIB_STRINGS.cpp" DOX_ALIB_STRINGS_PROPERTY_FORMATTER_3
59 *
60 * Three different output formats, \e Short, \e Default and \e All should be supported
61 * We define an enumeration type for this purpose and use macro \ref ALIB_ENUMS_ASSIGN_RECORD
62 * to equip the enumeration with \ref alib_enums_records "ALib Enum Records" of type
63 * \alib{config;VariableDecl}.
64 * In addition, macro \ref ALIB_RESOURCED is used to announce that the record data is defined using
65 * resourced string data.
66 *
67 * \snippet "DOX_ALIB_STRINGS.cpp" DOX_ALIB_STRINGS_PROPERTY_FORMATTER_MAP_1
68 *
69 * The following piece of code is to be performed during \ref alib_manual_bootstrapping "bootstrapping".
70 * We take the freedom to use the resource pool of module \alib{lang::basecamp;BaseCamp}:
71 * \snippet "DOX_ALIB_STRINGS.cpp" DOX_ALIB_STRINGS_PROPERTY_FORMATTER_MAP_2
72 *
73 * \note
74 * The default value and variable comment string would be saved when we write
75 * back the variables to a configuration file. This hints users to the fact that the output format
76 * is changeable, i.e. when they open an INI-file.
77 * See \alib{config;Configuration::FetchFromDefault} for information about how to write built-in
78 * default variables like this to an external configuration file.
79 *
80 * In the next phase of bootstrapping, our enumeration records have to be initialized from the
81 * resource pool:
82 *
83 * \snippet "DOX_ALIB_STRINGS.cpp" DOX_ALIB_STRINGS_PROPERTY_FORMATTER_MAP_22
84 *
85 * With this in place, the \b %PropertyFormatters can be created and method
86 * #Format can be used:
87 *
88 * \snippet "DOX_ALIB_STRINGS.cpp" DOX_ALIB_STRINGS_PROPERTY_FORMATTER_MAP_31
89 *
90 * But we're still not fully done yet: The next goal is to have a lightweight object
91 * that is \"\alib{strings;T_Append;appendable}\" to objects of class \alib{strings;TAString;AString}.
92 * Such object is given with template type \alib{lang::format;PropertyFormatterMapAppendable}.
93 * It is a simple helper struct that holds a reference to the formatter map, the format
94 * enumeration value and the object to format.<br>
95 * We define a shortcut to the type with the right template arguments in place:
96 * \snippet "DOX_ALIB_STRINGS.cpp" DOX_ALIB_STRINGS_PROPERTY_FORMATTER_MAP_32
97 *
98 * Now, we are set and can start using the formatter:
99 * \snippet "DOX_ALIB_STRINGS.cpp" DOX_ALIB_STRINGS_PROPERTY_FORMATTER_MAP_4
100 *
101 * Running the code above produces the following output:
102 * \verbinclude "DOX_ALIB_STRINGS_PROPERTY_FORMATTER_MAP.txt"
103 *
104 * To make the code even shorter, macros may be used:
105 * \snippet "DOX_ALIB_STRINGS.cpp" DOX_ALIB_STRINGS_PROPERTY_FORMATTER_MAP_5
106 *
107 * The output is:
108 * \verbinclude "DOX_ALIB_STRINGS_PROPERTY_FORMATTER_MAP_2.txt"
109 *
110\I{################################################################################################}
111 * # Using The Appendable With Formatters # {#alib_ns_strings_propertyformatter_map_usingwithfmts}
112 * The sample above showcased how to \ref alib_strings_assembly_ttostring "append" a lightweight
113 * object of helper class \alib{lang::format;PropertyFormatterMapAppendable} to objects of class
114 * \alib{strings;TAString;AString}.
115 * A final step is to define the \ref alib::boxing "boxing" interface
116 * \alib{boxing;FAppend} to make boxed objects of our helper type applicable. As the type
117 * itself is already appendable, we can use a built-in simple macro for that:
118 *
119 * \snippet "DOX_ALIB_STRINGS.cpp" DOX_ALIB_STRINGS_PROPERTY_FORMATTER_MAP_6
120 *
121 * As described in the namespace documentation of module \alib_boxing_nl, such interface definition
122 * should be done only once and be placed in the bootstrap section of a software.
123 *
124 * With this, using formatters in combination with our helper struct works fine:
125 * \snippet "DOX_ALIB_STRINGS.cpp" DOX_ALIB_STRINGS_PROPERTY_FORMATTER_MAP_7
126 *
127 * This code produces the following output.
128 * \verbinclude "DOX_ALIB_STRINGS_PROPERTY_FORMATTER_MAP_3.txt"
129 *
130\I{################################################################################################}
131 * # Module Dependencies #
132 * This class is only available if module \alib_config is included in the \alibdist.
133 *
134\I{################################################################################################}
135 * # Reference Documentation #
136 * @throws alib::lang::format::FMTExceptions::MissingConfigurationVariable
137 *
138 * @tparam TFormattable The type that is formatted.
139 * @tparam TVariable The enumeration of variables which defines the format strings.
140 **************************************************************************************************/
141template<typename TFormattable, typename TVariable >
143{
144 protected:
145 /** The callback table for the property formatters (as given in the constructor). */
147
148 /** The configuration used to load (and store the default) format strings from. */
150
151 /** The map of formatters */
152 std::unordered_map<TVariable, PropertyFormatter*> formatters;
153
154 /** A temporary variable to be reused (allocate once pattern). */
156 public:
157 /** The formatter (as given in the constructor). */
159
160
161 public:
162 /**
163 * Constructor storing arguments in fields.
164 * All default values of the variables are stored in the \ref alib::config "configuration"
165 * and thus - if the configuration is write enabled - can be noted by the end-user to be
166 * configurable.
167 *
168 * Parameter \p{formatter} defaults to \c nullptr, which causes this constructor to create
169 * a clone of the formatter returned by \alib{lang::format;Formatter::GetDefault}.
170 * Note, that this is in contrast to the similar parameter of class
171 * \alib{lang::format;PropertyFormatter}, which uses the default formatter itself
172 * in the case that \c nullptr is provided. The rationale behind creating a copy is that
173 * it is quite likely that the \b %PropertyFormatter objects created here are used
174 * nested within other format operations. This is especially true with the use of helper
175 * struct \alib{lang::format;PropertyFormatterMapAppendable}. Now, nested formatting must
176 * not be done with the same formatter object.
177 *
178 *
179 * @param callbackTable The callback table as specified with
180 * \alib{lang::format;PropertyFormatter::TCallbackTable}.
181 * @param configuration The configuration to load the format strings from (and to store
182 * the default values defined by the enum record of \p{TVariable}).
183 * @param formatter The underlying formatter. Used for construction of
184 * \alib{lang::format;PropertyFormatter}s.<br>
185 * Defaults to \c nullptr which denotes to create a copy of the
186 * formatter returned by \alib{lang::format;Formatter::GetDefault}.
187 */
189 config::Configuration& configuration,
190 SPFormatter formatter = nullptr )
191 : callbacks( callbackTable )
192 , config ( configuration )
193 , Formatter( formatter )
194 {
195 if ( Formatter == nullptr )
197
198 for( auto recordIt= EnumRecords<TVariable>().begin() ;
199 recordIt != EnumRecords<TVariable>().end() ; ++recordIt )
200 config.StoreDefault( tempVar.Declare( recordIt.Enum() ) );
201 }
202
203 /**
204 * Destructor. Deletes the \alib{lang::format;PropertyFormatter}s which got created.
205 */
207 {
208 for( auto& formatter : formatters )
209 delete formatter.second;
210 }
211
212 /**
213 * Chooses or - if not yet available - creates the right \alib{lang::format;PropertyFormatter}
214 * and invokes its method \alib{lang::format;PropertyFormatter::Format;Format}.
215 *
216 * @param target The target string to write into.
217 * @param option The user defined formatting option.
218 * @param formattable The custom object which is passed to the callback methods to collect
219 * the formatter arguments.
220 */
221 void Format( AString& target, TVariable option, TFormattable& formattable )
222 {
223 auto formatter= formatters.find( option );
224 if( formatter == formatters.end() )
225 {
226 // find option in the table
227 for( auto varEntryIt= EnumRecords<TVariable>().begin() ;
228 varEntryIt != EnumRecords<TVariable>().end() ; ++varEntryIt )
229 if( varEntryIt.Enum() == option )
230 {
231 if( config.Load( tempVar.Declare( varEntryIt.Enum() ) ) == Priorities::NONE
232 || tempVar.GetString().IsEmpty() )
234 tempVar.Fullname() );
235
236 formatter= formatters.emplace(
237 std::make_pair( option,
240 ).first;
241 break;
242 }
243
244 ALIB_ASSERT_ERROR( formatter != formatters.end(), "FMT",
245 "No entry for option {!Q<>} found in option table of PropertyFormatters.",
246 option )
247 }
248
249 formatter->second->Format( target, formattable );
250 }
251
252}; // class PropertyFormatters
253
254/**
255 * Helper struct for users of class \alib{lang::format;PropertyFormatters}.
256 * Objects of this type are \alib{strings;T_Append;appendable} to \b %AStrings.
257 *
258 * A custom using statement should be used to access this type in a very short fashion,
259 * to make "applications" to \b %AStrings a short call. Alternatively one ore more preprocessor
260 * macros might even lead to shorter invocations. (See sample in class description).
261 */
262
263template<typename TFormattable, typename TOptionEnum >
265{
267 TOptionEnum Option; ///< The format option defining the
268 ///< \alib{lang::format;PropertyFormatter} used.
269 TFormattable& Formattable; ///< The object to be formatted.
270
271
272 /**
273 * Constructor. Just saves the given parameters.
274 * @param pFormatterMap The \alib{lang::format;PropertyFormatters} to use.
275 * @param pOption The format option defining the
276 * \alib{lang::format;PropertyFormatter} used.
277 * @param pFormattable The object to be formatted.
278 */
280 TOptionEnum pOption,
281 TFormattable& pFormattable )
282 : FormatterMap(pFormatterMap)
283 , Option(pOption)
284 , Formattable(pFormattable)
285 {}
286}; // struct PropertyFormatterMapAppendable
287
288
289// #################################################################################################
290// ##### T_Append specialization
291// #################################################################################################
292
293} namespace strings {
294
295#if defined(ALIB_DOX)
296 namespace APPENDABLES { // Documentation fake namespace
297#endif
298
299/**
300 * Specialization of functor \alib{strings;T_Append} for helper struct
301 * \b %PropertyFormatterMapAppendable used to format objects with
302 * \alib{lang::format;PropertyFormatters}.
303 * @tparam TFormattable The formattable object type.
304 * @tparam TOptionEnum The format option enumeration type.
305 */
306template<typename TFormattable, typename TOptionEnum >
307struct T_Append<typename lang::format::PropertyFormatterMapAppendable<TFormattable,TOptionEnum>, character >
308{
309 /**
310 * Invokes the \alib{lang::format;PropertyFormatters::Format} of the formatter map
311 * encapsulated in \p{src}.
312 * @param target The target string.
313 * @param src The helper struct object.
314 */
319};
320
321/**
322 * Specialization of functor \alib{strings;T_Append} for pointers to helper struct
323 * \b %PropertyFormatterMapAppendable used to format objects with
324 * \alib{lang::format;PropertyFormatters}.
325 * @tparam TFormattable The formattable object type.
326 * @tparam TOptionEnum The format option enumeration type.
327 */
328template<typename TFormattable, typename TOptionEnum >
329struct T_Append<typename lang::format::PropertyFormatterMapAppendable<TFormattable,TOptionEnum>*, character >
330{
331 /**
332 * Invokes the \alib{lang::format;PropertyFormatters::Format} of the formatter map
333 * encapsulated in \p{src}.
334 * @param target The target string.
335 * @param src Pointer to the helper struct object.
336 */
341};
342
343#if defined(ALIB_DOX)
344} // APPENDABLES documentation fake namespace
345#endif
346
347} // namespace alib[::strings]
348
349
350/// Type alias in namespace \b alib.
351template<typename TFormattable, typename TOptionEnum >
353
354} // namespace [alib]
355
356#endif // ALIB_CONFIGURATION
357
358#endif // HPP_ALIB_LANG_FORMAT_PROPERTY_FORMATTERS
ALIB_API Priorities Load(Variable &variable)
ALIB_API Priorities StoreDefault(Variable &variable, const String &externalizedValue=nullptr)
ALIB_API const String & Fullname()
Definition variable.cpp:266
ALIB_API Variable & Declare(const VariableDecl &declaration, const Box &replacements)
Definition variable.cpp:77
const String & GetString(int idx=0)
Definition variable.hpp:780
ALIB_API AString & Format(AString &target) const
static SPFormatter GetDefault()
std::vector< IdentifierEntry > TCallbackTable
PropertyFormatters(typename PropertyFormatter::TCallbackTable &callbackTable, config::Configuration &configuration, SPFormatter formatter=nullptr)
void Format(AString &target, TVariable option, TFormattable &formattable)
PropertyFormatter::TCallbackTable & callbacks
std::unordered_map< TVariable, PropertyFormatter * > formatters
constexpr bool IsEmpty() const
Definition string.hpp:414
#define ALIB_ASSERT_MODULE(modulename)
Definition alib.hpp:190
#define ALIB_CALLER_NULLED
Definition alib.hpp:846
#define ALIB_ASSERT_ERROR(cond,...)
Definition alib.hpp:984
Definition alib.cpp:57
lang::Exception Exception
Type alias in namespace alib.
lang::format::PropertyFormatter PropertyFormatter
Type alias in namespace alib.
std::shared_ptr< lang::format::Formatter > SPFormatter
characters::character character
Type alias in namespace alib.
static constexpr ForwardIterator end()
Definition records.hpp:434
TFormattable & Formattable
The object to be formatted.
PropertyFormatters< TFormattable, TOptionEnum > & FormatterMap
The formatter map to use.
PropertyFormatterMapAppendable(PropertyFormatters< TFormattable, TOptionEnum > &pFormatterMap, TOptionEnum pOption, TFormattable &pFormattable)
void operator()(TAString< character > &target, const typename lang::format::PropertyFormatterMapAppendable< TFormattable, TOptionEnum > &src)
void operator()(TAString< character > &target, const typename lang::format::PropertyFormatterMapAppendable< TFormattable, TOptionEnum > *src)