9#if (ALIB_SINGLE_THREADED && ALIB_EXT_LIB_THREADS_AVAILABLE) || DOXYGEN
12 namespace { std::thread::id dbg_thread_seen;
13 bool dbg_in_single_threaded_check=
false; }
41 if( dbg_in_single_threaded_check )
43 dbg_in_single_threaded_check=
true;
48 dbg_thread_seen= std::this_thread::get_id();
49 dbg_in_single_threaded_check=
false;
53 if( dbg_thread_seen != std::this_thread::get_id() )
56 "A second thread was detected using a single-threaded compilation of ALib"
57 "(Configuration Macro 'ALIB_SINGLE_THREADED' given with the ALib Build)." )
59 dbg_in_single_threaded_check=
false;
71 std::string_view domain, std::string_view msg ) =
nullptr;
73std::string_view
FORMAT =
"{file}:{line} {type}:\n{message}";
80 thread_local TLD HALT_FLAGS_AND_COUNTERS;
81 bool isInitialized=
false;
82 std::string outBuffer;
83#if !ALIB_SINGLE_THREADED
88static std::unordered_map<std::type_index, AnyConversionFunc> registeredAnys;
90#if __has_include(<format>)
96void appendUtf8CodePoint(uint32_t codePoint, std::string& s) {
97 if (codePoint > 0x10FFFFu || (codePoint >= 0xD800u && codePoint <= 0xDFFFu))
100 if (codePoint <= 0x7Fu) {
101 s+=
static_cast<char>(codePoint);
102 }
else if (codePoint <= 0x7FFu) {
103 s+=
static_cast<char>(0xC0u | (codePoint >> 6));
104 s+=
static_cast<char>(0x80u | (codePoint & 0x3Fu));
105 }
else if (codePoint <= 0xFFFFu) {
106 s+=
static_cast<char>(0xE0u | (codePoint >> 12));
107 s+=
static_cast<char>(0x80u | ((codePoint >> 6) & 0x3Fu));
108 s+=
static_cast<char>(0x80u | (codePoint & 0x3Fu));
110 s+=
static_cast<char>(0xF0u | (codePoint >> 18));
111 s+=
static_cast<char>(0x80u | ((codePoint >> 12) & 0x3Fu));
112 s+=
static_cast<char>(0x80u | ((codePoint >> 6) & 0x3Fu));
113 s+=
static_cast<char>(0x80u | (codePoint & 0x3Fu));
116template<
typename TChar>
117uint32_t toUnsignedCodeUnit(TChar value) {
118 if constexpr (
sizeof(TChar) == 1)
return static_cast<uint32_t
>(
static_cast<uint8_t
>(value));
119 if constexpr (
sizeof(TChar) == 2)
return static_cast<uint32_t
>(
static_cast<uint16_t
>(value));
120 return static_cast<uint32_t
>(value);
123template<
typename TChar>
124void appendUtf8FromScalar(TChar value, std::string& s)
126 appendUtf8CodePoint(toUnsignedCodeUnit(value), s);
130template<
typename TChar>
131void appendUtf8FromRange(
const TChar* begin,
const TChar* end, std::string& s) {
132 if (begin ==
nullptr || end ==
nullptr || begin >= end)
135 if constexpr (
sizeof(TChar) == 2) {
136 for (
const TChar* it= begin; it < end; ++it) {
137 uint32_t codePoint= toUnsignedCodeUnit(*it);
138 if (codePoint >= 0xD800u && codePoint <= 0xDBFFu) {
140 uint32_t low= toUnsignedCodeUnit(*(it + 1));
141 if (low >= 0xDC00u && low <= 0xDFFFu) {
142 codePoint= 0x10000u + ((codePoint - 0xD800u) << 10) + (low - 0xDC00u);
150 }
else if (codePoint >= 0xDC00u && codePoint <= 0xDFFFu) {
153 appendUtf8CodePoint(codePoint, s);
156 for (
const TChar* it= begin; it < end; ++it)
157 appendUtf8CodePoint(toUnsignedCodeUnit(*it), s);
161template<
typename TChar>
162void appendUtf8FromNullTerminated(
const TChar* value, std::string& s) {
163 if (value ==
nullptr)
166 if constexpr (
sizeof(TChar) == 2) {
167 while (*value !=
static_cast<TChar
>(0)) {
168 uint32_t codePoint= toUnsignedCodeUnit(*value++);
169 if (codePoint >= 0xD800u && codePoint <= 0xDBFFu) {
170 if (*value !=
static_cast<TChar
>(0)) {
171 uint32_t low= toUnsignedCodeUnit(*value);
172 if (low >= 0xDC00u && low <= 0xDFFFu) {
173 codePoint= 0x10000u + ((codePoint - 0xD800u) << 10) + (low - 0xDC00u);
181 }
else if (codePoint >= 0xDC00u && codePoint <= 0xDFFFu) {
184 appendUtf8CodePoint(codePoint, s);
187 while (*value !=
static_cast<TChar
>(0))
188 appendUtf8CodePoint(toUnsignedCodeUnit(*value++), s);
191void initializeDefaultPrintables() {
193 RegisterPrintable(
typeid(
bool ), [](
const std::any& any, std::string& s) { s+= f::format(
"{}", std::any_cast< bool >(any)); });
194 RegisterPrintable(
typeid(
char ), [](
const std::any& any, std::string& s) { s+= f::format(
"{}", std::any_cast< char >(any)); });
195 RegisterPrintable(
typeid( int8_t ), [](
const std::any& any, std::string& s) { s+= f::format(
"{}", std::any_cast< int8_t >(any)); });
196 RegisterPrintable(
typeid(uint8_t ), [](
const std::any& any, std::string& s) { s+= f::format(
"{}", std::any_cast<uint8_t >(any)); });
197 RegisterPrintable(
typeid( int16_t ), [](
const std::any& any, std::string& s) { s+= f::format(
"{}", std::any_cast< int16_t >(any)); });
198 RegisterPrintable(
typeid(uint16_t ), [](
const std::any& any, std::string& s) { s+= f::format(
"{}", std::any_cast<uint16_t >(any)); });
199 RegisterPrintable(
typeid( int32_t ), [](
const std::any& any, std::string& s) { s+= f::format(
"{}", std::any_cast< int32_t >(any)); });
200 RegisterPrintable(
typeid(uint32_t ), [](
const std::any& any, std::string& s) { s+= f::format(
"{}", std::any_cast<uint32_t >(any)); });
201 RegisterPrintable(
typeid( int64_t ), [](
const std::any& any, std::string& s) { s+= f::format(
"{}", std::any_cast< int64_t >(any)); });
202 RegisterPrintable(
typeid(uint64_t ), [](
const std::any& any, std::string& s) { s+= f::format(
"{}", std::any_cast<uint64_t >(any)); });
203 RegisterPrintable(
typeid(
float ), [](
const std::any& any, std::string& s) { s+= f::format(
"{}", std::any_cast<float >(any)); });
204 RegisterPrintable(
typeid(
unsigned long), [](
const std::any& any, std::string& s) { s+= f::format(
"{}", std::any_cast<unsigned long>(any)); });
206 wchar_t wc= std::any_cast<wchar_t>(any);
207 appendUtf8FromScalar(wc, s);
209DOX_MARKER( [DOX_ASSERT_REGISTER_PRINTABLE])
211 [](
const std::any& any, std::string& s) {
212 s+= f::format(
"{}", std::any_cast<double >(any));
215 [](
const std::any& any, std::string& s) {
216 auto* value= std::any_cast<const char*>(any);
221 [](
const std::any& any, std::string& s) {
222 auto* value= std::any_cast<const char*>(any);
227 [](
const std::any& any, std::string& s) {
228 auto* value= std::any_cast<const wchar_t*>(any);
229 appendUtf8FromNullTerminated(value, s);
231DOX_MARKER( [DOX_ASSERT_REGISTER_PRINTABLE])
233 if constexpr (
sizeof(wchar_t) == 2)
235 [](
const std::any& any, std::string& s) {
236 auto* value= std::any_cast<const char32_t*>(any);
237 appendUtf8FromNullTerminated(value, s);
239 if constexpr (
sizeof(wchar_t) == 4)
241 [](
const std::any& any, std::string& s) {
242 auto* value= std::any_cast<const char16_t*>(any);
243 appendUtf8FromNullTerminated(value, s);
246 RegisterPrintable(
typeid(std::string ), [](
const std::any& any, std::string& s) { s+= *std::any_cast<std::string >(&any); });
247 RegisterPrintable(
typeid(std::string_view ), [](
const std::any& any, std::string& s) { s+= std::any_cast<std::string_view>( any); });
248 RegisterPrintable(
typeid(
const std::type_info*), [](
const std::any& any, std::string& s) {
249 auto* typeInfo= std::any_cast<const std::type_info*>(any);
253 RegisterPrintable(
typeid(std::thread::id) , [](
const std::any& any, std::string& s) {
254 #if !ALIB_SINGLE_THREADED
255 auto threadID= std::any_cast<std::thread::id>(any);
259 #if !ALIB_CHARACTERS_WIDE
262 appendUtf8FromNullTerminated(thread->
GetName(), s);
264 s += f::format(
"({})", thread->
GetID());
267 s+=
"<Unknown thread>";
271 s+=
"<SINGLE_THREADED>";
276 std::error_code ec = std::make_error_code(std::any_cast<std::errc>(any));
277 s+=
'"'; s+= ec.message(); s+=
'"'; s+= f::format(
"({})", ec.value());
282 CallerInfo callerInfo= std::any_cast<CallerInfo>(any);
283 if ( callerInfo.
File ==
nullptr ) {
284 s+=
"<nulled caller>";
287 s+=f::format(
"{{Caller: @ {}:{} ({}) ", callerInfo.
File,callerInfo.
Line, callerInfo.
Func);
291 #if !ALIB_SINGLE_THREADED
292 s+=f::format(
"thread::id= {}", 5 );
298 #if !ALIB_SINGLE_THREADED
299 Thread* thread= std::any_cast<Thread*>(any);
301 #if !ALIB_CHARACTERS_WIDE
304 appendUtf8FromNullTerminated(thread->
GetName(), s);
306 s += f::format(
"({})", thread->
GetID());
309 s+=
"<Unknown thread>";
312 s+=
"<SINGLE_THREADED>";
316 #if !ALIB_SINGLE_THREADED
318 auto state= std::any_cast<Thread::State>(any);
324 else s+=
"<Unknown thread state>";
329 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()) ); });
330 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()) ); });
331 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()) ); });
332 RegisterPrintable(
typeid(
WString ),[](
const std::any& any, std::string& s) {
auto src=std::any_cast<WString >(any); appendUtf8FromRange(src.Buffer(), src.Buffer() + src.Length(), s); });
333 RegisterPrintable(
typeid(
WAString ),[](
const std::any& any, std::string& s) {
auto src=std::any_cast<WAString>(any); appendUtf8FromRange(src.Buffer(), src.Buffer() + src.Length(), s); });
334 RegisterPrintable(
typeid(
WCString ),[](
const std::any& any, std::string& s) {
auto src=std::any_cast<WCString>(any); appendUtf8FromRange(src.Buffer(), src.Buffer() + src.Length(), s); });
335 RegisterPrintable(
typeid(
XString ),[](
const std::any& any, std::string& s) {
auto src=std::any_cast<XString >(any); appendUtf8FromRange(src.Buffer(), src.Buffer() + src.Length(), s); });
336 RegisterPrintable(
typeid(
XAString ),[](
const std::any& any, std::string& s) {
auto src=std::any_cast<XAString>(any); appendUtf8FromRange(src.Buffer(), src.Buffer() + src.Length(), s); });
337 RegisterPrintable(
typeid(
XCString ),[](
const std::any& any, std::string& s) {
auto src=std::any_cast<XCString>(any); appendUtf8FromRange(src.Buffer(), src.Buffer() + src.Length(), s); });
339 RegisterPrintable(
typeid(
NSubstring),[](
const std::any& any, std::string& s) { s+= std::string_view( std::any_cast<NSubstring >(any).Buffer(),
size_t(std::any_cast<NSubstring >(any).Length()) ); });
340 RegisterPrintable(
typeid(
WSubstring),[](
const std::any& any, std::string& s) {
auto src=std::any_cast<WSubstring >(any); appendUtf8FromRange(src.Buffer(), src.Buffer() + src.Length(), s); });
344 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()) ); });
345 RegisterPrintable(
typeid(
WAStringMA),[](
const std::any& any, std::string& s) {
auto src=std::any_cast<WAStringMA>(any); appendUtf8FromRange(src.Buffer(), src.Buffer() + src.Length(), s); });
346 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()) ); });
347 RegisterPrintable(
typeid(
WAStringPA),[](
const std::any& any, std::string& s) {
auto src=std::any_cast<WAStringPA>(any); appendUtf8FromRange(src.Buffer(), src.Buffer() + src.Length(), s); });
351 #if ALIB_BOXING && ALIB_ENUMRECORDS
388 auto* o= std::any_cast<const variables::Variable*>(any);
395 auto* o= std::any_cast<variables::Variable*>(any);
402 auto o= std::any_cast<variables::Variable>(any);
415 #if ALIB_THREADMODEL && ALIB_ENUMRECORDS
421void printRegisteredAny(
const std::any& any,
const CallerInfo& ci) {
422 if (!any.has_value())
424 auto it = registeredAnys.find(std::type_index(any.type()));
425 if (it != registeredAnys.end()) {
427 it->second(any, outBuffer);
429 std::cerr <<
"Internal Error using alib::assert::Assert(): No converter registered for type: <"
432 <<
"at " << ci.
File <<
':' << ci.
Line << std::endl;
436const char* resolveMessageType(
int msgType) {
437 if (msgType == 0)
return "error";
438 if (msgType == 1)
return "warning";
442void writeMessage( std::ostream& os,
int msgType,
const std::string_view& domain,
443 const char* file,
int line,
444 const std::string_view& message ) {
450 while (start <
format.size()) {
452 size_t openBrace =
format.find(
'{', start);
453 if (openBrace == std::string_view::npos) {
455 os <<
format.substr(start);
460 os <<
format.substr(start, openBrace - start);
463 size_t closeBrace =
format.find(
'}', openBrace + 1);
464 if (closeBrace == std::string_view::npos) {
466 os <<
format.substr(openBrace);
471 std::string_view placeholder =
format.substr(openBrace + 1, closeBrace - openBrace - 1);
474 if ( placeholder ==
"type" ) os << resolveMessageType(msgType);
475 else if ( placeholder ==
"file" ) os << file;
476 else if ( placeholder ==
"line" ) os << line;
477 else if ( placeholder ==
"message" ) os << message;
478 else if ( placeholder ==
"domain" ) os << domain;
479 else os <<
"{" << placeholder <<
"}";
482 start = closeBrace + 1;
487class RecursionBlocker {
489 static inline std::atomic<bool> isRecursing{
false};
493 RecursionBlocker()
noexcept { wasBlocked = isRecursing.exchange(
true); }
495 ~RecursionBlocker() {
if (!wasBlocked) isRecursing =
false; }
497 [[nodiscard]]
bool blocked()
const noexcept {
return wasBlocked; }
500 RecursionBlocker(
const RecursionBlocker&) =
delete;
501 RecursionBlocker& operator =(
const RecursionBlocker&) =
delete;
504#if ALIB_DEBUG_ASSERTION_PRINTABLES
505 struct Key {
const char* str;
507 bool operator==(
const Key& other)
const {
508 return str == other.str && value == other.value;
511 struct KeyHash { std::size_t operator()(
const Key& key)
const {
512 return std::hash<const char*>()(key.str) ^ ( std::hash<int>()(key.value) << 1);
515 std::unordered_set<Key, KeyHash> seenSourceLocations;
521 registeredAnys[typeIndex] = func;
524#if ALIB_DEBUG_ASSERTION_PRINTABLES
525# pragma message ("ALIB_DEBUG_ASSERTION_PRINTABLES set. ALib will print all assertions once, no matter if they are raised or not." )
528 if( !isInitialized ) initializeDefaultPrintables();
530 if (!seenSourceLocations.insert(Key{ci.File, ci.Line}).second)
534 for (
size_t i = 0; i < args.size(); ++i) {
535 auto it = registeredAnys.find(std::type_index(args[i].type()));
536 if (it == registeredAnys.end()) {
537 std::cerr <<
"Internal Error using alib::assert::Assert(): No converter registered for type: <"
538 << lang::DbgTypeDemangler( args[i].type() ).Get()
540 <<
" at: " << ci.File <<
':' << ci.Line << std::endl;
544 raise(ci, -1,
"ASSERTTEST", args );
553 const std::span<std::any>& args ) {
557 RecursionBlocker blocker;
558 if (blocker.blocked())
563 initializeDefaultPrintables();
571 for(
nchar c : domain ) {
573 || ( c >=
'A' && c <=
'Z' )
574 || c ==
'-' || c ==
'_' || c ==
'/' || c ==
'.' ) ) {
575 std::cerr <<
"Illegal alib::assert::Assert() domain given: " << domain << std::endl;
580 while (i < args.size()) {
581 const std::any& arg = args[i];
583 if ( arg.type() ==
typeid(
const char*)
584 || arg.type() ==
typeid(std::string)
585 || arg.type() ==
typeid(std::string_view) ) {
587 std::string_view str;
589 if (arg.type() ==
typeid(
const char*)) str = std::string_view( std::any_cast<const char* >( arg));
590 else if (arg.type() ==
typeid(std::string)) str = std::string_view(*std::any_cast<std::string >(&arg));
591 else str = std::any_cast<std::string_view>( arg) ;
592 std::string_view origStr= str;
596 auto handle_format_string = [&]() {
598 while ((pos = str.find(
"{}")) != std::string::npos) {
600 outBuffer+= str.substr(0, pos);
603 if (++i >= args.size()) {
604 std::cerr <<
"alib::assert: Not enough arguments for format placeholders!" << std::endl;
605 std::cerr <<
" Format string: <" << origStr <<
'>' << std::endl;
606 std::cerr <<
" @ : " << ci.
File <<
':' << ci.
Line << std::endl;
612 const std::any& placeholderArg = args[i];
613 printRegisteredAny(placeholderArg, ci);
616 str = str.substr(pos + 2);
626 handle_format_string();
628 printRegisteredAny(arg, ci);
635 PLUGIN( ci, type, domain, outBuffer.c_str() );
642 #if !ALIB_SINGLE_THREADED
644 if( lockingIoStreams )
651 type, domain, ci.
File, ci.
Line, outBuffer);
652 #if !ALIB_SINGLE_THREADED
653 if( lockingIoStreams )
660 if (type == 0) {HALT_FLAGS_AND_COUNTERS.CtdErrors++; halt= HALT_FLAGS_AND_COUNTERS.HaltOnErrors; }
661 else if (type == 1) {HALT_FLAGS_AND_COUNTERS.CtdWarnings++; halt= HALT_FLAGS_AND_COUNTERS.HaltOnWarnings; }
662 else {HALT_FLAGS_AND_COUNTERS.CtdMessages++; halt=
false; }
663 #if defined( _WIN32 )
673 #if defined(__GNUC__) || defined(__clang__)
676 #elif defined ( _MSC_VER )
#define ALIB_ERROR(domain,...)
#define ALIB_LOCK_RECURSIVE_WITH(lock)
@ 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".
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::TSubstring< nchar > NSubstring
Type alias in namespace #"%alib".
strings::TCString< xchar > XCString
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>".
strings::TSubstring< wchar > WSubstring
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".