ALib C++ Library
Library Version: 2511 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 /// Implementation of \alib{enumrecords;EnumRecordPrototype::Parse}.
70 /// \note Field \alib{enumrecords;ERSerializable::MinimumRecognitionLength} is not read from the
71 /// string, but set to fixed value \c 0.
73 void Parse();
74};
75
76//==================================================================================================
77/// The (one and only) <em>"throwable"</em> used with \aliblong.
78///
79/// Please consult the Programmer's Manual of module \alib_exceptions for
80/// \ref alib_exceptions_exceptions "detailed information" about this class and its use.
81///
82/// In short, this class implements the following "exception paradigm":
83/// - There is only one exception type.
84/// - That type stores a forward list of \alib{exceptions;Message;messages}.
85/// - With creation, a first message is added to the list of messages.
86/// - While unwinding the stack, new messages may be added to the list.
87/// - A new message may either add information to the previous entry or may change the meaning
88/// of the exception.
89/// - Messages contain IDs of \alib{boxing;Enum;arbitrary scoped enumeration types}.
90/// This allows structured processing of Exceptions.
91///
92/// This type uses a smart memory model leveraging class \alib{monomem;TSharedMonoVal}
93/// which places all internal data in a first buffer of a \alib{monomem;TMonoAllocator},
94/// even the \b %Exception object itself!
95/// With that, exceptions usually perform only one single dynamic allocation, even if various
96/// messages with various data objects (\alib{boxing;Box;boxes}) are attached.
97/// Only when many messages are added, a next allocation might occur.
98/// The allocation size of the monotonic buffers is set to be one kilobyte.
99///
100/// Although the footprint (<c>sizeof</c>) of the class is just the size of a pointer
101/// (One into the first memory buffer of the monotonic allocator), objects of this type should be
102/// caught as references. Once caught, copies may be stored for later logging or similar.
103///
104/// @see Chapter \ref alib_exceptions_exceptions of the Programmer's Manual of
105/// camp \alib_exceptions_nl.
106//==================================================================================================
107class Exception : protected monomem::TSharedMonoVal<detail::ExceptionEntry*, HeapAllocator, void>
108{
109 protected:
110 /// Shortcut to the parent class.
112
113 public:
114 /// Deleted copy constructor. Exceptions must be caught only as references.
115 Exception( Exception& ) noexcept =default;
116
117 /// Defaulted move constructor.
118 /// @param src The object to move.
119 Exception(Exception&& src) noexcept =default;
120
121 /// Defaulted copy assignment operator.
122 /// @return Nothing (deleted).
123 Exception& operator=( Exception& ) noexcept =default;
124
125 /// Defaulted move assignment operator.
126 /// @return Nothing (deleted).
127 Exception& operator=( Exception&& ) noexcept =default;
128
129 /// Defaulted destructor.
130 ~Exception() noexcept =default;
131
132 /// Defaulted default constructor.
133 Exception() noexcept =default;
134
135 /// Constructs an empty instance from \c std::nullptr.
136 /// This constructor is necessary to allow assignment of \c nullptr to values of this type,
137 /// which clears the automatic pointer.
138 Exception(std::nullptr_t) noexcept {}
139
140 /// Constructor that allows providing the size of the allocated memory buffer in bytes.
141 /// With other constructors, this size is fixed to \c 1kB (1024 bytes).
142 /// A higher size may avoid a second allocation (which is not problematic in usual cases).
143 ///
144 /// \note The use of this constructor is advisable only in seldom cases. The same
145 /// notes as given with the documentation of the default constructor apply.
146 ///
147 /// @param initialBufferSizeInKB The initial allocation size of the internal
148 /// \alib{MonoAllocator} in kilobytes (1024 bytes).
149 /// @param bufferGrowthInPercent Optional growth factor in percent, applied to the buffer size
150 /// with each next buffer allocation.
151 /// With this type, the parameter defaults to \c 100, which does
152 /// not increase subsequent buffer allocations.
153 template<typename TIntegral>
154 Exception( TIntegral initialBufferSizeInKB, int bufferGrowthInPercent= 100 )
155 : TSharedMonoVal( size_t(initialBufferSizeInKB), bufferGrowthInPercent ) {
156 static_assert( !std::is_integral<TIntegral>::value,
157 "Erroneous use of Exception constructor overload which expects an integral "
158 "value as first parameter to determine the size of the first memory buffer." );
159 }
160
161 /// Constructs an exception and invokes #Add to create the initial message entry.
162 ///
163 /// In case that the enumeration type of given parameter \p{type} is equipped with
164 /// \ref alib_enums_records "ALib Enum Records" according to record type
165 /// \alib{exceptions;ERException}, the first argument added to the message entry
166 /// is collected from the corresponding enum record. For more
167 /// information consult the \ref alib_exceptions_exceptions_res "corresponding section" of the
168 /// Programmer's Manual.
169 ///
170 /// @tparam TEnum Template type of the enumeration element.
171 /// @tparam TArgs The variadic template argument types.
172 ///
173 /// @param ci Source location of entry creation.
174 /// @param type An enum element denoting the message type.
175 /// @param args The message arguments.
176 template<typename TEnum, typename... TArgs >
177 Exception( const lang::CallerInfo& ci, TEnum type, TArgs&&... args )
178 : TSharedMonoVal( 1, 100 ) { ConstructT(); Add( ci, type, std::forward<TArgs>(args)... ); }
179
180//##################################################################################################
181// Interface
182//##################################################################################################
183 /// Returns the last message in the list of stored messages.
184 ///
185 /// @return The most recently added message.
187 Message& Back() const;
188
189 /// Returns the number of message entries.
190 ///
191 /// @return The number of messages added to this exception.
193 int Size() const;
194
195 /// Returns field \alib{exceptions;Message::Type} of the \b last message in the list of
196 /// messages that has a positive underlying enum element value.
197 ///
198 /// The rationale here is explained in the
199 /// \ref alib_exceptions_exception_types "Programmer's Manual".
200 /// In short, positive and negative enum element values are used to separated
201 /// "informational entries" (with a negative value) from message entries that change the
202 /// type of the exception (positive value). Usually, only the latter ones are processed
203 /// by exception handlers.
204 ///
205 /// @return The most high level exception code.
207 const Enum& Type() const;
208
209 /// Adds a new message to this exception. The parameters of this method are
210 /// exactly those that are expected by the \alib{exceptions;Message::Message;constructor}
211 /// of class \alib{exceptions;Message}.
212 ///
213 /// The message object itself is created in the inherited monotonic allocator.
214 /// After the insertion, method \alib{boxing;TBoxes;CloneAll} is invoked, which
215 /// creates "safe" copies of the arguments to guarantee their survival during this
216 /// exception's lifespan.
217 ///
218 /// If the enumeration type \p{TEnum} (which is deduced from parameter \p{type}) is equipped
219 /// with \ref alib_enums_records "ALib Enum Records" of type \alib{exceptions;ERException},
220 /// an additional message argument is \b prepended to the message
221 /// This argument is of a string-type and is taken from field
222 /// \alib{exceptions::ERException;DescriptionOrItsResourceName} of the associated enum record.
223 /// As described in chapter alib_exceptions_exceptions_args of the Programmer's Manual,
224 /// it is proposed that this argument of string-type, is a formatter-string that is used to
225 /// format the arguments of an exception into a human-readable message.
226 ///
227 /// If furthermore, the type trait \alib{resources;ResourcedTraits} is specialized for
228 /// enumeration type \p{TEnum}, then the value of \b DescriptionOrItsResourceName is not
229 /// directly prepended but interpreted as a resource name. In this case the resourced
230 /// description is prepended instead.
231 ///
232 /// For more information, consult chapter \ref alib_exceptions_exceptions_res of the
233 /// Programmer's Manual.
234 ///
235 /// @tparam TEnum The enumeration type used to define the message type.
236 /// @tparam TArgs The variadic template argument types.
237 /// @param ci Source location of entry creation.
238 /// @param type An enum element denoting the message type.
239 /// @param args The message arguments.
240 /// @return Return <c>*this</c> to allow concatenated operations or use with throw statement.
241 template <typename TEnum, typename... TArgs> inline
242 Exception& Add( const lang::CallerInfo& ci, TEnum type, TArgs&&... args ) {
243 Message* newMessage= allocMessageLink();
244 new (newMessage) Message( ci, GetAllocator(), type );
245 newMessage->Add( std::forward<TArgs>( args )... );
246 finalizeMessage( newMessage,
247 std::is_base_of_v<ERException,typename enumrecords::RecordsTraits<TEnum>::Type>,
250 return *this;
251 }
252
253
254 #if ALIB_FORMAT
255 /// Uses class \alib{format;Paragraphs} to write all entries of this
256 /// exception into the given narrow \p{target} string.
257 /// Entries are expected to have a format string set as their description meta-information
258 /// that corresponds (in respect to the placeholders within the string) to the arguments
259 /// found in the entry.
260 /// \note In multithreaded applications, the\alib{format;Formatter::DefaultLock}
261 /// has to be acquired before invoking this method.
262 /// \par Availability
263 /// This method is available only if the module \alib_format is included in the \alibbuild.
264 /// @param target The target string to format the entry description to.
265 /// @return Returns given \b AString \p{target} for convenience.
267 AString& Format( AString& target ) const;
268
269 /// Same as \alib{exceptions::Exception;Format(AString&)const;Format(AString&)}, but writing
270 /// to a string of complement character width.
271 /// \note In multithreaded applications, the\alib{format;Formatter::DefaultLock}
272 /// has to be acquired before invoking this method.
273 /// \par Availability
274 /// This method is available only if the module \alib_format is included in the \alibbuild.
275 /// @param target The target string to format the entry description to.
276 /// @return Returns given \b AString \p{target} for convenience.
280 {
281 target << Format();
282 return target;
283 }
284
285 /// Inline shortcut to \alib{exceptions::Exception;Format(AString&)const;Format(AString&)}
286 /// that creates, uses and returns an AString value for the exception's description.
287 /// \note In multithreaded applications, the\alib{format;Formatter::DefaultLock} has to
288 /// be acquired before invoking this method.
289 ///
290 /// \par Availability
291 /// This method is available only if the module \alib_format is included in the \alibbuild.
292 /// @return The formatted description of the Exception.
293 AString Format() const {
294 AString result;
295 Format( result );
296 return result;
297 }
298 #endif
299
300
301//##################################################################################################
302// std::ForwardIterator
303//##################################################################################################
304 protected:
305 /// Implementation of \c std::ForwardIterator that iterates all \alib{exceptions;Message}
306 /// entries of an \b %Exception.
307 template<typename TConstOrMutableMessage>
309 {
310 protected:
311 /// The pointer to the actual node.
313
314 public:
315 using iterator_category = std::forward_iterator_tag; ///< Implementation of <c>std::iterator_traits</c>.
316 using value_type = Message ; ///< Implementation of <c>std::iterator_traits</c>.
317 using difference_type = integer ; ///< Implementation of <c>std::iterator_traits</c>.
318 using pointer = TConstOrMutableMessage* ; ///< Implementation of <c>std::iterator_traits</c>.
319 using reference = TConstOrMutableMessage& ; ///< Implementation of <c>std::iterator_traits</c>.
320
321 public:
322 /// Constructor.
323 /// @param _p Our initial value
324 explicit IteratorType( detail::ExceptionEntry* _p = nullptr )
325 : p(_p) {}
326
327 /// Constructor taking a constant entry pointer.
328 /// Available for the constant version of this iterator only.
329 /// @param entry The initial message entry.
330 template<typename TConstEntry>
331 requires std::is_const_v<TConstEntry>
332 IteratorType( TConstEntry* entry ) : p(const_cast<detail::ExceptionEntry*>(entry)) {}
333
334
335 /// Constructor taking a mutable iterator.
336 /// Available for the constant version of this iterator only.
337 /// @param it The mutable iterator used to construct this constant one.
338 template<typename TMutableIterator>
339 requires std::same_as<TMutableIterator, IteratorType<const Message>>
340 IteratorType( TMutableIterator it ) : p(it) {}
341
342 //############################ To satisfy concept of InputIterator ##########################
343
344 /// Prefix increment operator.
345 /// @return A reference to ourselves.
346 IteratorType& operator++() { p= p->next; return *this; }
347
348 /// Postfix increment operator.
349 /// @return A new iterator object that is not increased, yet.
351 auto result= IteratorType(p);
352 p= p->next;
353 return result;
354 }
355
356 /// Comparison operator.
357 /// @param other The iterator to compare ourselves to.
358 /// @return \c true if this and given iterator are equal, \c false otherwise.
359 bool operator==(IteratorType other) const { return p == other.p; }
360
361 /// Comparison operator.
362 /// @param other The iterator to compare ourselves to.
363 /// @return \c true if this and given iterator are not equal, \c false otherwise.
364 bool operator!=(IteratorType other) const { return p != other.p; }
365
366 /// Retrieves the message that this iterator references.
367 /// @return The message reference.
368 TConstOrMutableMessage& operator*() const { return p->message; }
369
370 /// Retrieves the pointer to the message that this iterator references.
371 /// @return The message pointer.
372 TConstOrMutableMessage* operator->() const { return &p->message; }
373 };
374
375 public:
376 /// The constant iterator exposed by this container.
377 using ConstForwardIterator = IteratorType <const Message>;
378
379 /// The mutable iterator exposed by this container.
380 using ForwardIterator = IteratorType < Message>;
381
382
383 /// Returns an iterator pointing to the first message entry.
384 /// @return A forward iterator to the first message entry.
385 ForwardIterator begin() { return ForwardIterator( **this ); }
386
387 /// Returns an iterator representing the end of the message entries.
388 /// @return The end of this exception's message entries.
389 ForwardIterator end() { return ForwardIterator( nullptr ); }
390
391 /// Returns an iterator pointing to the first message entry.
392 /// @return A forward iterator to the first message entry.
393 ConstForwardIterator begin() const { return ConstForwardIterator( **this ); }
394
395 /// Returns an iterator representing the end of the message entries.
396 /// @return The end of this exception's message entries.
397 ConstForwardIterator end() const { return ConstForwardIterator( nullptr ); }
398
399
400//##################################################################################################
401// protected methods
402//##################################################################################################
403 protected:
404 /// Searches the last linked message and attaches a new, monotonically allocated list node.
405 /// @returns A pointer to the message in the allocated link node.
408
409 /// Non-inlined portion of the method #Add.
410 /// Clones arguments and prepends description argument, in case the enum element of the message
411 /// has an enum record attached.
412 /// If furthermore, the enum element's record was resourced, then the record's description
413 /// value is interpreted as a resource string's name, which is prepended instead.
414 /// @param message The message to finalize.
415 /// @param hasRecord Indicates if a record is assigned.
416 /// @param pool If records are resourced, this is the resource pool to use.
417 /// @param category If records are resourced, this is the category to use.
419 void finalizeMessage( Message* message, bool hasRecord, ResourcePool* pool, const NString& category );
420
421
422}; // class Exception
423
424
425} // namespace alib[::exceptions]
426
427
428/// Type alias in namespace \b alib.
430
431} // namespace [alib]
432
434
435
436#if ALIB_CAMP
437ALIB_EXPORT namespace alib::system {
438/// A Namespace function that creates an according \alib{exceptions;Exception} to a corresponding
439/// system error number.
440///
441/// The small challenge here is that arbitrary error numbers (of an unknown) type might occur, that
442/// do not have a corresponding enum record.
443/// In this case, \alib{system;SystemErrors;SystemErrors::UNKNOWN} is thrown and only the
444/// number is displayed in the description text.
445///
446/// \par Availability
447/// This method is available only if \alib_camp is included in the \alibbuild.
448/// The reason for this is that all format strings for the many system errors are only resourced
449/// with class \alib{camp;Basecamp}.
450/// @param ci The source location of the exception creation.
451/// @param errNo The system's error number.
452/// @return An exception object.
453ALIB_DLL Exception CreateSystemException( const CallerInfo& ci, int errNo );
454}
455#endif
456
457//##################################################################################################
458// Append
459//##################################################################################################
460#if ALIB_FORMAT
461ALIB_EXPORT namespace alib::strings {
462#if DOXYGEN
463namespace APPENDABLES {
464#endif
465//==================================================================================================
466/// Specialization of functor \alib{strings;AppendableTraits} for type
467/// \alib{exceptions;Exception}.
468///
469/// \par Availability
470/// This method is available only if the module \alib_format is included in the \alibbuild.
471/// @tparam TChar The character type.
472/// @tparam TAllocator The allocator type, as prototyped with \alib{lang;Allocator}.
473//==================================================================================================
474template<typename TChar, typename TAllocator> struct AppendableTraits<exceptions::Exception,TChar,TAllocator>
475{
476 /// Invokes \alib{exceptions;Exception::Format} passing the \p{target}.
477 ///
478 /// @param target The \b AString that method \b Append was invoked on.
479 /// @param src The exception to append.
481 src.Format(target);
482 }
483};
484#if DOXYGEN
485}
486#endif
487}
488#endif // ALIB_FORMAT
TBoxes & Add()
Definition boxes.inl:55
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:63
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:76
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 bufferGrowthInPercent)
#define ALIB_DLL
Definition alib.inl:503
#define ALIB_BOXING_VTABLE_DECLARE(TMapped, Identifier)
#define ALIB_EXPORT
Definition alib.inl:497
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:2198
resources::ResourcePool ResourcePool
Type alias in namespace alib.
boxing::Enum Enum
Type alias in namespace alib.
Definition enum.inl:192
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:2189
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)