ALib C++ Library
Library Version: 2510 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
exception.inl
Go to the documentation of this file.
1//==================================================================================================
2/// \file
3/// This header-file is part of module \alib_exceptions of the \aliblong.
4///
5/// \emoji :copyright: 2013-2025 A-Worx GmbH, Germany.
6/// Published under \ref mainpage_license "Boost Software License".
7//==================================================================================================
8ALIB_EXPORT namespace alib { namespace exceptions {
9
10/// Internal details of namespace #alib::exceptions.
11namespace detail
12{
13 /// An element of the (single) linked list of message entries of class exception.
14 /// A pointer to this type is used as the template parameter \p{T} of
15 /// struct \alib{monomem;TSharedMonoVal} that class \alib{exceptions;Exception} is derived from
16 /// and this way allocated (self-contained) in a \alib{MonoAllocator}.
18 {
19 Message message; ///< The message,
20 ExceptionEntry* next = nullptr; ///< A pointer to the next message.
21 };
22}
23
24//==================================================================================================
25/// An \ref alib_enums_records "ALib Enum Record" type used to equip custom enumeration types
26/// with records that define an entries of class \alib{exceptions;Exception}.
27///
28/// Besides the exception entry name, the only field this record adds provides a textual description
29/// of an exception entry.
30/// If the type trait \alib{resources;ResourcedTraits} is likewise specialized
31/// for a custom enumeration type, then this field is interpreted as a resource name to load the
32/// description from.
33///
34/// When parsing the enum records from string data, inherited field
35/// \alib{enumrecords;ERSerializable::MinimumRecognitionLength} is not parsed from the string, but set to
36/// fixed value \c 0. Therefore, only three fields have to be given per record:
37///
38/// 1. The custom integral enum value (this is mandatory with every resourced enum record).
39/// 2. A string denoting inherited field \alib{enumrecords;ERSerializable::EnumElementName}.
40/// 3. A string containing the description text, respectively the resource name of that.
41//==================================================================================================
43{
44 /// The description of the exception.
45 /// \note
46 /// If the type trait \alib{resources;ResourcedTraits} is specialized for an
47 /// enumeration, this field is interpreted as a resource name to load the description from.
49
50 /// Default constructor leaving the record undefined.
51 ERException() noexcept = default;
52
53
54 /// Constructor usually used with static variable declarations (declarations that are not
55 /// using enumeration types associated with \ref alib_enums_records "ALib Enum Records" of this
56 /// type).
57 ///
58 /// If used however to define an enum record during bootstrap of software (by user code
59 /// that omits the preferred option of parsing resourced strings to create such records), then
60 /// each parameter of type \b String passed, has to be of "static nature".
61 /// This means, that string buffers and their contents are deemed to survive the life-cycle of
62 /// an application. Usually, C++ string literals are passed in such situation.
63 /// @param name The name of the exception. (Usually the enum element's C++ name.)
64 /// @param description The exception's descrption. (Usually a format string.)
65 ERException(const String& name, const String& description) noexcept
66 : ERSerializable(name)
67 , DescriptionOrItsResourceName(description)
68 {}
69
70 /// Implementation of \alib{enumrecords;EnumRecordPrototype::Parse}.
71 /// \note Field \alib{enumrecords;ERSerializable::MinimumRecognitionLength} is not read from the
72 /// string, but set to fixed value \c 0.
74 void Parse();
75};
76
77//==================================================================================================
78/// The (one and only) <em>"throwable"</em> used with \aliblong.
79///
80/// Please consult the Programmer's Manual of module \alib_exceptions for
81/// \ref alib_exceptions_exceptions "detailed information" about this class and its use.
82///
83/// In short, this class implements the following "exception paradigm":
84/// - There is only one exception type.
85/// - That type stores a forward list of \alib{exceptions;Message;messages}.
86/// - With creation, a first message is added to the list of messages.
87/// - While unwinding the stack, new messages may be added to the list.
88/// - A new message may either add information to the previous entry or may change the meaning
89/// of the exception.
90/// - Messages contain IDs of \alib{boxing;Enum;arbitrary scoped enumeration types}.
91/// This allows structured processing of Exceptions.
92///
93/// This type uses a smart memory model leveraging class \alib{monomem;TSharedMonoVal}
94/// which places all internal data in a first buffer of a \alib{monomem;TMonoAllocator},
95/// even the \b %Exception object itself!
96/// With that, exceptions usually perform only one single dynamic allocation, even if various
97/// messages with various data objects (\alib{boxing;Box;boxes}) are attached.
98/// Only when many messages are added, a next allocation might occur.
99/// The allocation size of the monotonic buffers is set to be one kilobyte.
100///
101/// Although the footprint (<c>sizeof</c>) of the class is just the size of a pointer
102/// (One into the first memory buffer of the monotonic allocator), objects of this type should be
103/// caught as references. Once caught, copies may be stored for later logging or similar.
104///
105/// @see Chapter \ref alib_exceptions_exceptions of the Programmer's Manual of
106/// camp \alib_exceptions_nl.
107//==================================================================================================
108class Exception : protected monomem::TSharedMonoVal<detail::ExceptionEntry*, HeapAllocator, void>
109{
110 protected:
111 /// Shortcut to the parent class.
113
114 public:
115 /// Deleted copy constructor. Exceptions must be caught only as references.
116 Exception( Exception& ) noexcept = default;
117
118 /// Defaulted move constructor.
119 /// @param src The object to move.
120 Exception(Exception&& src) noexcept = default;
121
122 /// Defaulted copy assignment operator.
123 /// @return Nothing (deleted).
124 Exception& operator=( Exception& ) noexcept = default;
125
126 /// Defaulted move assignment operator.
127 /// @return Nothing (deleted).
128 Exception& operator=( Exception&& ) noexcept = default;
129
130 /// Defaulted destructor.
131 ~Exception() noexcept = default;
132
133 /// Defaulted default constructor.
134 Exception() noexcept = default;
135
136 /// Constructs an empty instance from \c std::nullptr.
137 /// This constructor is necessary to allow assignment of \c nullptr to values of this type,
138 /// which clears the automatic pointer.
139 Exception(std::nullptr_t) noexcept {}
140
141 //==============================================================================================
142 /// Constructor that allows providing the size of the allocated memory buffer in bytes.
143 /// With other constructors, this size is fixed to \c 1kB (1024 bytes).
144 /// A higher size may avoid a second allocation (which is not problematic in usual cases).
145 ///
146 /// \note The use of this constructor is advisable only in seldom cases. The same
147 /// notes as given with the documentation of the default constructor apply.
148 ///
149 /// @param initialBufferSizeInKB The initial allocation size of the internal
150 /// \alib{MonoAllocator} in kilobytes (1024 bytes).
151 /// @param bufferGrowthInPercent Optional growth factor in percent, applied to the buffer size
152 /// with each next buffer allocation.
153 /// With this type, the parameter defaults to \c 100, which does
154 /// not increase subsequent buffer allocations.
155 //==============================================================================================
156 template<typename TIntegral>
157 Exception( TIntegral initialBufferSizeInKB, int bufferGrowthInPercent= 100 )
158 : TSharedMonoVal( size_t(initialBufferSizeInKB), bufferGrowthInPercent )
159 {
160 static_assert( !std::is_integral<TIntegral>::value,
161 "Erroneous use of Exception constructor overload which expects an integral "
162 "value as first parameter to determine the size of the first memory buffer." );
163 }
164
165 //==============================================================================================
166 /// Constructs an exception and invokes #Add to create the initial message entry.
167 ///
168 /// In case that the enumeration type of given parameter \p{type} is equipped with
169 /// \ref alib_enums_records "ALib Enum Records" according to record type
170 /// \alib{exceptions;ERException}, the first argument added to the message entry
171 /// is collected from the corresponding enum record. For more
172 /// information consult the \ref alib_exceptions_exceptions_res "corresponding section" of the
173 /// Programmer's Manual.
174 ///
175 /// @tparam TEnum Template type of the enumeration element.
176 /// @tparam TArgs The variadic template argument types.
177 ///
178 /// @param ci Source location of entry creation.
179 /// @param type An enum element denoting the message type.
180 /// @param args The message arguments.
181 //==============================================================================================
182 template<typename TEnum, typename... TArgs >
183 Exception( const lang::CallerInfo& ci, TEnum type, TArgs&&... args )
184 : TSharedMonoVal( 1, 100 )
185 {
186 ConstructT();
187 Add( ci, type, std::forward<TArgs>(args)... );
188 }
189
190// #################################################################################################
191// Interface
192// #################################################################################################
193 //==============================================================================================
194 /// Returns the last message in the list of stored messages.
195 ///
196 /// @return The most recently added message.
197 //==============================================================================================
199 Message& Back() const;
200
201 //==============================================================================================
202 /// Returns the number of message entries.
203 ///
204 /// @return The number of messages added to this exception.
205 //==============================================================================================
207 int Size() const;
208
209 //==============================================================================================
210 /// Returns field \alib{exceptions;Message::Type} of the \b last message in the list of
211 /// messages that has a positive underlying enum element value.
212 ///
213 /// The rationale here is explained in the
214 /// \ref alib_exceptions_exception_types "Programmer's Manual".
215 /// In short, positive and negative enum element values are used to separated
216 /// "informational entries" (with a negative value) from message entries that change the
217 /// type of the exception (positive value). Usually, only the latter ones are processed
218 /// by exception handlers.
219 ///
220 /// @return The most high level exception code.
221 //==============================================================================================
223 const Enum& Type() const;
224
225 //==============================================================================================
226 /// Adds a new message to this exception. The parameters of this method are
227 /// exactly those that are expected by the \alib{exceptions;Message::Message;constructor}
228 /// of class \alib{exceptions;Message}.
229 ///
230 /// The message object itself is created in the inherited monotonic allocator.
231 /// After the insertion, method \alib{boxing;TBoxes;CloneAll} is invoked, which
232 /// creates "safe" copies of the arguments to guarantee their survival during this
233 /// exception's lifespan.
234 ///
235 /// If the enumeration type \p{TEnum} (which is deduced from parameter \p{type}) is equipped
236 /// with \ref alib_enums_records "ALib Enum Records" of type \alib{exceptions;ERException},
237 /// an additional message argument is \b prepended to the message
238 /// This argument is of a string-type and is taken from field
239 /// \alib{exceptions::ERException;DescriptionOrItsResourceName} of the associated enum record.
240 /// As described in chapter alib_exceptions_exceptions_args of the Programmer's Manual,
241 /// it is proposed that this argument of string-type, is a formatter-string that is used to
242 /// format the arguments of an exception into a human-readable message.
243 ///
244 /// If furthermore, the type trait \alib{resources;ResourcedTraits} is specialized for
245 /// enumeration type \p{TEnum}, then the value of \b DescriptionOrItsResourceName is not
246 /// directly prepended but interpreted as a resource name. In this case the resourced
247 /// description is prepended instead.
248 ///
249 /// For more information, consult chapter \ref alib_exceptions_exceptions_res of the
250 /// Programmer's Manual.
251 ///
252 /// @tparam TEnum The enumeration type used to define the message type.
253 /// @tparam TArgs The variadic template argument types.
254 /// @param ci Source location of entry creation.
255 /// @param type An enum element denoting the message type.
256 /// @param args The message arguments.
257 /// @return Return <c>*this</c> to allow concatenated operations or use with throw statement.
258 //==============================================================================================
259 template <typename TEnum, typename... TArgs> inline
260 Exception& Add( const lang::CallerInfo& ci, TEnum type, TArgs&&... args )
261 {
262 Message* newMessage= allocMessageLink();
263 new (newMessage) Message( ci, GetAllocator(), type );
264 newMessage->Add( std::forward<TArgs>( args )... );
265 finalizeMessage( newMessage,
266 std::is_base_of_v<ERException,typename enumrecords::RecordsTraits<TEnum>::Type>,
269 return *this;
270 }
271
272
273 #if ALIB_FORMAT
274 /// Uses class \alib{format;Paragraphs} to write all entries of this
275 /// exception into the given narrow \p{target} string.
276 /// Entries are expected to have a format string set as their description meta-information
277 /// that corresponds (in respect to the placeholders within the string) to the arguments
278 /// found in the entry.
279 /// \note In multithreaded applications, the\alib{format;Formatter::DefaultLock}
280 /// has to be acquired before invoking this method.
281 /// \par Availability
282 /// This method is available only if the module \alib_format is included in the \alibbuild.
283 /// @param target The target string to format the entry description to.
284 /// @return Returns given \b AString \p target for convenience.
286 AString& Format( AString& target ) const;
287
288 /// Same as \alib{exceptions::Exception;Format(AString&)const;Format(AString&)}, but writing
289 /// to a string of complement character width.
290 /// \note In multithreaded applications, the\alib{format;Formatter::DefaultLock}
291 /// has to be acquired before invoking this method.
292 /// \par Availability
293 /// This method is available only if the module \alib_format is included in the \alibbuild.
294 /// @param target The target string to format the entry description to.
295 /// @return Returns given \b AString \p target for convenience.
299 {
300 target << Format();
301 return target;
302 }
303
304 /// Inline shortcut to \alib{exceptions::Exception;Format(AString&)const;Format(AString&)}
305 /// that creates, uses and returns an AString value for the exception's description.
306 /// \note In multithreaded applications, the\alib{format;Formatter::DefaultLock} has to
307 /// be acquired before invoking this method.
308 ///
309 /// \par Availability
310 /// This method is available only if the module \alib_format is included in the \alibbuild.
311 /// @return The formatted description of the Exception.
313 {
314 AString result;
315 Format( result );
316 return result;
317 }
318 #endif
319
320
321// #################################################################################################
322// std::ForwardIterator
323// #################################################################################################
324protected:
325 //==============================================================================================
326 /// Implementation of \c std::ForwardIterator that iterates all \alib{exceptions;Message}
327 /// entries of an \b %Exception.
328 //==============================================================================================
329 template<typename TConstOrMutableMessage>
331 {
332 protected:
333 /// The pointer to the actual node.
335
336 public:
337 using iterator_category = std::forward_iterator_tag; ///< Implementation of <c>std::iterator_traits</c>.
338 using value_type = Message ; ///< Implementation of <c>std::iterator_traits</c>.
339 using difference_type = integer ; ///< Implementation of <c>std::iterator_traits</c>.
340 using pointer = TConstOrMutableMessage* ; ///< Implementation of <c>std::iterator_traits</c>.
341 using reference = TConstOrMutableMessage& ; ///< Implementation of <c>std::iterator_traits</c>.
342
343 public:
344 /// Constructor.
345 /// @param _p Our initial value
346 explicit IteratorType( detail::ExceptionEntry* _p = nullptr )
347 : p(_p)
348 {}
349
350 /// Constructor taking a constant entry pointer.
351 /// Available for the constant version of this iterator only.
352 /// @param entry The initial message entry.
353 template<typename TConstEntry>
354 requires std::is_const_v<TConstEntry>
355 IteratorType( TConstEntry* entry ) : p(const_cast<detail::ExceptionEntry*>(entry)) {}
356
357
358 /// Constructor taking a mutable iterator.
359 /// Available for the constant version of this iterator only.
360 /// @param it The mutable iterator used to construct this constant one.
361 template<typename TMutableIterator>
362 requires std::same_as<TMutableIterator, IteratorType<const Message>>
363 IteratorType( TMutableIterator it ) : p(it) {}
364
365 //###################### To satisfy concept of InputIterator ######################
366
367 /// Prefix increment operator.
368 /// @return A reference to ourselves.
370 {
371 p= p->next;
372 return *this;
373 }
374
375 /// Postfix increment operator.
376 /// @return A new iterator object that is not increased, yet.
378 {
379 auto result= IteratorType(p);
380 p= p->next;
381 return result;
382 }
383
384 /// Comparison operator.
385 /// @param other The iterator to compare ourselves to.
386 /// @return \c true if this and given iterator are equal, \c false otherwise.
387 bool operator==(IteratorType other) const
388 {
389 return p == other.p;
390 }
391
392 /// Comparison operator.
393 /// @param other The iterator to compare ourselves to.
394 /// @return \c true if this and given iterator are not equal, \c false otherwise.
395 bool operator!=(IteratorType other) const
396 {
397 return p != other.p;
398 }
399
400 /// Retrieves the message that this iterator references.
401 /// @return The message reference.
402 TConstOrMutableMessage& operator*() const
403 {
404 return p->message;
405 }
406
407 /// Retrieves the pointer to the message that this iterator references.
408 /// @return The message pointer.
409 TConstOrMutableMessage* operator->() const
410 {
411 return &p->message;
412 }
413 };
414
415public:
416 /// The constant iterator exposed by this container.
417 using ConstForwardIterator = IteratorType <const Message>;
418
419 /// The mutable iterator exposed by this container.
420 using ForwardIterator = IteratorType < Message>;
421
422
423 /// Returns an iterator pointing to the first message entry.
424 /// @return A forward iterator to the first message entry.
426 {
427 return ForwardIterator( **this );
428 }
429
430 /// Returns an iterator representing the end of the message entries.
431 /// @return The end of this exception's message entries.
433 {
434 return ForwardIterator( nullptr );
435 }
436
437 /// Returns an iterator pointing to the first message entry.
438 /// @return A forward iterator to the first message entry.
440 {
441 return ConstForwardIterator( **this );
442 }
443
444 /// Returns an iterator representing the end of the message entries.
445 /// @return The end of this exception's message entries.
447 {
448 return ConstForwardIterator( nullptr );
449 }
450
451
452// #################################################################################################
453// protected methods
454// #################################################################################################
455protected:
456 //==============================================================================================
457 /// Searches the last linked message and attaches a new, monotonically allocated list node.
458 /// @returns A pointer to the message in the allocated link node.
459 //==============================================================================================
462
463 //==============================================================================================
464 /// Non-inlined portion of the method #Add.
465 /// Clones arguments and prepends description argument, in case the enum element of the message
466 /// has an enum record attached.
467 /// If furthermore, the enum element's record was resourced, then the record's description
468 /// value is interpreted as a resource string's name, which is prepended instead.
469 /// @param message The message to finalize.
470 /// @param hasRecord Indicates if a record is assigned.
471 /// @param pool If records are resourced, this is the resource pool to use.
472 /// @param category If records are resourced, this is the category to use.
473 //==============================================================================================
475 void finalizeMessage( Message* message, bool hasRecord, ResourcePool* pool, const NString& category );
476
477
478}; // class Exception
479
480
481} // namespace alib[::exceptions]
482
483
484/// Type alias in namespace \b alib.
486
487} // namespace [alib]
488
490
491
492#if ALIB_CAMP
493ALIB_EXPORT namespace alib::system {
494/// A Namespace function that creates an according \alib{exceptions;Exception} to a corresponding
495/// system error number.
496///
497/// The small challenge here is that arbitrary error numbers (of an unknown) type might occur, that
498/// do not have a corresponding enum record.
499/// In this case, \alib{system;SystemErrors;SystemErrors::UNKNOWN} is thrown and only the
500/// number is displayed in the description text.
501///
502/// \par Availability
503/// This method is available only if \alib_camp is included in the \alibbuild.
504/// The reason for this is that all format strings for the many system errors are only resourced
505/// with class \alib{camp;Basecamp}.
506/// @param ci The source location of the exception creation.
507/// @param errNo The system's error number.
508/// @return An exception object.
509ALIB_DLL Exception CreateSystemException( const CallerInfo& ci, int errNo );
510}
511#endif
512
513// #################################################################################################
514// Append
515// #################################################################################################
516#if ALIB_FORMAT
517ALIB_EXPORT namespace alib::strings {
518#if DOXYGEN
519namespace APPENDABLES {
520#endif
521 //==============================================================================================
522 /// Specialization of functor \alib{strings;AppendableTraits} for type
523 /// \alib{exceptions;Exception}.
524 ///
525 /// \par Availability
526 /// This method is available only if the module \alib_format is included in the \alibbuild.
527 /// @tparam TChar The character type.
528 /// @tparam TAllocator The allocator type, as prototyped with \alib{lang;Allocator}.
529 //==============================================================================================
530 template<typename TChar, typename TAllocator> struct AppendableTraits<exceptions::Exception,TChar,TAllocator>
531 {
532 /// Invokes \alib{exceptions;Exception::Format} passing the \p{target}.
533 ///
534 /// @param target The \b AString that method \b Append was invoked on.
535 /// @param src The exception to append.
537 src.Format(target);
538 }
539 };
540#if DOXYGEN
541}
542#endif
543}
544#endif // ALIB_FORMAT
545
TBoxes & Add()
Definition boxes.inl:61
TConstOrMutableMessage & reference
Implementation of std::iterator_traits.
bool operator==(IteratorType other) const
std::forward_iterator_tag iterator_category
Implementation of std::iterator_traits.
Message value_type
Implementation of std::iterator_traits.
integer difference_type
Implementation of std::iterator_traits.
IteratorType(detail::ExceptionEntry *_p=nullptr)
TConstOrMutableMessage * pointer
Implementation of std::iterator_traits.
TConstOrMutableMessage & operator*() const
bool operator!=(IteratorType other) const
TConstOrMutableMessage * operator->() const
Exception(Exception &) noexcept=default
Deleted copy constructor. Exceptions must be caught only as references.
IteratorType< Message > ForwardIterator
The mutable iterator exposed by this container.
ALIB_DLL AString & Format(AString &target) const
ALIB_DLL Message & Back() const
ConstForwardIterator end() const
Exception(Exception &&src) noexcept=default
ALIB_DLL Message * allocMessageLink()
Definition exception.cpp:64
ALIB_DLL strings::TAString< complementChar, lang::HeapAllocator > & Format(strings::TAString< complementChar, lang::HeapAllocator > &target) const
ForwardIterator begin()
Exception & Add(const lang::CallerInfo &ci, TEnum type, TArgs &&... args)
TSharedMonoVal< detail::ExceptionEntry *, HeapAllocator, void > base
Shortcut to the parent class.
IteratorType< const Message > ConstForwardIterator
The constant iterator exposed by this container.
Exception(TIntegral initialBufferSizeInKB, int bufferGrowthInPercent=100)
Exception & operator=(Exception &&) noexcept=default
ALIB_DLL const Enum & Type() const
ConstForwardIterator begin() const
ALIB_DLL void finalizeMessage(Message *message, bool hasRecord, ResourcePool *pool, const NString &category)
Definition exception.cpp:78
Exception & operator=(Exception &) noexcept=default
Exception(const lang::CallerInfo &ci, TEnum type, TArgs &&... args)
ALIB_DLL int Size() const
TSharedMonoVal(HeapAllocator &allocator, size_t initialBufferSizeInKB, unsigned int bufferGrowthInPercent)
#define ALIB_DLL
Definition alib.inl:496
#define ALIB_BOXING_VTABLE_DECLARE(TMapped, Identifier)
#define ALIB_EXPORT
Definition alib.inl:488
Internal details of namespace alib::exceptions.
Definition exception.inl:12
Exception CreateSystemException(const CallerInfo &ci, int errNo)
strings::TAString< character, lang::HeapAllocator > AString
Type alias in namespace alib.
lang::integer integer
Type alias in namespace alib.
Definition integers.inl:149
strings::TString< nchar > NString
Type alias in namespace alib.
Definition string.inl:2390
resources::ResourcePool ResourcePool
Type alias in namespace alib.
boxing::Enum Enum
Type alias in namespace alib.
Definition enum.inl:211
exceptions::Exception Exception
Type alias in namespace alib.
lang::CallerInfo CallerInfo
Type alias in namespace alib.
strings::TString< character > String
Type alias in namespace alib.
Definition string.inl:2381
ERSerializable() noexcept=default
Defaulted constructor leaving the record undefined.
void Type
The data type associated with elements of TEnum.
Definition records.inl:38
ERException() noexcept=default
Default constructor leaving the record undefined.
ExceptionEntry * next
A pointer to the next message.
Definition exception.inl:20
static constexpr NString Category()
static constexpr ResourcePool * Pool()
void operator()(TAString< TChar, TAllocator > &target, const exceptions::Exception &src)