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