8#if !defined(ALIB_C20_MODULES) || ((ALIB_C20_MODULES != 0) && (ALIB_C20_MODULES != 1))
9# error "Symbol 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>
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; }
143 if( dbg_in_single_threaded_check )
145 dbg_in_single_threaded_check=
true;
150 dbg_thread_seen= std::this_thread::get_id();
151 dbg_in_single_threaded_check=
false;
155 if( dbg_thread_seen != std::this_thread::get_id() )
158 "A second thread was detected using a single-threaded compilation of ALib"
159 "(Symbol 'ALIB_SINGLE_THREADED' given with the ALib Build)." )
161 dbg_in_single_threaded_check=
false;
172void (*
PLUGIN)(
const CallerInfo& ci,
int type, 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);
235 std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
236 s+= converter.to_bytes(value);
240DOX_MARKER( [DOX_ASSERT_REGISTER_PRINTABLE])
242 if constexpr (
sizeof(wchar_t) == 2)
244 [](
const std::any& any, std::string& s) {
245 auto* value= std::any_cast<const char32_t*>(any);
249 std::wstring_convert<std::codecvt_utf8<char32_t>,
char32_t> converter;
250 s+= converter.to_bytes(value);
254 if constexpr (
sizeof(wchar_t) == 4)
256 [](
const std::any& any, std::string& s) {
257 auto* value= std::any_cast<const char16_t*>(any);
261 std::wstring_convert<std::codecvt_utf8<char16_t>,
char16_t> converter;
262 s+= converter.to_bytes(value);
267 RegisterPrintable(
typeid(std::string ), [](
const std::any& any, std::string& s) { s+= *std::any_cast<std::string >(&any); });
268 RegisterPrintable(
typeid(std::string_view ), [](
const std::any& any, std::string& s) { s+= std::any_cast<std::string_view>( any); });
269 RegisterPrintable(
typeid(
const std::type_info*), [](
const std::any& any, std::string& s) {
270 auto* typeInfo= std::any_cast<const std::type_info*>(any);
274 RegisterPrintable(
typeid(std::thread::id) , [](
const std::any& any, std::string& s) {
275 #if !ALIB_SINGLE_THREADED
276 auto threadID= std::any_cast<std::thread::id>(any);
280 #if !ALIB_CHARACTERS_WIDE
283 std::wstring_convert<std::codecvt_utf8<character>,
character> converter;
284 s+= converter.to_bytes(thread->
GetName());
286 s += f::format(
"({})", thread->
GetID());
289 s+=
"<Unknown thread>";
293 s+=
"<SINGLE_THREADED>";
298 CallerInfo callerInfo= std::any_cast<CallerInfo>(any);
299 if ( callerInfo.
File ==
nullptr ) {
300 s+=
"<nulled caller>";
303 s+=f::format(
"{{Caller: @ {}:{} ({}) ", callerInfo.
File,callerInfo.
Line, callerInfo.
Func);
307 #if !ALIB_SINGLE_THREADED
308 s+=f::format(
"thread::id= {}", 5 );
314 #if !ALIB_SINGLE_THREADED
315 Thread* thread= std::any_cast<Thread*>(any);
317 #if !ALIB_CHARACTERS_WIDE
320 std::wstring_convert<std::codecvt_utf8<character>,
character> converter;
321 s+= converter.to_bytes(thread->
GetName());
323 s += f::format(
"({})", thread->
GetID());
326 s+=
"<Unknown thread>";
329 s+=
"<SINGLE_THREADED>";
333 #if !ALIB_SINGLE_THREADED
335 auto state= std::any_cast<Thread::State>(any);
341 else s+=
"<Unknown thread state>";
347 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()) ); });
348 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()) ); });
349 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()) ); });
350 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() ); });
351 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() ); });
352 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() ); });
353 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() ); });
354 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() ); });
355 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() ); });
358 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()) ); });
359 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() ); });
360 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()) ); });
361 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() ); });
366 #if ALIB_BOXING && ALIB_ENUMRECORDS
401 auto* o= std::any_cast<const variables::Variable*>(any);
408 auto* o= std::any_cast<variables::Variable*>(any);
415 auto o= std::any_cast<variables::Variable>(any);
429 #if ALIB_THREADMODEL && ALIB_ENUMRECORDS
435 void printRegisteredAny(
const std::any& any,
const CallerInfo& ci) {
436 if (!any.has_value())
438 auto it = registeredAnys.find(std::type_index(any.type()));
439 if (it != registeredAnys.end()) {
441 it->second(any, outBuffer);
443 std::cerr <<
"Internal Error using alib::assert::Assert(): No converter registered for type: <"
446 <<
"at " << ci.
File <<
':' << ci.
Line << std::endl;
451 const char* resolveMessageType(
int msgType) {
452 if (msgType == 0)
return "error";
453 if (msgType == 1)
return "warning";
457 void writeMessage( std::ostream& os,
int msgType,
const std::string_view& domain,
458 const char* file,
int line,
459 const std::string_view& message ) {
465 while (start <
format.size()) {
467 size_t openBrace =
format.find(
'{', start);
468 if (openBrace == std::string_view::npos) {
470 os <<
format.substr(start);
475 os <<
format.substr(start, openBrace - start);
478 size_t closeBrace =
format.find(
'}', openBrace + 1);
479 if (closeBrace == std::string_view::npos) {
481 os <<
format.substr(openBrace);
486 std::string_view placeholder =
format.substr(openBrace + 1, closeBrace - openBrace - 1);
489 if ( placeholder ==
"type" ) os << resolveMessageType(msgType);
490 else if ( placeholder ==
"file" ) os << file;
491 else if ( placeholder ==
"line" ) os << line;
492 else if ( placeholder ==
"message" ) os << message;
493 else if ( placeholder ==
"domain" ) os << domain;
494 else os <<
"{" << placeholder <<
"}";
497 start = closeBrace + 1;
502 class RecursionBlocker {
504 static inline std::atomic<bool> isRecursing{
false};
508 RecursionBlocker()
noexcept {
509 wasBlocked = isRecursing.exchange(
true);
512 ~RecursionBlocker() {
518 [[nodiscard]]
bool blocked()
const noexcept {
523 RecursionBlocker(
const RecursionBlocker&) =
delete;
524 RecursionBlocker& operator=(
const RecursionBlocker&) =
delete;
527#if ALIB_DEBUG_ASSERTION_PRINTABLES
528 struct Key {
const char* str;
530 bool operator==(
const Key& other)
const {
531 return str == other.str && value == other.value;
534 struct KeyHash { std::size_t operator()(
const Key& key)
const {
535 return std::hash<const char*>()(key.str) ^ ( std::hash<int>()(key.value) << 1);
538 std::unordered_set<Key, KeyHash> seenSourceLocations;
544 registeredAnys[typeIndex] = func;
547#if ALIB_DEBUG_ASSERTION_PRINTABLES
548# pragma message ("ALIB_DEBUG_ASSERTION_PRINTABLES set. ALib will print all assertions once, no matter if they are raised or not." )
551 if( !isInitialized ) initializeDefaultPrintables();
553 if (!seenSourceLocations.insert(Key{ci.File, ci.Line}).second)
557 for (
size_t i = 0; i < args.size(); ++i) {
558 auto it = registeredAnys.find(std::type_index(args[i].type()));
559 if (it == registeredAnys.end()) {
560 std::cerr <<
"Internal Error using alib::assert::Assert(): No converter registered for type: <"
561 << lang::DbgTypeDemangler( args[i].type() ).Get()
563 <<
" at: " << ci.File <<
':' << ci.Line << std::endl;
567 raise(ci, -1,
"ASSERTTEST", args );
576 const std::span<std::any>& args ) {
580 RecursionBlocker blocker;
581 if (blocker.blocked())
586 initializeDefaultPrintables();
594 for(
nchar c : domain ) {
596 || ( c >=
'A' && c <=
'Z' )
597 || c ==
'-' || c ==
'_' || c ==
'/' || c ==
'.' ) ) {
598 std::cerr <<
"Illegal alib::assert::Assert() domain given: " << domain << std::endl;
603 while (i < args.size()) {
604 const std::any& arg = args[i];
606 if ( arg.type() ==
typeid(
const char*)
607 || arg.type() ==
typeid(std::string)
608 || arg.type() ==
typeid(std::string_view) ) {
610 std::string_view str;
612 if (arg.type() ==
typeid(
const char*)) str = std::string_view( std::any_cast<const char* >( arg));
613 else if (arg.type() ==
typeid(std::string)) str = std::string_view(*std::any_cast<std::string >(&arg));
614 else str = std::any_cast<std::string_view>( arg) ;
615 std::string_view origStr= str;
619 auto handle_format_string = [&]() {
621 while ((pos = str.find(
"{}")) != std::string::npos) {
623 outBuffer+= str.substr(0, pos);
626 if (++i >= args.size())
628 std::cerr <<
"alib::assert: Not enough arguments for format placeholders!" << std::endl;
629 std::cerr <<
" Format string: <" << origStr <<
'>' << std::endl;
630 std::cerr <<
" @ : " << ci.
File <<
':' << ci.
Line << std::endl;
636 const std::any& placeholderArg = args[i];
637 printRegisteredAny(placeholderArg, ci);
640 str = str.substr(pos + 2);
650 handle_format_string();
652 printRegisteredAny(arg, ci);
659 PLUGIN( ci, type, domain, outBuffer.c_str() );
666 #if !ALIB_SINGLE_THREADED
668 if( lockingIoStreams )
675 type, domain, ci.
File, ci.
Line, outBuffer);
676 #if !ALIB_SINGLE_THREADED
677 if( lockingIoStreams )
684 if (type == 0) {HALT_FLAGS_AND_COUNTERS.CtdErrors++; halt= HALT_FLAGS_AND_COUNTERS.HaltOnErrors; }
685 else if (type == 1) {HALT_FLAGS_AND_COUNTERS.CtdWarnings++; halt= HALT_FLAGS_AND_COUNTERS.HaltOnWarnings; }
686 else {HALT_FLAGS_AND_COUNTERS.CtdMessages++; halt=
false; }
687 #if defined( _WIN32 )
698 #if defined(__GNUC__) || defined(__clang__)
699 if (halt) __builtin_trap();
700 #elif defined ( _MSC_VER )
701 if (halt) __debugbreak();
ALIB_DLL const char * Get()
@ 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 ALIB_DLL Thread * Get(std::thread::id nativeID)
#define ALIB_WARNINGS_RESTORE
#define ALIB_STRINGS_TO_NARROW( src, dest, bufSize)
#define ALIB_ERROR(domain,...)
#define ALIB_LOCK_RECURSIVE_WITH(lock)
#define ALIB_WARNINGS_IGNORE_DEPRECATED
This namespace exposes entities of module ALib Assert.
std::ostream * STREAM_WARNINGS
void(* PLUGIN)(const CallerInfo &ci, int type, std::string_view domain, std::string_view msg)
std::ostream * STREAM_ERRORS
ALIB_DLL void CheckArgsImpl(const CallerInfo &ci, const std::span< std::any > &args)
TLD & GetHaltFlagAndCounters()
ALIB_DLL void RegisterPrintable(std::type_index typeIndex, AnyConversionFunc func)
void raise(const CallerInfo &ci, int type, std::string_view domain, const std::span< std::any > &args)
std::ostream * STREAM_MESSAGES
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.
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.
Whitespaces
Denotes whether a string is trimmed or not.
constexpr bool IsNull(const T &t)
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.
ALIB_DLL Lock STD_IOSTREAMS_LOCK
strings::TAString< wchar, lang::HeapAllocator > WAString
Type alias in namespace alib.
strings::TAString< wchar, PoolAllocator > WAStringPA
Type alias in namespace alib.
strings::util::Token Token
Type alias in namespace alib.
LocalString< 256 > String256
Type alias name for TLocalString<character,256>.
camp::Basecamp BASECAMP
The singleton instance of ALib Camp class Basecamp.
strings::TAString< wchar, MonoAllocator > WAStringMA
Type alias in namespace alib.
strings::TString< xchar > XString
Type alias in namespace alib.
characters::wchar wchar
Type alias in namespace alib.
strings::TString< nchar > NString
Type alias in namespace alib.
strings::TAString< nchar, lang::HeapAllocator > NAString
Type alias in namespace alib.
strings::TCString< xchar > XCString
Type alias in namespace alib.
threads::Thread Thread
Type alias in namespace alib.
strings::TString< wchar > WString
Type alias in namespace alib.
strings::TCString< wchar > WCString
Type alias in namespace alib.
strings::TCString< nchar > NCString
Type alias in namespace alib.
characters::nchar nchar
Type alias in namespace alib.
boxing::Enum Enum
Type alias in namespace alib.
boxing::Box Box
Type alias in namespace alib.
strings::TAString< nchar, PoolAllocator > NAStringPA
Type alias in namespace alib.
threads::RecursiveLock RecursiveLock
Type alias in namespace alib.
strings::TAString< nchar, MonoAllocator > NAStringMA
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<nchar,256>.
strings::TAString< xchar, lang::HeapAllocator > XAString
Type alias in namespace alib.
characters::character character
Type alias in namespace alib.
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.