8#if !defined(ALIB_C20_MODULES) || ((ALIB_C20_MODULES != 0) && (ALIB_C20_MODULES != 1))
9# error "Configuration MACRO ALIB_C20_MODULES has to be given to the compiler as either 0 or 1"
28# if __has_include(<format>)
31# include <fmt/format.h>
35# if (ALIB_SINGLE_THREADED && ALIB_EXT_LIB_THREADS_AVAILABLE)
38# if ALIB_DEBUG_ASSERTION_PRINTABLES
39# include <unordered_set>
53 import ALib.Bootstrap;
56 import ALib.Strings.Token;
58 import ALib.Strings.Monomem;
65 import ALib.EnumRecords;
68 import ALib.Resources;
71 import ALib.Variables;
77 import ALib.ThreadModel;
80 import ALib.Camp.Base;
110#if (ALIB_SINGLE_THREADED && ALIB_EXT_LIB_THREADS_AVAILABLE) || DOXYGEN
113 namespace { std::thread::id dbg_thread_seen;
114 bool dbg_in_single_threaded_check=
false; }
142 if( dbg_in_single_threaded_check )
144 dbg_in_single_threaded_check=
true;
149 dbg_thread_seen= std::this_thread::get_id();
150 dbg_in_single_threaded_check=
false;
154 if( dbg_thread_seen != std::this_thread::get_id() )
157 "A second thread was detected using a single-threaded compilation of ALib"
158 "(Configuration Macro 'ALIB_SINGLE_THREADED' given with the ALib Build)." )
160 dbg_in_single_threaded_check=
false;
172 std::string_view domain, std::string_view msg ) =
nullptr;
175std::string_view
FORMAT =
"{file}:{line} {type}:\n{message}";
182 thread_local TLD HALT_FLAGS_AND_COUNTERS;
183 bool isInitialized=
false;
184 std::string outBuffer;
185#if !ALIB_SINGLE_THREADED
190static std::unordered_map<std::type_index, AnyConversionFunc> registeredAnys;
192#if __has_include(<format>)
198void initializeDefaultPrintables() {
200 RegisterPrintable(
typeid(
bool ), [](
const std::any& any, std::string& s) { s+= f::format(
"{}", std::any_cast< bool >(any)); });
201 RegisterPrintable(
typeid(
char ), [](
const std::any& any, std::string& s) { s+= f::format(
"{}", std::any_cast< char >(any)); });
202 RegisterPrintable(
typeid( int8_t ), [](
const std::any& any, std::string& s) { s+= f::format(
"{}", std::any_cast< int8_t >(any)); });
203 RegisterPrintable(
typeid(uint8_t ), [](
const std::any& any, std::string& s) { s+= f::format(
"{}", std::any_cast<uint8_t >(any)); });
204 RegisterPrintable(
typeid( int16_t ), [](
const std::any& any, std::string& s) { s+= f::format(
"{}", std::any_cast< int16_t >(any)); });
205 RegisterPrintable(
typeid(uint16_t ), [](
const std::any& any, std::string& s) { s+= f::format(
"{}", std::any_cast<uint16_t >(any)); });
206 RegisterPrintable(
typeid( int32_t ), [](
const std::any& any, std::string& s) { s+= f::format(
"{}", std::any_cast< int32_t >(any)); });
207 RegisterPrintable(
typeid(uint32_t ), [](
const std::any& any, std::string& s) { s+= f::format(
"{}", std::any_cast<uint32_t >(any)); });
208 RegisterPrintable(
typeid( int64_t ), [](
const std::any& any, std::string& s) { s+= f::format(
"{}", std::any_cast< int64_t >(any)); });
209 RegisterPrintable(
typeid(uint64_t ), [](
const std::any& any, std::string& s) { s+= f::format(
"{}", std::any_cast<uint64_t >(any)); });
210 RegisterPrintable(
typeid(
float ), [](
const std::any& any, std::string& s) { s+= f::format(
"{}", std::any_cast<float >(any)); });
211 RegisterPrintable(
typeid(
unsigned long), [](
const std::any& any, std::string& s) { s+= f::format(
"{}", std::any_cast<unsigned long>(any)); });
212DOX_MARKER( [DOX_ASSERT_REGISTER_PRINTABLE])
214 [](
const std::any& any, std::string& s) {
215 s+= f::format(
"{}", std::any_cast<double >(any));
218 [](
const std::any& any, std::string& s) {
219 auto* value= std::any_cast<const char*>(any);
224 [](
const std::any& any, std::string& s) {
225 auto* value= std::any_cast<const char*>(any);
230 [](
const std::any& any, std::string& s) {
231 auto* value= std::any_cast<const wchar_t*>(any);
234 std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
235 s+= converter.to_bytes(value);
239DOX_MARKER( [DOX_ASSERT_REGISTER_PRINTABLE])
241 if constexpr (
sizeof(wchar_t) == 2)
243 [](
const std::any& any, std::string& s) {
244 auto* value= std::any_cast<const char32_t*>(any);
247 std::wstring_convert<std::codecvt_utf8<char32_t>,
char32_t> converter;
248 s+= converter.to_bytes(value);
252 if constexpr (
sizeof(wchar_t) == 4)
254 [](
const std::any& any, std::string& s) {
255 auto* value= std::any_cast<const char16_t*>(any);
258 std::wstring_convert<std::codecvt_utf8<char16_t>,
char16_t> converter;
259 s+= converter.to_bytes(value);
264 RegisterPrintable(
typeid(std::string ), [](
const std::any& any, std::string& s) { s+= *std::any_cast<std::string >(&any); });
265 RegisterPrintable(
typeid(std::string_view ), [](
const std::any& any, std::string& s) { s+= std::any_cast<std::string_view>( any); });
266 RegisterPrintable(
typeid(
const std::type_info*), [](
const std::any& any, std::string& s) {
267 auto* typeInfo= std::any_cast<const std::type_info*>(any);
271 RegisterPrintable(
typeid(std::thread::id) , [](
const std::any& any, std::string& s) {
272 #if !ALIB_SINGLE_THREADED
273 auto threadID= std::any_cast<std::thread::id>(any);
277 #if !ALIB_CHARACTERS_WIDE
280 std::wstring_convert<std::codecvt_utf8<character>,
character> converter;
281 s+= converter.to_bytes(thread->
GetName());
283 s += f::format(
"({})", thread->
GetID());
286 s+=
"<Unknown thread>";
290 s+=
"<SINGLE_THREADED>";
295 std::error_code ec = std::make_error_code(std::any_cast<std::errc>(any));
296 s+=
'"'; s+= ec.message(); s+=
'"'; s+= f::format(
"({})", ec.value());
301 CallerInfo callerInfo= std::any_cast<CallerInfo>(any);
302 if ( callerInfo.
File ==
nullptr ) {
303 s+=
"<nulled caller>";
306 s+=f::format(
"{{Caller: @ {}:{} ({}) ", callerInfo.
File,callerInfo.
Line, callerInfo.
Func);
310 #if !ALIB_SINGLE_THREADED
311 s+=f::format(
"thread::id= {}", 5 );
317 #if !ALIB_SINGLE_THREADED
318 Thread* thread= std::any_cast<Thread*>(any);
320 #if !ALIB_CHARACTERS_WIDE
323 std::wstring_convert<std::codecvt_utf8<character>,
character> converter;
324 s+= converter.to_bytes(thread->
GetName());
326 s += f::format(
"({})", thread->
GetID());
329 s+=
"<Unknown thread>";
332 s+=
"<SINGLE_THREADED>";
336 #if !ALIB_SINGLE_THREADED
338 auto state= std::any_cast<Thread::State>(any);
344 else s+=
"<Unknown thread state>";
350 RegisterPrintable(
typeid(
NString ), [](
const std::any& any, std::string& s) { s+= std::string_view( std::any_cast<NString >(any).Buffer(),
size_t(std::any_cast<NString >(any).Length()) ); });
351 RegisterPrintable(
typeid(
NAString), [](
const std::any& any, std::string& s) { s+= std::string_view( std::any_cast<NAString>(any).Buffer(),
size_t(std::any_cast<NAString>(any).Length()) ); });
352 RegisterPrintable(
typeid(
NCString), [](
const std::any& any, std::string& s) { s+= std::string_view( std::any_cast<NCString>(any).Buffer(),
size_t(std::any_cast<NCString>(any).Length()) ); });
353 RegisterPrintable(
typeid(
WString ), [](
const std::any& any, std::string& s) { std::wstring_convert<std::codecvt_utf8<wchar>,
wchar> converter;
auto src=std::any_cast<WString >(any); s+= converter.to_bytes(src.Buffer(), src.Buffer() + src.Length() ); });
354 RegisterPrintable(
typeid(
WAString), [](
const std::any& any, std::string& s) { std::wstring_convert<std::codecvt_utf8<wchar>,
wchar> converter;
auto src=std::any_cast<WAString>(any); s+= converter.to_bytes(src.Buffer(), src.Buffer() + src.Length() ); });
355 RegisterPrintable(
typeid(
WCString), [](
const std::any& any, std::string& s) { std::wstring_convert<std::codecvt_utf8<wchar>,
wchar> converter;
auto src=std::any_cast<WCString>(any); s+= converter.to_bytes(src.Buffer(), src.Buffer() + src.Length() ); });
356 RegisterPrintable(
typeid(
XString ), [](
const std::any& any, std::string& s) { std::wstring_convert<std::codecvt_utf8<xchar>,
xchar> converter;
auto src=std::any_cast<XString >(any); s+= converter.to_bytes(src.Buffer(), src.Buffer() + src.Length() ); });
357 RegisterPrintable(
typeid(
XAString), [](
const std::any& any, std::string& s) { std::wstring_convert<std::codecvt_utf8<xchar>,
xchar> converter;
auto src=std::any_cast<XAString>(any); s+= converter.to_bytes(src.Buffer(), src.Buffer() + src.Length() ); });
358 RegisterPrintable(
typeid(
XCString), [](
const std::any& any, std::string& s) { std::wstring_convert<std::codecvt_utf8<xchar>,
xchar> converter;
auto src=std::any_cast<XCString>(any); s+= converter.to_bytes(src.Buffer(), src.Buffer() + src.Length() ); });
361 RegisterPrintable(
typeid(
NAStringMA), [](
const std::any& any, std::string& s) { s+= std::string_view( std::any_cast<NAStringMA>(any).Buffer(),
size_t(std::any_cast<NAStringMA>(any).Length()) ); });
362 RegisterPrintable(
typeid(
WAStringMA), [](
const std::any& any, std::string& s) { std::wstring_convert< std::codecvt_utf8<wchar>,
wchar> converter;
auto src=std::any_cast<WAStringMA>(any); s+= converter.to_bytes(src.Buffer(), src.Buffer() + src.Length() ); });
363 RegisterPrintable(
typeid(
NAStringPA), [](
const std::any& any, std::string& s) { s+= std::string_view( std::any_cast<NAStringPA>(any).Buffer(),
size_t(std::any_cast<NAStringPA>(any).Length()) ); });
364 RegisterPrintable(
typeid(
WAStringPA), [](
const std::any& any, std::string& s) { std::wstring_convert< std::codecvt_utf8<wchar>,
wchar> converter;
auto src=std::any_cast<WAStringPA>(any); s+= converter.to_bytes(src.Buffer(), src.Buffer() + src.Length() ); });
369 #if ALIB_BOXING && ALIB_ENUMRECORDS
406 auto* o= std::any_cast<const variables::Variable*>(any);
413 auto* o= std::any_cast<variables::Variable*>(any);
420 auto o= std::any_cast<variables::Variable>(any);
433 #if ALIB_THREADMODEL && ALIB_ENUMRECORDS
439void printRegisteredAny(
const std::any& any,
const CallerInfo& ci) {
440 if (!any.has_value())
442 auto it = registeredAnys.find(std::type_index(any.type()));
443 if (it != registeredAnys.end()) {
445 it->second(any, outBuffer);
447 std::cerr <<
"Internal Error using alib::assert::Assert(): No converter registered for type: <"
450 <<
"at " << ci.
File <<
':' << ci.
Line << std::endl;
454const char* resolveMessageType(
int msgType) {
455 if (msgType == 0)
return "error";
456 if (msgType == 1)
return "warning";
460void writeMessage( std::ostream& os,
int msgType,
const std::string_view& domain,
461 const char* file,
int line,
462 const std::string_view& message ) {
468 while (start <
format.size()) {
470 size_t openBrace =
format.find(
'{', start);
471 if (openBrace == std::string_view::npos) {
473 os <<
format.substr(start);
478 os <<
format.substr(start, openBrace - start);
481 size_t closeBrace =
format.find(
'}', openBrace + 1);
482 if (closeBrace == std::string_view::npos) {
484 os <<
format.substr(openBrace);
489 std::string_view placeholder =
format.substr(openBrace + 1, closeBrace - openBrace - 1);
492 if ( placeholder ==
"type" ) os << resolveMessageType(msgType);
493 else if ( placeholder ==
"file" ) os << file;
494 else if ( placeholder ==
"line" ) os << line;
495 else if ( placeholder ==
"message" ) os << message;
496 else if ( placeholder ==
"domain" ) os << domain;
497 else os <<
"{" << placeholder <<
"}";
500 start = closeBrace + 1;
505class RecursionBlocker {
507 static inline std::atomic<bool> isRecursing{
false};
511 RecursionBlocker()
noexcept { wasBlocked = isRecursing.exchange(
true); }
513 ~RecursionBlocker() {
if (!wasBlocked) isRecursing =
false; }
515 [[nodiscard]]
bool blocked()
const noexcept {
return wasBlocked; }
518 RecursionBlocker(
const RecursionBlocker&) =
delete;
519 RecursionBlocker& operator =(
const RecursionBlocker&) =
delete;
522#if ALIB_DEBUG_ASSERTION_PRINTABLES
523 struct Key {
const char* str;
525 bool operator==(
const Key& other)
const {
526 return str == other.str && value == other.value;
529 struct KeyHash { std::size_t operator()(
const Key& key)
const {
530 return std::hash<const char*>()(key.str) ^ ( std::hash<int>()(key.value) << 1);
533 std::unordered_set<Key, KeyHash> seenSourceLocations;
539 registeredAnys[typeIndex] = func;
542#if ALIB_DEBUG_ASSERTION_PRINTABLES
543# pragma message ("ALIB_DEBUG_ASSERTION_PRINTABLES set. ALib will print all assertions once, no matter if they are raised or not." )
546 if( !isInitialized ) initializeDefaultPrintables();
548 if (!seenSourceLocations.insert(Key{ci.File, ci.Line}).second)
552 for (
size_t i = 0; i < args.size(); ++i) {
553 auto it = registeredAnys.find(std::type_index(args[i].type()));
554 if (it == registeredAnys.end()) {
555 std::cerr <<
"Internal Error using alib::assert::Assert(): No converter registered for type: <"
556 << lang::DbgTypeDemangler( args[i].type() ).Get()
558 <<
" at: " << ci.File <<
':' << ci.Line << std::endl;
562 raise(ci, -1,
"ASSERTTEST", args );
571 const std::span<std::any>& args ) {
575 RecursionBlocker blocker;
576 if (blocker.blocked())
581 initializeDefaultPrintables();
589 for(
nchar c : domain ) {
591 || ( c >=
'A' && c <=
'Z' )
592 || c ==
'-' || c ==
'_' || c ==
'/' || c ==
'.' ) ) {
593 std::cerr <<
"Illegal alib::assert::Assert() domain given: " << domain << std::endl;
598 while (i < args.size()) {
599 const std::any& arg = args[i];
601 if ( arg.type() ==
typeid(
const char*)
602 || arg.type() ==
typeid(std::string)
603 || arg.type() ==
typeid(std::string_view) ) {
605 std::string_view str;
607 if (arg.type() ==
typeid(
const char*)) str = std::string_view( std::any_cast<const char* >( arg));
608 else if (arg.type() ==
typeid(std::string)) str = std::string_view(*std::any_cast<std::string >(&arg));
609 else str = std::any_cast<std::string_view>( arg) ;
610 std::string_view origStr= str;
614 auto handle_format_string = [&]() {
616 while ((pos = str.find(
"{}")) != std::string::npos) {
618 outBuffer+= str.substr(0, pos);
621 if (++i >= args.size()) {
622 std::cerr <<
"alib::assert: Not enough arguments for format placeholders!" << std::endl;
623 std::cerr <<
" Format string: <" << origStr <<
'>' << std::endl;
624 std::cerr <<
" @ : " << ci.
File <<
':' << ci.
Line << std::endl;
630 const std::any& placeholderArg = args[i];
631 printRegisteredAny(placeholderArg, ci);
634 str = str.substr(pos + 2);
644 handle_format_string();
646 printRegisteredAny(arg, ci);
653 PLUGIN( ci, type, domain, outBuffer.c_str() );
660 #if !ALIB_SINGLE_THREADED
662 if( lockingIoStreams )
669 type, domain, ci.
File, ci.
Line, outBuffer);
670 #if !ALIB_SINGLE_THREADED
671 if( lockingIoStreams )
678 if (type == 0) {HALT_FLAGS_AND_COUNTERS.CtdErrors++; halt= HALT_FLAGS_AND_COUNTERS.HaltOnErrors; }
679 else if (type == 1) {HALT_FLAGS_AND_COUNTERS.CtdWarnings++; halt= HALT_FLAGS_AND_COUNTERS.HaltOnWarnings; }
680 else {HALT_FLAGS_AND_COUNTERS.CtdMessages++; halt=
false; }
681 #if defined( _WIN32 )
691 #if defined(__GNUC__) || defined(__clang__)
694 #elif defined ( _MSC_VER )
#define ALIB_ALLOW_DEPRECATED
#define ALIB_ERROR(domain,...)
#define ALIB_LOCK_RECURSIVE_WITH(lock)
#define ALIB_POP_ALLOWANCE
@ Running
The thread's #".Run" method is currently processed.
@ Started
Method #".Start" was invoked but not running, yet.
@ Terminated
The thread is terminated.
virtual const character * GetName() const
static Thread * Get(std::thread::id nativeID)
This namespace exposes entities of module ALib Assert.
void CheckArgsImpl(const CallerInfo &ci, const std::span< std::any > &args)
void(* PLUGIN)(const CallerInfo &ci, int type, std::string_view domain, std::string_view msg)
void RegisterPrintable(std::type_index typeIndex, AnyConversionFunc func)
std::ostream * STREAM_MESSAGES
void raise(const CallerInfo &ci, int type, std::string_view domain, const std::span< std::any > &args)
std::ostream * STREAM_ERRORS
TLD & GetHaltFlagAndCounters()
std::ostream * STREAM_WARNINGS
void(*)(const std::any &, std::string &) AnyConversionFunc
SortOrder
Denotes sort order.
Side
Denotes if something is left or right.
SourceData
Denotes if the source data should be moved or copied.
Reach
Denotes the reach of something.
Recursive
Denotes whether recursion is performed/allowed or not.
Timing
Denotes if asynchronous tasks become synchronized.
Alignment
Denotes Alignments.
LineFeeds
Denotes line-feed encoding sequences "\n" and "\r\n".
ContainerOp
Denotes standard container operations.
Switch
Denotes if sth. is switched on or off.
Phase
Denotes a phase, e.g.,of a transaction.
CreateIfNotExists
Denotes whether something should be created if it does not exist.
Case
Denotes upper and lower case character treatment.
CreateDefaults
Denotes whether default entities should be created or not.
constexpr bool IsNull(const T &t)
Whitespaces
Denotes whether a string is trimmed or not.
Caching
Denotes if a cache mechanism is enabled or disabled.
Propagation
Denotes whether a e.g a setting should be propagated.
ValueReference
Denotes if a value is interpreted as an absolute or relative number.
Safeness
Denotes whether something should be performed in a safe or unsafe fashion.
Initialization
Used, for example, with constructors that allow to suppress initialization of members.
Inclusion
Denotes how members of a set something should be taken into account.
Timezone
Denotes whether a time value represents local time or UTC.
Priority
Possible priorities of jobs assigned to an #"DedicatedWorker".
strings::TAString< wchar, MonoAllocator > WAStringMA
Type alias in namespace alib.
strings::TString< nchar > NString
Type alias in namespace alib.
threads::Thread Thread
Type alias in namespace alib.
strings::TCString< wchar > WCString
Type alias in namespace alib.
strings::TCString< nchar > NCString
Type alias in namespace alib.
strings::TString< wchar > WString
Type alias in namespace alib.
strings::TAString< wchar, PoolAllocator > WAStringPA
Type alias in namespace alib.
strings::TString< xchar > XString
Type alias in namespace alib.
strings::TAString< nchar, lang::HeapAllocator > NAString
Type alias in namespace alib.
characters::wchar wchar
Type alias in namespace alib.
boxing::Box Box
Type alias in namespace alib.
strings::TAString< xchar, lang::HeapAllocator > XAString
Type alias in namespace alib.
characters::nchar nchar
Type alias in namespace alib.
strings::TAString< nchar, MonoAllocator > NAStringMA
Type alias in namespace alib.
camp::Basecamp BASECAMP
The singleton instance of ALib Camp class #"Basecamp".
strings::TCString< xchar > XCString
Type alias in namespace alib.
characters::xchar xchar
Type alias in namespace alib.
bool NonCampModulesInitialized
lang::CallerInfo CallerInfo
Type alias in namespace alib.
NLocalString< 256 > NString256
Type alias name for #"TLocalString;TLocalString<nchar,256>".
strings::TAString< wchar, lang::HeapAllocator > WAString
Type alias in namespace alib.
strings::TAString< nchar, PoolAllocator > NAStringPA
Type alias in namespace alib.
LocalString< 256 > String256
Type alias name for #"TLocalString;TLocalString<character,256>".
characters::character character
Type alias in namespace alib.
strings::util::Token Token
Type alias in namespace alib.
threads::RecursiveLock RecursiveLock
Type alias in namespace alib.
boxing::Enum Enum
Type alias in namespace alib.
#define ALIB_STRINGS_TO_NARROW( src, dest, bufSize)
const char * File
The name of the source file as given by compiler.
const std::type_info * TypeInfo
The calling type.
int Line
The line number within #".File".