ALib C++ Library
Library Version: 2402 R1
Documentation generated by doxygen
Loading...
Searching...
No Matches
exception.hpp
Go to the documentation of this file.
1/** ************************************************************************************************
2 * \file
3 * This header file is part of module \alib_basecamp 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_CAMP_MESSAGE_EXCEPTION
9#define HPP_ALIB_CAMP_MESSAGE_EXCEPTION 1
10
11#if !defined (HPP_ALIB_CAMP_MESSAGE_MESSAGE)
13#endif
14
16
17#if !defined (HPP_ALIB_ENUMS_RECORDS)
18# include "alib/enums/records.hpp"
19#endif
20
21#if !defined (HPP_ALIB_LANG_RESOURCES_RESOURCES)
23#endif
24
25
26
27namespace alib { namespace lang {
28
29/** Internal details of namespace #alib::lang. */
30namespace detail
31{
32 /**
33 * An element of the (single) linked list of message entries of class exception.
34 * A pointer to this type is used as the template parameter \p{TContained} of
35 * struct \alib{monomem;SelfContained} that class \alib{lang;Exception} is derived from
36 * and this way allocated (self-contained) in a \alib{monomem;MonoAllocator}.
37 */
39 {
40 Message message; ///< The message,
41 ExceptionEntry* next = nullptr; ///< A pointer to the next message.
42 };
43}
44
45/** ************************************************************************************************
46 * An \ref alib_enums_records "ALib Enum Record" type used to equip custom enumeration types
47 * with records that define an entries of class \alib{lang;Exception}.
48 *
49 * Besides the exception entry name, the only field this record adds provides a textual description
50 * of an exception entry.
51 * If TMP struct \alib{lang::resources;T_Resourced} is likewise specialized for a custom enumeration type,
52 * then this field is interpreted as a resource name to load the description from.
53 *
54 * When parsing the enum records from string data, inherited field
55 * \alib{enums;ERSerializable::MinimumRecognitionLength} is not parsed from the string, but set to
56 * fixed value \c 0. Therefore, only three fields have to be given per record:
57 *
58 * 1. The custom integral enum value (this is mandatory with every resourced enum record).
59 * 2. A string denoting inherited field \alib{enums;ERSerializable::EnumElementName}.
60 * 3. A string containing the description text, respectively the resource name of that.
61 **************************************************************************************************/
63{
64 /**
65 * The description of the exception.
66 * \note
67 * If TMP struct \alib{lang::resources;T_Resourced} is specialized for an enumeration,
68 * this field is interpreted as a resource name to load the description from.
69 */
71
72 /** Default constructor leaving the record undefined. */
73 ERException() noexcept = default;
74
75
76 /**
77 * Constructor usually used with static variable declarations (declarations that are not
78 * using enumeration types associated with \ref alib_enums_records "ALib Enum Records" of this
79 * type).
80 *
81 * If used however to define an enum record during bootstrap of a software (by user code
82 * that omits the preferred option of parsing resourced strings to create such records), then
83 * each parameter of type \b String passed, has to be of "static nature".
84 * This means, that string buffers and their contents are deemed to survive the life-cycle of
85 * an application. Usually, C++ string literals are passed in such situation.
86 * @param name The name of the exception. (Usually the enum element's C++ name.)
87 * @param description The exception's descrption. (Usually a format string.)
88 */
89 ERException(const String& name, const String& description) noexcept
90 : ERSerializable(name)
91 , DescriptionOrItsResourceName(description)
92 {}
93
94 /**
95 * Implementation of \alib{enums;EnumRecordPrototype::Parse}.
96 * \note Field \alib{enums;ERSerializable::MinimumRecognitionLength} is not read from the string, but set
97 * to fixed value \c 0.
98 */
100 void Parse();
101};
102
103/** ************************************************************************************************
104 * The (one and only) <em>"throwable"</em> used with \aliblong.
105 *
106 * Please consult the Programmer's Manual of module \alib_basecamp for
107 * \ref alib_basecamp_message_exceptions "detailed information" about this class and its use.
108 *
109 * In short, this class implements the following "exception paradigm":
110 * - There is only one exception type.
111 * - With creation, a first "message" is added to the list of messages.
112 * - While unwinding the stack new messages may be added to the list.
113 * - A new message may either add information to the previous entry or may change the meaning
114 * of the exception.
115 * - Messages contain IDs of \alib{boxing;Enum;arbitrary scoped enumeration types}.
116 * This allows structured processing of Exceptions.
117 *
118 * This type uses a smart memory model leveraging class \alib{monomem;MonoAllocator}
119 * which places all internal data in \alib{monomem;MonoAllocator}, even this object itself!
120 * With that, exceptions usually perform only one single dynamic
121 * allocation, even if various messages with various data objects (\alib{boxing;Box;boxes}) are
122 * attached.
123 *
124 * Although the footprint (<c>sizeof</c>) of the class is just the size of a pointer
125 * (One into the first chunk of memory of the monotonic allocator), objects of this type have to
126 * (can only)
127 * be caught by reference. Copy-construction and assignment is deleted.
128 **************************************************************************************************/
129class Exception : protected monomem::SelfContained<detail::ExceptionEntry*>
130{
131 public:
132 /** ****************************************************************************************
133 * Deleted copy constructor. Exceptions must be caught only as references.
134 ******************************************************************************************/
135 Exception( Exception& ) = delete;
136
137 /** ****************************************************************************************
138 * Move constructor moves the entries and deletes them in source object.
139 *
140 * @param src The object to move.
141 ******************************************************************************************/
142 Exception(Exception&& src) noexcept
143 : SelfContained( std::move(src) )
144 {}
145
146 /** ****************************************************************************************
147 * Deleted copy assignment operator.
148 * @return Nothing (deleted).
149 ******************************************************************************************/
151
152 /** ****************************************************************************************
153 * Deleted move assignment operator.
154 * @return Nothing (deleted).
155 ******************************************************************************************/
157
158 /** ****************************************************************************************
159 * Default constructor.
160 * \note If this constructor is used, one or more invocations of #Add have be performed
161 * prior to throwing the exception. Otherwise, the exception does not contain any
162 * information. From this perspective, it could be said that this constructor is
163 * provided for the cases where either more than one entry is added in a loop or
164 * different types of entries are added in a later <c>if statement</c> after
165 * construction. Otherwise, this constructor should be avoided.
166 ******************************************************************************************/
168 : SelfContained( 1024, 100 )
169 {}
170
171 /** ****************************************************************************************
172 * Constructor that allows to provide the size of the allocated chunk of memory in bytes.
173 * With other constructors, this size is fixed to \c 1024.
174 * A higher size may avoid a second allocation (which is not problematic in usual cases).
175 *
176 * \note The use of this constructor is advisable only in seldom cases. The same
177 * notes as given with the documentation of the default constructor apply.
178 *
179 * @param initialChunkSize The initial allocation size of the internal
180 * \alib{monomem;MonoAllocator}.
181 * @param chunkGrowthInPercent Optional growth faktor in percent (*100), applied to each
182 * allocation of a next chunk size.
183 * Values provided should be greater than 100.<p>
184 * Defaults to 100, which does not increase subsequent
185 * chunk allocations.
186 ******************************************************************************************/
187 template<typename TIntegral>
188 Exception( TIntegral initialChunkSize, int chunkGrowthInPercent= 100 )
189 : SelfContained( static_cast<size_t>(initialChunkSize), chunkGrowthInPercent )
190 {
191 static_assert( !std::is_enum<TIntegral>::value,
192 "Erroneous use of Exception constructor. Enumeration element given "
193 "without caller information. Add macro ALIB_CALLER or "
194 "ALIB_CALLER_NULLED as a first argument." );
195 }
196
197 /** ****************************************************************************************
198 * Constructs an exception and invokes #Add to create the initial message entry.
199 *
200 * In case that the enumeration type of given parameter \p{type} is equipped with
201 * \ref alib_enums_records "ALib Enum Records" according to record type
202 * \alib{lang;ERException}, the first argument added to the message entry
203 * is collected from the corresponding enum record. For more
204 * information consult the \ref alib_basecamp_message_exceptions_res "corresponding section" of the
205 * Programmer's Manual.
206 *
207 * @tparam TEnum Template type of the enumeration element.
208 * @tparam TArgs The variadic template argument types.
209 *
210 * @param file File name of the place of entry creation.
211 * @param line Line number of the place of entry creation.
212 * @param func Function/method name of the place of entry creation.
213 * @param type An enum element denoting the message type.
214 * @param args The message arguments.
215 ******************************************************************************************/
216 template<typename TEnum, typename... TArgs >
217 Exception( const NCString& file, int line, const NCString& func,
218 TEnum type, TArgs&&... args )
219 : SelfContained( 1024, 100 )
220 {
221 Add( file,line,func, type, std::forward<TArgs>(args)... );
222 }
223
224 /** ****************************************************************************************
225 * Destructor
226 ******************************************************************************************/
227 ~Exception() = default;
228
229 // #############################################################################################
230 // Interface
231 // #############################################################################################
232 /** ****************************************************************************************
233 * Returns the last message in the list of stored messages.
234 *
235 * @return The most recently added message.
236 ******************************************************************************************/
238 Message& Back() const;
239
240 /** ****************************************************************************************
241 * Returns the number of message entries.
242 *
243 * @return The number of messages added to this exception.
244 ******************************************************************************************/
246 int Size() const;
247
248 /** ****************************************************************************************
249 * Returns field \alib{lang;Message::Type} of the \b last message in the list of
250 * messages that has a positive underlying enum element value.
251 *
252 * The rationale here is explained in the
253 * \ref alib_basecamp_message_exception_types "Programmer's Manual".
254 * In short, positive and negative enum element values are used to separated
255 * "informational entries" (with a negative value) from message entries that change the
256 * type of the exception (positive value). Usually, only the latter ones are processed
257 * by exception handlers.
258 *
259 * @return The most high level exception code.
260 ******************************************************************************************/
262 const Enum& Type() const;
263
264 /** ****************************************************************************************
265 * Adds a new message to this exception. The parameters of this method are
266 * exactly those that are expected by the \alib{lang;Message::Message;constructor}
267 * of class \alib{lang;Message}.
268 *
269 * The message object itself is created in the monotonic allocator of this exception
270 * received by inherited method \alib{monomem;SelfContained::Allocator}.
271 *
272 * After the insertion, method \alib{lang;Message;CloneArguments} is invoked, which
273 * creates "safe" copies of the arguments to guarantee their survival during this
274 * exception's lifespan.
275 *
276 * If the enumeration type \p{TEnum} (which is deduced from parameter \p{type}) is equipped
277 * with \ref alib_enums_records "ALib Enum Records" of type \alib{lang;ERException},
278 * an additional message argument is \b prepended to the message
279 * This argument is of string type and is taken from field
280 * \alib{lang::ERException;DescriptionOrItsResourceName} of the associated enum record.
281 * As described in chapter alib_basecamp_message_exceptions_args of the Programmer's Manual, it is
282 * proposed that this argument of string type, is a formatter-string that is used to format
283 * the arguments of an exception into a human readable message.
284 *
285 * If furthermore, TMP struct \alib{lang::resources;T_Resourced} is specialized for enumeration
286 * type \p{TEnum}, then the value of \b DescriptionOrItsResourceName is not directly
287 * prepended, but interpreted as a resource name. In this case the resourced description
288 * is prepended instead.
289 *
290 * For more information consult chapter \ref alib_basecamp_message_exceptions_res of the
291 * Programmer's Manual.
292 *
293 * @tparam TEnum The enumeration type used to define the message type.
294 * @tparam TArgs The variadic template argument types.
295 *
296 * @param file File name of the place of entry creation.
297 * @param line Line number of the place of entry creation.
298 * @param func Function/method name of the place of entry creation.
299 * @param type An enum element denoting the message type.
300 * @param args The message arguments.
301 * @return Return <c>*this</c> to allow concatenated operations or use with throw statement.
302 ******************************************************************************************/
303 template <typename TEnum, typename... TArgs> inline
304 Exception& Add( const NCString& file, int line, const NCString& func, TEnum type, TArgs&&... args )
305 {
306 Message* newMessage= allocMessageLink();
307 new (newMessage) Message( file,line,func, &Allocator(), lang::Responsibility::KeepWithSender, type );
308 newMessage->Add( std::forward<TArgs>( args )... );
309 finalizeMessage( newMessage,
313
314 return *this;
315 }
316
317 /** ****************************************************************************************
318 * Uses class \alib{lang::format;Paragraphs} to write all entries of this
319 * exception into the given narrow \p{target} string.
320 * Entries are expected to have a format string set as their description meta information
321 * that corresponds (in respect to the placeholders within the string) to the arguments
322 * found in the entry.
323 *
324 * @param target The target string to format the entry description to.
325 * @return Returns given \b AString \p target for convenience.
326 ******************************************************************************************/
328 AString& Format( AString& target ) const;
329
330 /** ****************************************************************************************
331 * Same as \alib{lang::Exception;Format(AString&)const;Format(AString&)}, but writing
332 * to a string of complement character width.
333 *
334 * @param target The target string to format the entry description to.
335 * @return Returns given \b AString \p target for convenience.
336 ******************************************************************************************/
340 {
341 target << Format();
342 return target;
343 }
344
345 /** ****************************************************************************************
346 * Inline shortcut to \alib{lang::Exception;Format(AString&)const;Format(AString&)}
347 * that creates, uses and returns an AString value for the exception's description.
348 *
349 * @return The formatted description of the Exception.
350 ******************************************************************************************/
352 {
353 AString result;
354 Format( result );
355 return result;
356 }
357
358
359 // #############################################################################################
360 // std::ForwardIterator
361 // #############################################################################################
362 protected:
363 /** ****************************************************************************************
364 * Implementation of \c std::ForwardIterator that iterates all \alib{lang;Message}
365 * entries of an \b %Exception.
366 ******************************************************************************************/
367 template<typename TConstOrMutableMessage>
369 {
370 protected:
371 /** The pointer to the actual node. */
373
374 public:
375 using iterator_category = std::forward_iterator_tag; ///< Implementation of <c>std::iterator_traits</c>.
376 using value_type = Message ; ///< Implementation of <c>std::iterator_traits</c>.
377 using difference_type = integer ; ///< Implementation of <c>std::iterator_traits</c>.
378 using pointer = TConstOrMutableMessage* ; ///< Implementation of <c>std::iterator_traits</c>.
379 using reference = TConstOrMutableMessage& ; ///< Implementation of <c>std::iterator_traits</c>.
380
381 public:
382 /** Constructor.
383 * @param _p Our initial value */
384 explicit IteratorType( detail::ExceptionEntry* _p = nullptr )
385 : p(_p)
386 {}
387
388 /** Constructor taking a constant entry pointer.
389 * Available for the constant version of this iterator only.
390 * @param entry The initial message entry. */
391 ATMP_SELECT_IF_1TP( typename TConstEntry, std::is_const<TConstEntry>::value )
392 IteratorType( TConstEntry* entry )
393 : p(const_cast<detail::ExceptionEntry*>(entry))
394 {}
395
396
397 /** Constructor taking a mutable iterator.
398 * Available for the constant version of this iterator only.
399 * @param it The mutable iterator to used to construct this constant one. */
400 ATMP_SELECT_IF_1TP( typename TMutableIterator, ATMP_EQ(TMutableIterator, IteratorType<const Message> ) )
401 IteratorType( TMutableIterator it )
402 : p(it)
403 {}
404
405 //###################### To satisfy concept of InputIterator ######################
406
407 /** Prefix increment operator.
408 * @return A reference to ourselves. */
410 {
411 p= p->next;
412 return *this;
413 }
414
415 /** Postfix increment operator.
416 * @return A new iterator object that is not increased, yet. */
418 {
419 auto result= IteratorType(p);
420 p= p->next;
421 return result;
422 }
423
424 /** Comparison operator.
425 * @param other The iterator to compare ourselves to.
426 * @return \c true if this and given iterator are equal, \c false otherwise. */
427 bool operator==(IteratorType other) const
428 {
429 return p == other.p;
430 }
431
432 /** Comparison operator.
433 * @param other The iterator to compare ourselves to.
434 * @return \c true if this and given iterator are not equal, \c false otherwise. */
435 bool operator!=(IteratorType other) const
436 {
437 return p != other.p;
438 }
439
440 /** Retrieves the message that this iterator references.
441 * @return The message reference. */
442 TConstOrMutableMessage& operator*() const
443 {
444 return p->message;
445 }
446
447 /** Retrieves the pointer to the message that this iterator references.
448 * @return The message pointer. */
449 TConstOrMutableMessage* operator->() const
450 {
451 return &p->message;
452 }
453 };
454
455 public:
456 /** The constant iterator exposed by this container. */
457 using ConstForwardIterator = IteratorType <const Message>;
458
459 /** The mutable iterator exposed by this container. */
460 using ForwardIterator = IteratorType < Message>;
461
462
463 /**
464 * Returns an iterator pointing to the first message entry.
465 * @return A forward iterator to the first message entry.
466 */
468 {
469 return ForwardIterator( Self() );
470 }
471
472 /**
473 * Returns an iterator representing the end of the message entries.
474 * @return The end of this exception's message entries.
475 */
477 {
478 return ForwardIterator( nullptr );
479 }
480
481 /**
482 * Returns an iterator pointing to the first message entry.
483 * @return A forward iterator to the first message entry.
484 */
486 {
487 return ConstForwardIterator( Self() );
488 }
489
490 /**
491 * Returns an iterator representing the end of the message entries.
492 * @return The end of this exception's message entries.
493 */
495 {
496 return ConstForwardIterator( nullptr );
497 }
498
499
500 // #############################################################################################
501 // protected methods
502 // #############################################################################################
503 protected:
504 /** ****************************************************************************************
505 * Searches the last linked message and attaches a new, monotonically allocated list node.
506 * @returns A pointer to the message in the allocated link node.
507 ******************************************************************************************/
510
511 /** ****************************************************************************************
512 * Non-inlined portion of method #Add. Clones arguments and prepends description argument,
513 * in case the enum element of the message has an enum record attached.
514 * If furthermore, the enum element's record was resourced, then the record's description
515 * value is interpreted as a resource string's name, which is prepended instead.
516 * @param message The message to finalize.
517 * @param hasRecord Indicates if a record is assigned.
518 * @param pool If records are resourced, this is the resource pool to use.
519 * @param category If records are resourced, this is the category to use.
520 ******************************************************************************************/
522 void finalizeMessage( Message* message, bool hasRecord, ResourcePool* pool, const NString& category );
523
524
525}; // class Exception
526
527
528} // namespace alib[::lang]
529
530
531/// Type alias in namespace \b alib.
533
534} // namespace [alib]
535
537
538
539// #################################################################################################
540// Append
541// #################################################################################################
542namespace alib { namespace strings {
543#if defined(ALIB_DOX)
544namespace APPENDABLES {
545#endif
546 /** ********************************************************************************************
547 * Specialization of functor \alib{strings;T_Append} for type
548 * \alib{lang;Exception}.
549 * @tparam TChar The character type.
550 **********************************************************************************************/
551 template<typename TChar> struct T_Append<lang::Exception,TChar>
552 {
553 /**
554 * Invokes \alib{lang;Exception::Format} passing the \p{target}.
555 *
556 * @param target The \b AString that method \b Append was invoked on.
557 * @param src The exception to append.
558 */
559 void operator()( TAString<TChar>& target, const lang::Exception& src )
560 {
561 src.Format(target);
562 }
563 };
564#if defined(ALIB_DOX)
565}
566#endif
567}}
568
569
570#endif // HPP_ALIB_CAMP_MESSAGE_EXCEPTION
bool operator!=(IteratorType other) const
detail::ExceptionEntry * p
TConstOrMutableMessage * pointer
Implementation of std::iterator_traits.
IteratorType(detail::ExceptionEntry *_p=nullptr)
bool operator==(IteratorType other) const
std::forward_iterator_tag iterator_category
Implementation of std::iterator_traits.
TConstOrMutableMessage * operator->() const
TConstOrMutableMessage & operator*() const
TConstOrMutableMessage & reference
Implementation of std::iterator_traits.
integer difference_type
Implementation of std::iterator_traits.
Exception(Exception &&src) noexcept
ALIB_API Message & Back() const
ALIB_API int Size() const
AString Format() const
Exception(Exception &)=delete
ALIB_API const Enum & Type() const
ALIB_API Message * allocMessageLink()
Definition exception.cpp:58
Exception & operator=(Exception &&)=delete
ConstForwardIterator end() const
Exception & Add(const NCString &file, int line, const NCString &func, TEnum type, TArgs &&... args)
ForwardIterator begin()
Exception(TIntegral initialChunkSize, int chunkGrowthInPercent=100)
ForwardIterator end()
Exception operator=(Exception &)=delete
Exception(const NCString &file, int line, const NCString &func, TEnum type, TArgs &&... args)
IteratorType< Message > ForwardIterator
ALIB_API strings::TAString< complementChar > & Format(strings::TAString< complementChar > &target) const
ALIB_API void finalizeMessage(Message *message, bool hasRecord, ResourcePool *pool, const NString &category)
Definition exception.cpp:72
ALIB_API AString & Format(AString &target) const
IteratorType< const Message > ConstForwardIterator
ConstForwardIterator begin() const
#define ALIB_ASSERT_MODULE(modulename)
Definition alib.hpp:190
#define ATMP_ISOF( T, TBase)
Definition tmp.hpp:33
#define ALIB_API
Definition alib.hpp:538
#define ALIB_BOXING_VTABLE_DECLARE(TMapped, Identifier)
Definition vtable.inl:477
#define ATMP_EQ( T, TEqual)
Definition tmp.hpp:32
#define ATMP_SELECT_IF_1TP(TParam, ...)
Definition tmp.hpp:57
platform_specific integer
Definition integers.hpp:50
@ KeepWithSender
Keeps responsibility, e.g. when passing an object.
Definition alib.cpp:57
ERSerializable() noexcept=default
String DescriptionOrItsResourceName
Definition exception.hpp:70
ERException() noexcept=default
ALIB_API void Parse()
Definition exception.cpp:51
ExceptionEntry * next
A pointer to the next message.
Definition exception.hpp:41
void operator()(TAString< TChar > &target, const lang::Exception &src)