ALib C++ Library
Library Version: 2511 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
assert.cpp
1//##################################################################################################
2// ALib C++ Library
3//
4// Copyright 2013-2025 A-Worx GmbH, Germany
5// Published under 'Boost Software License' (a free software license, see LICENSE.txt)
6//##################################################################################################
7#include "alib_precompile.hpp"
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"
10#endif
11#if ALIB_C20_MODULES
12 module;
13#endif
14//========================================= Global Fragment ========================================
17#if ALIB_DEBUG
18# include <cstdlib>
20# include <cassert>
21# include <cstring>
22# include <iostream>
23# include <iomanip>
24# include <string>
25# include <string>
26# include <stdexcept>
27# include <any>
28# if __has_include(<format>)
29# include <format>
30# else
31# include <fmt/format.h>
32# endif
33# include <codecvt>
34
35# if (ALIB_SINGLE_THREADED && ALIB_EXT_LIB_THREADS_AVAILABLE)
36# include <thread>
37# endif
38# if ALIB_DEBUG_ASSERTION_PRINTABLES
39# include <unordered_set>
40# endif
41
42# include <iostream>
43# include <iomanip>
44# include <typeindex>
45# include <functional>
46#endif
47
48//============================================== Module ============================================
49#if ALIB_C20_MODULES
50 module ALib.Lang;
51# if ALIB_DEBUG
52 import ALib.Threads;
53 import ALib.Bootstrap;
54# if ALIB_STRINGS
55 import ALib.Strings;
56 import ALib.Strings.Token;
57# if ALIB_MONOMEM
58 import ALib.Strings.Monomem;
59# endif
60# endif
61# if ALIB_BOXING
62 import ALib.Boxing;
63# endif
64# if ALIB_ENUMRECORDS
65 import ALib.EnumRecords;
66# endif
67# if ALIB_RESOURCES
68 import ALib.Resources;
69# endif
70# if ALIB_VARIABLES
71 import ALib.Variables;
72# endif
73# if ALIB_SYSTEM
74 import ALib.System;
75# endif
76# if ALIB_THREADMODEL
77 import ALib.ThreadModel;
78# endif
79# if ALIB_CAMP
80 import ALib.Camp.Base;
81# endif
82# endif
83#else
84# include "ALib.Lang.H"
85# if ALIB_DEBUG
86# include "ALib.Bootstrap.H"
87# include "ALib.Threads.H"
88# include "ALib.Strings.H"
89# include "ALib.Strings.Token.H"
90# include "ALib.Strings.Monomem.H"
91# include "ALib.Boxing.H"
92# include "ALib.EnumRecords.H"
93# include "ALib.Resources.H"
94# include "ALib.Variables.H"
95# include "ALib.System.H"
96# include "ALib.ThreadModel.H"
97# include "ALib.Camp.Base.H"
98# endif
99#endif
100
101#if ALIB_DEBUG
102//========================================== Implementation ========================================
104
105namespace alib::assert {
106
107//##################################################################################################
108// Debug functions
109//##################################################################################################
110#if (ALIB_SINGLE_THREADED && ALIB_EXT_LIB_THREADS_AVAILABLE) || DOXYGEN
111
112#if !DOXYGEN
113 namespace { std::thread::id dbg_thread_seen;
114 bool dbg_in_single_threaded_check= false; }
115#endif
116
117
118//==================================================================================================
119/// This function stores the first thread that invokes it, and if in the future the method is
120/// visited by a different thread, it asserts.
121///
122/// In release compilations, this function is inlined and empty, and therefore it is not
123/// necessary to remove usages with preprocessor macro \ref ALIB_DBG or similar.
124///
125/// In debug-compilations, this is not empty if:
126/// 1. Compiler symbol \ref ALIB_SINGLE_THREADED is set (what disables thread-safeness
127/// throughout the library), and
128/// 2. Compiler symbol \ref ALIB_EXT_LIB_THREADS_AVAILABLE was passed on library compilation,
129/// which allows using the C++ standard library's threading types without causing linker
130/// failures.
131///
132/// If given, this function is, for example, called by macros \ref ALIB_LOCK or
133/// \ref ALIB_DCS, which otherwise are defined to do what they are supposed to do.
134/// This exclamatory approach was made with \alib to motivate to
135/// write \ref alib_threads_intro_agnostic "threading-agnostic software".
136///
137/// Besides several macros, some other prominent \alib entities, like \alib{lox::Lox},
138/// \alib{format;Formatter} or \alib{monomem;TMonoAllocator} invoke this method with their
139/// acquisition.
140//==================================================================================================
142{
143 if( dbg_in_single_threaded_check ) // this would happen when the assertion below is raised
144 return;
145 dbg_in_single_threaded_check= true;
146
147 // first time?
148 if( lang::IsNull(dbg_thread_seen) )
149 {
150 dbg_thread_seen= std::this_thread::get_id();
151 dbg_in_single_threaded_check= false;
152 return;
153 }
154
155 if( dbg_thread_seen != std::this_thread::get_id() )
156 {
157 ALIB_ERROR( "THREADS",
158 "A second thread was detected using a single-threaded compilation of ALib"
159 "(Symbol 'ALIB_SINGLE_THREADED' given with the ALib Build)." )
160 }
161 dbg_in_single_threaded_check= false;
162}
163#endif // ALIB_SINGLE_THREADED && ALIB_EXT_LIB_THREADS_AVAILABLE
164
165} // namespace [alib]
166
167//##################################################################################################
168// Assert functions
169//##################################################################################################
170namespace alib::assert {
171
172void (*PLUGIN)( const CallerInfo& ci , int type,
173 std::string_view domain, std::string_view msg ) = nullptr;
174
175namespace { }
176std::string_view FORMAT = "{file}:{line} {type}:\n{message}";
177std::ostream* STREAM_ERRORS = &std::cerr;
178std::ostream* STREAM_WARNINGS = &std::cout;
179std::ostream* STREAM_MESSAGES = &std::cout;
180
181#if !DOXYGEN
182namespace {
183 thread_local TLD HALT_FLAGS_AND_COUNTERS;
184 bool isInitialized= false;
185 std::string outBuffer;
186#if !ALIB_SINGLE_THREADED
187 RecursiveLock lock;
188#endif
189
190
191static std::unordered_map<std::type_index, AnyConversionFunc> registeredAnys;
192
193#if __has_include(<format>)
194 namespace f=std;
195#else
196 namespace f=fmt;
197#endif
198
199void initializeDefaultPrintables() {
200 isInitialized= true;
201 RegisterPrintable(typeid( bool ), [](const std::any& any, std::string& s) { s+= f::format("{}", std::any_cast< bool >(any)); });
202 RegisterPrintable(typeid( char ), [](const std::any& any, std::string& s) { s+= f::format("{}", std::any_cast< char >(any)); });
203 RegisterPrintable(typeid( int8_t ), [](const std::any& any, std::string& s) { s+= f::format("{}", std::any_cast< int8_t >(any)); });
204 RegisterPrintable(typeid(uint8_t ), [](const std::any& any, std::string& s) { s+= f::format("{}", std::any_cast<uint8_t >(any)); });
205 RegisterPrintable(typeid( int16_t ), [](const std::any& any, std::string& s) { s+= f::format("{}", std::any_cast< int16_t >(any)); });
206 RegisterPrintable(typeid(uint16_t ), [](const std::any& any, std::string& s) { s+= f::format("{}", std::any_cast<uint16_t >(any)); });
207 RegisterPrintable(typeid( int32_t ), [](const std::any& any, std::string& s) { s+= f::format("{}", std::any_cast< int32_t >(any)); });
208 RegisterPrintable(typeid(uint32_t ), [](const std::any& any, std::string& s) { s+= f::format("{}", std::any_cast<uint32_t >(any)); });
209 RegisterPrintable(typeid( int64_t ), [](const std::any& any, std::string& s) { s+= f::format("{}", std::any_cast< int64_t >(any)); });
210 RegisterPrintable(typeid(uint64_t ), [](const std::any& any, std::string& s) { s+= f::format("{}", std::any_cast<uint64_t >(any)); });
211 RegisterPrintable(typeid(float ), [](const std::any& any, std::string& s) { s+= f::format("{}", std::any_cast<float >(any)); });
212 RegisterPrintable(typeid(unsigned long), [](const std::any& any, std::string& s) { s+= f::format("{}", std::any_cast<unsigned long>(any)); });
213DOX_MARKER( [DOX_ASSERT_REGISTER_PRINTABLE])
214RegisterPrintable(typeid(double),
215 [](const std::any& any, std::string& s) {
216 s+= f::format("{}", std::any_cast<double >(any));
217 });
218RegisterPrintable(typeid(const char*),
219 [](const std::any& any, std::string& s) {
220 auto* value= std::any_cast<const char*>(any);
221 if (value)
222 s+= value;
223 });
224RegisterPrintable(typeid(const char8_t*),
225 [](const std::any& any, std::string& s) {
226 auto* value= std::any_cast<const char*>(any);
227 if (value)
228 s+= value;
229 });
230RegisterPrintable(typeid(const wchar_t*),
231 [](const std::any& any, std::string& s) {
232 auto* value= std::any_cast<const wchar_t*>(any);
233 if (value) {
235 std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
236 s+= converter.to_bytes(value);
238 }
239 });
240DOX_MARKER( [DOX_ASSERT_REGISTER_PRINTABLE])
241
242 if constexpr (sizeof(wchar_t) == 2)
243 RegisterPrintable(typeid(const char32_t*),
244 [](const std::any& any, std::string& s) {
245 auto* value= std::any_cast<const char32_t*>(any);
246 if (value) {
248 std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> converter;
249 s+= converter.to_bytes(value);
251 }
252 });
253 if constexpr (sizeof(wchar_t) == 4)
254 RegisterPrintable(typeid(const char16_t*),
255 [](const std::any& any, std::string& s) {
256 auto* value= std::any_cast<const char16_t*>(any);
257 if (value) {
259 std::wstring_convert<std::codecvt_utf8<char16_t>, char16_t> converter;
260 s+= converter.to_bytes(value);
262 }
263 });
264
265 RegisterPrintable(typeid(std::string ), [](const std::any& any, std::string& s) { s+= *std::any_cast<std::string >(&any); });
266 RegisterPrintable(typeid(std::string_view ), [](const std::any& any, std::string& s) { s+= std::any_cast<std::string_view>( any); });
267 RegisterPrintable(typeid(const std::type_info*), [](const std::any& any, std::string& s) {
268 auto* typeInfo= std::any_cast<const std::type_info*>(any);
269 if (typeInfo)
270 s+= lang::DbgTypeDemangler(*typeInfo).Get();
271 });
272 RegisterPrintable(typeid(std::thread::id) , [](const std::any& any, std::string& s) {
273 #if !ALIB_SINGLE_THREADED
274 auto threadID= std::any_cast<std::thread::id>(any);
275 if ( !lang::IsNull(threadID)) {
276 Thread* thread= Thread::Get(threadID);
277 if (thread) {
278 #if !ALIB_CHARACTERS_WIDE
279 s+= thread->GetName();
280 #else
281 std::wstring_convert<std::codecvt_utf8<character>, character> converter;
282 s+= converter.to_bytes(thread->GetName());
283 #endif
284 s += f::format("({})", thread->GetID());
285 }
286 else
287 s+= "<Unknown thread>";
288 }
289 #else
290 (void) any;
291 s+= "<SINGLE_THREADED>";
292 #endif
293 });
294
295 RegisterPrintable(typeid(CallerInfo), [](const std::any& any, std::string& s) {
296 CallerInfo callerInfo= std::any_cast<CallerInfo>(any);
297 if ( callerInfo.File == nullptr ) {
298 s+= "<nulled caller>";
299 return;
300 }
301 s+=f::format("{{Caller: @ {}:{} ({}) ", callerInfo.File,callerInfo.Line, callerInfo.Func);
302 if ( callerInfo.TypeInfo ) {
303 s+= "<"; s+= lang::DbgTypeDemangler(*callerInfo.TypeInfo).Get();s+= "> ";
304 }
305 #if !ALIB_SINGLE_THREADED
306 s+=f::format("thread::id= {}", 5 );
307 #endif
308 s+= '}';
309 });
310
311 RegisterPrintable(typeid(Thread*) , [](const std::any& any, std::string& s) {
312 #if !ALIB_SINGLE_THREADED
313 Thread* thread= std::any_cast<Thread*>(any);
314 if (thread) {
315 #if !ALIB_CHARACTERS_WIDE
316 s+= thread->GetName();
317 #else
318 std::wstring_convert<std::codecvt_utf8<character>, character> converter;
319 s+= converter.to_bytes(thread->GetName());
320 #endif
321 s += f::format("({})", thread->GetID());
322 }
323 else
324 s+= "<Unknown thread>";
325 #else
326 (void) any;
327 s+= "<SINGLE_THREADED>";
328 #endif
329 });
330
331 #if !ALIB_SINGLE_THREADED
332 RegisterPrintable(typeid(Thread::State) , [](const std::any& any, std::string& s) {
333 auto state= std::any_cast<Thread::State>(any);
334 if (state==Thread::State::Unstarted ) s+= "Unstarted";
335 else if (state==Thread::State::Started ) s+= "Started";
336 else if (state==Thread::State::Running ) s+= "Running";
337 else if (state==Thread::State::Done ) s+= "Done";
338 else if (state==Thread::State::Terminated) s+= "Terminated";
339 else s+= "<Unknown thread state>";
340 });
341 #endif
342
344 #if ALIB_STRINGS
345 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()) ); });
346 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()) ); });
347 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()) ); });
348 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() ); });
349 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() ); });
350 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() ); });
351 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() ); });
352 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() ); });
353 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() ); });
354 RegisterPrintable(typeid(Token ), [](const std::any& any, std::string& s) { s+= NString256(String256(std::any_cast<Token>(any))); });
355 #if ALIB_MONOMEM
356 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()) ); });
357 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() ); });
358 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()) ); });
359 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() ); });
360 #endif
361 #endif
363
364 #if ALIB_BOXING && ALIB_ENUMRECORDS
365 RegisterPrintable(typeid(Box ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<Box >(any)); });
366 RegisterPrintable(typeid(Enum), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<Enum>(any)); });
367 #endif
368
369 // CodeMarker_CommonEnums
370 #if ALIB_ENUMRECORDS
371 RegisterPrintable(typeid(lang::Alignment ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::Alignment >(any)); });
372 RegisterPrintable(typeid(lang::Bool ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::Bool >(any)); });
373 RegisterPrintable(typeid(lang::Caching ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::Caching >(any)); });
374 RegisterPrintable(typeid(lang::Case ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::Case >(any)); });
375 RegisterPrintable(typeid(lang::ContainerOp ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::ContainerOp >(any)); });
376 RegisterPrintable(typeid(lang::CreateDefaults ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::CreateDefaults >(any)); });
377 RegisterPrintable(typeid(lang::CreateIfNotExists), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::CreateIfNotExists>(any)); });
378 RegisterPrintable(typeid(lang::CurrentData ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::CurrentData >(any)); });
379 RegisterPrintable(typeid(lang::Inclusion ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::Inclusion >(any)); });
380 RegisterPrintable(typeid(lang::Initialization ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::Initialization >(any)); });
381 RegisterPrintable(typeid(lang::LineFeeds ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::LineFeeds >(any)); });
382 RegisterPrintable(typeid(lang::Phase ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::Phase >(any)); });
383 RegisterPrintable(typeid(lang::Propagation ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::Propagation >(any)); });
384 RegisterPrintable(typeid(lang::Reach ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::Reach >(any)); });
385 RegisterPrintable(typeid(lang::Recursive ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::Recursive >(any)); });
386 RegisterPrintable(typeid(lang::Responsibility ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::Responsibility >(any)); });
387 RegisterPrintable(typeid(lang::Safeness ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::Safeness >(any)); });
388 RegisterPrintable(typeid(lang::Side ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::Side >(any)); });
389 RegisterPrintable(typeid(lang::SortOrder ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::SortOrder >(any)); });
390 RegisterPrintable(typeid(lang::SourceData ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::SourceData >(any)); });
391 RegisterPrintable(typeid(lang::Switch ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::Switch >(any)); });
392 RegisterPrintable(typeid(lang::Timezone ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::Timezone >(any)); });
393 RegisterPrintable(typeid(lang::Timing ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::Timing >(any)); });
394 RegisterPrintable(typeid(lang::ValueReference ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::ValueReference >(any)); });
395 RegisterPrintable(typeid(lang::Whitespaces ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::Whitespaces >(any)); });
396 #endif
397
398 #if ALIB_VARIABLES
399 RegisterPrintable(typeid(const variables::Variable*), [](const std::any& any, std::string& s) {
400 auto* o= std::any_cast<const variables::Variable*>(any);
401 String256 serialize;
402 o->Name(serialize);
403 ALIB_STRINGS_TO_NARROW(serialize, ns, 256)
404 s+= ns;
405 });
406 RegisterPrintable(typeid(variables::Variable*), [](const std::any& any, std::string& s) {
407 auto* o= std::any_cast<variables::Variable*>(any);
408 String256 serialize;
409 o->Name(serialize);
410 ALIB_STRINGS_TO_NARROW(serialize, ns, 256)
411 s+= ns;
412 });
413 RegisterPrintable(typeid(variables::Variable), [](const std::any& any, std::string& s) {
414 auto o= std::any_cast<variables::Variable>(any);
415 String256 serialize;
416 o.Name(serialize);
417 ALIB_STRINGS_TO_NARROW(serialize, ns, 256)
418 s+= ns;
419 });
420 RegisterPrintable(typeid(variables::Priority), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<variables::Priority>(any)); });
421 #endif
422 #if ALIB_SYSTEM
423 RegisterPrintable(typeid(system::Path ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<system::Path >(any)); });
424 # if ALIB_CAMP
425 RegisterPrintable(typeid(system::SystemErrors), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<system::SystemErrors>(any)); });
426 # endif
427 #endif
428 #if ALIB_THREADMODEL && ALIB_ENUMRECORDS
429 RegisterPrintable(typeid(threadmodel::Priority), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<threadmodel::Priority>(any)); });
430 #endif
431
432 }
433
434void printRegisteredAny(const std::any& any, const CallerInfo& ci) {
435 if (!any.has_value())
436 return;
437 auto it = registeredAnys.find(std::type_index(any.type()));
438 if (it != registeredAnys.end()) {
439 // Call the associated function
440 it->second(any, outBuffer);
441 } else {
442 std::cerr << "Internal Error using alib::assert::Assert(): No converter registered for type: <"
443 << lang::DbgTypeDemangler( any.type() ).Get()
444 << '>' << std::endl
445 << "at " << ci.File << ':' << ci.Line << std::endl;
446 assert(false);
447} }
448
449const char* resolveMessageType(int msgType) {
450 if (msgType == 0) return "error";
451 if (msgType == 1) return "warning";
452 return "message";
453}
454
455void writeMessage( std::ostream& os, int msgType, const std::string_view& domain,
456 const char* file, int line,
457 const std::string_view& message ) {
458 // Start with the global format string
459 std::string_view format = FORMAT;
460
461 // Loop and process the format string
462 size_t start = 0;
463 while (start < format.size()) {
464 // Find the next placeholder starting from 'start'
465 size_t openBrace = format.find('{', start);
466 if (openBrace == std::string_view::npos) {
467 // No more placeholders, print the remaining part
468 os << format.substr(start);
469 break;
470 }
471
472 // Print everything before the '{'
473 os << format.substr(start, openBrace - start);
474
475 // Find the closing '}'
476 size_t closeBrace = format.find('}', openBrace + 1);
477 if (closeBrace == std::string_view::npos) {
478 // Invalid placeholder syntax (no closing '}'), just print raw text
479 os << format.substr(openBrace);
480 break;
481 }
482
483 // Extract the placeholder name
484 std::string_view placeholder = format.substr(openBrace + 1, closeBrace - openBrace - 1);
485
486 // Substitute the placeholder with the corresponding value
487 if ( placeholder == "type" ) os << resolveMessageType(msgType);
488 else if ( placeholder == "file" ) os << file;
489 else if ( placeholder == "line" ) os << line;
490 else if ( placeholder == "message" ) os << message;
491 else if ( placeholder == "domain" ) os << domain;
492 else os << "{" << placeholder << "}"; // unknown placeholder
493
494 // Move past the closing '}'
495 start = closeBrace + 1;
496 }
497 os << std::endl;
498} // writeMessage
499
500class RecursionBlocker {
501 private:
502 static inline std::atomic<bool> isRecursing{false};
503 bool wasBlocked;
504
505 public:
506 RecursionBlocker() noexcept { wasBlocked = isRecursing.exchange(true); }
507
508 ~RecursionBlocker() { if (!wasBlocked) isRecursing = false; }
509
510 [[nodiscard]] bool blocked() const noexcept { return wasBlocked; }
511
512 // Delete copy operations to ensure RAII semantics
513 RecursionBlocker(const RecursionBlocker&) =delete;
514 RecursionBlocker& operator =(const RecursionBlocker&) =delete;
515};
516
517#if ALIB_DEBUG_ASSERTION_PRINTABLES
518 struct Key { const char* str; // Pointer to the file name
519 int value; // Line number
520 bool operator==(const Key& other) const {
521 return str == other.str && value == other.value;
522 }};
523
524 struct KeyHash { std::size_t operator()(const Key& key) const {
525 return std::hash<const char*>()(key.str) ^ ( std::hash<int>()(key.value) << 1);
526 }};
527
528 std::unordered_set<Key, KeyHash> seenSourceLocations;
529#endif // ALIB_DEBUG_ASSERTION_PRINTABLES
530
531} // namespace [anonymous]
532
533void RegisterPrintable(std::type_index typeIndex, AnyConversionFunc func) {
534 registeredAnys[typeIndex] = func;
535}
536
537#if ALIB_DEBUG_ASSERTION_PRINTABLES
538# pragma message ("ALIB_DEBUG_ASSERTION_PRINTABLES set. ALib will print all assertions once, no matter if they are raised or not." )
539 void CheckArgsImpl( const CallerInfo& ci, const std::span<std::any>& args ) {
540 if ( !alib::NonCampModulesInitialized ) return;
541 if( !isInitialized ) initializeDefaultPrintables();
542
543 if (!seenSourceLocations.insert(Key{ci.File, ci.Line}).second)
544 return;
545
546
547 for (size_t i = 0; i < args.size(); ++i) {
548 auto it = registeredAnys.find(std::type_index(args[i].type()));
549 if (it == registeredAnys.end()) {
550 std::cerr << "Internal Error using alib::assert::Assert(): No converter registered for type: <"
551 << lang::DbgTypeDemangler( args[i].type() ).Get()
552 << '>' << std::endl
553 << " at: " << ci.File << ':' << ci.Line << std::endl;
554 assert(false);
555 }}
556
557 raise(ci, -1, "ASSERTTEST", args );
558 }
559#endif
560
561#endif // !DOXYGEN
562
563TLD& GetHaltFlagAndCounters() { return HALT_FLAGS_AND_COUNTERS; }
564
565void raise( const CallerInfo& ci, int type, std::string_view domain,
566 const std::span<std::any>& args ) {
567
568 // lock parallel assertions if necessary
570 RecursionBlocker blocker;
571 if (blocker.blocked())
572 return;
573
574 // register printable types (once)
575 if( !isInitialized )
576 initializeDefaultPrintables();
577
578 // assemble message
579 outBuffer.clear();
580
581 // With ALox replacing this method (the usual thing), the first string might auto-detected
582 // as an ALox domain name. To keep this consistent, we do a similar effort here.
583 {
584 for( nchar c : domain ) {
585 if (! ( isdigit( c )
586 || ( c >= 'A' && c <= 'Z' )
587 || c == '-' || c == '_' || c == '/' || c == '.' ) ) {
588 std::cerr << "Illegal alib::assert::Assert() domain given: " << domain << std::endl;
589 assert(false);
590 }}}
591
592 size_t i = 0; // Index to track the current argument
593 while (i < args.size()) {
594 const std::any& arg = args[i];
595
596 if ( arg.type() == typeid(const char*)
597 || arg.type() == typeid(std::string)
598 || arg.type() == typeid(std::string_view) ) {
599
600 std::string_view str;
601
602 if (arg.type() == typeid(const char*)) str = std::string_view( std::any_cast<const char* >( arg));
603 else if (arg.type() == typeid(std::string)) str = std::string_view(*std::any_cast<std::string >(&arg));
604 else str = std::any_cast<std::string_view>( arg) ;
605 std::string_view origStr= str;
606
607
608 // Lambda function to parse and print the format string
609 auto handle_format_string = [&]() {
610 size_t pos = 0; // Position to find "{}"
611 while ((pos = str.find("{}")) != std::string::npos) {
612 // Print the portion before the placeholder
613 outBuffer+= str.substr(0, pos);
614
615 // Move to the next argument for substitution
616 if (++i >= args.size()) {
617 std::cerr << "alib::assert: Not enough arguments for format placeholders!" << std::endl;
618 std::cerr << " Format string: <" << origStr << '>' << std::endl;
619 std::cerr << " @ : " << ci.File << ':' << ci.Line << std::endl;
620 assert(false);
621 return;
622 }
623
624 // Print the argument substituted in place of "{}"
625 const std::any& placeholderArg = args[i];
626 printRegisteredAny(placeholderArg, ci);
627
628 // Remove the processed portion of the string
629 str = str.substr(pos + 2);
630 }
631
632 // Print the remaining part of the string (after all `{}` are replaced)
633 outBuffer+= str;
634
635 // End the lambda function
636 };
637
638 // Process the format string with the lambda
639 handle_format_string();
640 } else
641 printRegisteredAny(arg, ci);
642
643 ++i;
644 }
645
646 // if plugin hook, use it.
647 if( PLUGIN && type!= -1 ) // -1 = CheckArgs
648 PLUGIN( ci, type, domain, outBuffer.c_str() );
649
650 // Print the formatted message to the console.
651 else {
652 // check if we already lock io-streams. We can do this, because this is anyhow
653 // debug-code. This way, we avoid recursive locking.
654 // (If locked by somebody else, we do not care and still write to the ostream!)
655 #if !ALIB_SINGLE_THREADED
656 bool lockingIoStreams= !threads::STD_IOSTREAMS_LOCK.Dbg.IsOwnedByCurrentThread();
657 if( lockingIoStreams )
659 #endif
660
661 writeMessage( type == 0 ? *STREAM_ERRORS
662 : type == 1 ? *STREAM_WARNINGS
664 type, domain, ci.File, ci.Line, outBuffer);
665 #if !ALIB_SINGLE_THREADED
666 if( lockingIoStreams )
668 #endif
669 }
670
671 // Halt?
672 bool halt;
673 if (type == 0) {HALT_FLAGS_AND_COUNTERS.CtdErrors++; halt= HALT_FLAGS_AND_COUNTERS.HaltOnErrors; }
674 else if (type == 1) {HALT_FLAGS_AND_COUNTERS.CtdWarnings++; halt= HALT_FLAGS_AND_COUNTERS.HaltOnWarnings; }
675 else {HALT_FLAGS_AND_COUNTERS.CtdMessages++; halt= false; }
676 #if defined( _WIN32 )
677 if( halt ) {
678 #if ALIB_CAMP
679 if ( BASECAMP.IsDebuggerPresent() )
680 DebugBreak();
681 else
682 #endif
683 assert( false );
684 }
685 #else
686 #if defined(__GNUC__) || defined(__clang__)
687 if (halt)
688 __builtin_trap();
689 #elif defined ( _MSC_VER )
690 if (halt)
691 __debugbreak();
692 #else
693 (void) halt; // for release compiles with ALIB_DEBUG set
694 assert( !halt );
695 #endif
696
697 #endif
698}
699}// namespace [alib::assert]
700
701# include "ALib.Lang.CIMethods.H"
702#endif // ALIB_DEBUG
ALIB_DLL const char * Get()
@ Running
The thread's Run method is currently processed.
Definition thread.inl:141
@ Started
Method Start was invoked but not running, yet.
Definition thread.inl:140
@ Terminated
The thread is terminated.
Definition thread.inl:144
ThreadID GetID() const
Definition thread.inl:227
virtual const character * GetName() const
Definition thread.inl:241
static ALIB_DLL Thread * Get(std::thread::id nativeID)
Definition thread.cpp:314
#define ALIB_CALLER
Definition alib.inl:1018
#define ALIB_WARNINGS_RESTORE
Definition alib.inl:719
#define ALIB_STRINGS_TO_NARROW( src, dest, bufSize)
#define ALIB_ERROR(domain,...)
Definition alib.inl:1062
#define ALIB_LOCK_RECURSIVE_WITH(lock)
Definition alib.inl:1340
#define ALIB_WARNINGS_IGNORE_DEPRECATED
Definition alib.inl:661
This namespace exposes entities of module ALib Assert.
Definition assert.cpp:105
std::string_view FORMAT
Definition assert.cpp:176
std::ostream * STREAM_WARNINGS
Definition assert.cpp:178
void(* PLUGIN)(const CallerInfo &ci, int type, std::string_view domain, std::string_view msg)
Definition assert.cpp:172
std::ostream * STREAM_ERRORS
Definition assert.cpp:177
ALIB_DLL void CheckArgsImpl(const CallerInfo &ci, const std::span< std::any > &args)
TLD & GetHaltFlagAndCounters()
Definition assert.cpp:563
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)
Definition assert.cpp:565
std::ostream * STREAM_MESSAGES
Definition assert.cpp:179
void SingleThreaded()
Definition assert.cpp:141
void(*)(const std::any &, std::string &) AnyConversionFunc
Definition assert.inl:91
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.
Whitespaces
Denotes whether a string is trimmed or not.
constexpr bool IsNull(const T &t)
Definition tmp.inl:48
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.
Definition jobs.inl:168
ALIB_DLL Lock STD_IOSTREAMS_LOCK
Definition locks.cpp:48
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.
Definition token.inl:398
LocalString< 256 > String256
Type alias name for TLocalString<character,256>.
camp::Basecamp BASECAMP
The singleton instance of ALib Camp class Basecamp.
Definition basecamp.cpp:81
strings::TAString< wchar, MonoAllocator > WAStringMA
Type alias in namespace alib.
strings::TString< xchar > XString
Type alias in namespace alib.
Definition string.inl:2204
characters::wchar wchar
Type alias in namespace alib.
strings::TString< nchar > NString
Type alias in namespace alib.
Definition string.inl:2198
strings::TAString< nchar, lang::HeapAllocator > NAString
Type alias in namespace alib.
strings::TCString< xchar > XCString
Type alias in namespace alib.
Definition cstring.inl:490
threads::Thread Thread
Type alias in namespace alib.
Definition thread.inl:387
strings::TString< wchar > WString
Type alias in namespace alib.
Definition string.inl:2201
strings::TCString< wchar > WCString
Type alias in namespace alib.
Definition cstring.inl:487
strings::TCString< nchar > NCString
Type alias in namespace alib.
Definition cstring.inl:484
characters::nchar nchar
Type alias in namespace alib.
boxing::Enum Enum
Type alias in namespace alib.
Definition enum.inl:192
boxing::Box Box
Type alias in namespace alib.
Definition box.inl:1149
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.