ALib C++ Library
Library Version: 2510 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
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 method 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, std::string_view domain, std::string_view msg ) = nullptr;
173
174namespace { }
175std::string_view FORMAT = "{file}:{line} {type}:\n{message}";
176std::ostream* STREAM_ERRORS = &std::cerr;
177std::ostream* STREAM_WARNINGS = &std::cout;
178std::ostream* STREAM_MESSAGES = &std::cout;
179
180#if !DOXYGEN
181namespace {
182 thread_local TLD HALT_FLAGS_AND_COUNTERS;
183 bool isInitialized= false;
184 std::string outBuffer;
185#if !ALIB_SINGLE_THREADED
186 RecursiveLock lock;
187#endif
188
189
190static std::unordered_map<std::type_index, AnyConversionFunc> registeredAnys;
191
192#if __has_include(<format>)
193 namespace f=std;
194#else
195 namespace f=fmt;
196#endif
197
198void initializeDefaultPrintables() {
199 isInitialized= true;
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])
213RegisterPrintable(typeid(double),
214 [](const std::any& any, std::string& s) {
215 s+= f::format("{}", std::any_cast<double >(any));
216 });
217RegisterPrintable(typeid(const char*),
218 [](const std::any& any, std::string& s) {
219 auto* value= std::any_cast<const char*>(any);
220 if (value)
221 s+= value;
222 });
223RegisterPrintable(typeid(const char8_t*),
224 [](const std::any& any, std::string& s) {
225 auto* value= std::any_cast<const char*>(any);
226 if (value)
227 s+= value;
228 });
229RegisterPrintable(typeid(const wchar_t*),
230 [](const std::any& any, std::string& s) {
231 auto* value= std::any_cast<const wchar_t*>(any);
232 if (value)
233 {
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)
247 {
249 std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> converter;
250 s+= converter.to_bytes(value);
252 }
253 });
254 if constexpr (sizeof(wchar_t) == 4)
255 RegisterPrintable(typeid(const char16_t*),
256 [](const std::any& any, std::string& s) {
257 auto* value= std::any_cast<const char16_t*>(any);
258 if (value)
259 {
261 std::wstring_convert<std::codecvt_utf8<char16_t>, char16_t> converter;
262 s+= converter.to_bytes(value);
264 }
265 });
266
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);
271 if (typeInfo)
272 s+= lang::DbgTypeDemangler(*typeInfo).Get();
273 });
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);
277 if ( !lang::IsNull(threadID)) {
278 Thread* thread= Thread::Get(threadID);
279 if (thread) {
280 #if !ALIB_CHARACTERS_WIDE
281 s+= thread->GetName();
282 #else
283 std::wstring_convert<std::codecvt_utf8<character>, character> converter;
284 s+= converter.to_bytes(thread->GetName());
285 #endif
286 s += f::format("({})", thread->GetID());
287 }
288 else
289 s+= "<Unknown thread>";
290 }
291 #else
292 (void) any;
293 s+= "<SINGLE_THREADED>";
294 #endif
295 });
296
297 RegisterPrintable(typeid(CallerInfo), [](const std::any& any, std::string& s) {
298 CallerInfo callerInfo= std::any_cast<CallerInfo>(any);
299 if ( callerInfo.File == nullptr ) {
300 s+= "<nulled caller>";
301 return;
302 }
303 s+=f::format("{{Caller: @ {}:{} ({}) ", callerInfo.File,callerInfo.Line, callerInfo.Func);
304 if ( callerInfo.TypeInfo ) {
305 s+= "<"; s+= lang::DbgTypeDemangler(*callerInfo.TypeInfo).Get();s+= "> ";
306 }
307 #if !ALIB_SINGLE_THREADED
308 s+=f::format("thread::id= {}", 5 );
309 #endif
310 s+= '}';
311 });
312
313 RegisterPrintable(typeid(Thread*) , [](const std::any& any, std::string& s) {
314 #if !ALIB_SINGLE_THREADED
315 Thread* thread= std::any_cast<Thread*>(any);
316 if (thread) {
317 #if !ALIB_CHARACTERS_WIDE
318 s+= thread->GetName();
319 #else
320 std::wstring_convert<std::codecvt_utf8<character>, character> converter;
321 s+= converter.to_bytes(thread->GetName());
322 #endif
323 s += f::format("({})", thread->GetID());
324 }
325 else
326 s+= "<Unknown thread>";
327 #else
328 (void) any;
329 s+= "<SINGLE_THREADED>";
330 #endif
331 });
332
333 #if !ALIB_SINGLE_THREADED
334 RegisterPrintable(typeid(Thread::State) , [](const std::any& any, std::string& s) {
335 auto state= std::any_cast<Thread::State>(any);
336 if (state==Thread::State::Unstarted ) s+= "Unstarted";
337 else if (state==Thread::State::Started ) s+= "Started";
338 else if (state==Thread::State::Running ) s+= "Running";
339 else if (state==Thread::State::Done ) s+= "Done";
340 else if (state==Thread::State::Terminated) s+= "Terminated";
341 else s+= "<Unknown thread state>";
342 });
343 #endif
344
346 #if ALIB_STRINGS
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() ); });
356 RegisterPrintable(typeid(Token ), [](const std::any& any, std::string& s) { s+= NString256(String256(std::any_cast<Token>(any))); });
357 #if ALIB_MONOMEM
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() ); });
362 #endif
363 #endif
365
366 #if ALIB_BOXING && ALIB_ENUMRECORDS
367 RegisterPrintable(typeid(Box ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<Box >(any)); });
368 RegisterPrintable(typeid(Enum), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<Enum>(any)); });
369 #endif
370
371 // CodeMarker_CommonEnums
372 #if ALIB_ENUMRECORDS
373 RegisterPrintable(typeid(lang::Alignment ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::Alignment >(any)); });
374 RegisterPrintable(typeid(lang::Bool ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::Bool >(any)); });
375 RegisterPrintable(typeid(lang::Caching ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::Caching >(any)); });
376 RegisterPrintable(typeid(lang::Case ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::Case >(any)); });
377 RegisterPrintable(typeid(lang::ContainerOp ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::ContainerOp >(any)); });
378 RegisterPrintable(typeid(lang::CreateDefaults ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::CreateDefaults >(any)); });
379 RegisterPrintable(typeid(lang::CreateIfNotExists), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::CreateIfNotExists>(any)); });
380 RegisterPrintable(typeid(lang::CurrentData ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::CurrentData >(any)); });
381 RegisterPrintable(typeid(lang::Inclusion ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::Inclusion >(any)); });
382 RegisterPrintable(typeid(lang::Initialization ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::Initialization >(any)); });
383 RegisterPrintable(typeid(lang::Phase ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::Phase >(any)); });
384 RegisterPrintable(typeid(lang::Propagation ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::Propagation >(any)); });
385 RegisterPrintable(typeid(lang::Reach ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::Reach >(any)); });
386 RegisterPrintable(typeid(lang::Recursive ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::Recursive >(any)); });
387 RegisterPrintable(typeid(lang::Responsibility ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::Responsibility >(any)); });
388 RegisterPrintable(typeid(lang::Safeness ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::Safeness >(any)); });
389 RegisterPrintable(typeid(lang::Side ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::Side >(any)); });
390 RegisterPrintable(typeid(lang::SortOrder ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::SortOrder >(any)); });
391 RegisterPrintable(typeid(lang::SourceData ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::SourceData >(any)); });
392 RegisterPrintable(typeid(lang::Switch ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::Switch >(any)); });
393 RegisterPrintable(typeid(lang::Timezone ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::Timezone >(any)); });
394 RegisterPrintable(typeid(lang::Timing ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::Timing >(any)); });
395 RegisterPrintable(typeid(lang::ValueReference ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::ValueReference >(any)); });
396 RegisterPrintable(typeid(lang::Whitespaces ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<lang::Whitespaces >(any)); });
397 #endif
398
399 #if ALIB_VARIABLES
400 RegisterPrintable(typeid(const variables::Variable*), [](const std::any& any, std::string& s) {
401 auto* o= std::any_cast<const variables::Variable*>(any);
402 String256 serialize;
403 o->Name(serialize);
404 ALIB_STRINGS_TO_NARROW(serialize, ns, 256)
405 s+= ns;
406 });
407 RegisterPrintable(typeid(variables::Variable*), [](const std::any& any, std::string& s) {
408 auto* o= std::any_cast<variables::Variable*>(any);
409 String256 serialize;
410 o->Name(serialize);
411 ALIB_STRINGS_TO_NARROW(serialize, ns, 256)
412 s+= ns;
413 });
414 RegisterPrintable(typeid(variables::Variable), [](const std::any& any, std::string& s) {
415 auto o= std::any_cast<variables::Variable>(any);
416 String256 serialize;
417 o.Name(serialize);
418 ALIB_STRINGS_TO_NARROW(serialize, ns, 256)
419 s+= ns;
420 });
421 RegisterPrintable(typeid(variables::Priority), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<variables::Priority>(any)); });
422 #endif
423 #if ALIB_SYSTEM
424 RegisterPrintable(typeid(system::Path ), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<system::Path >(any)); });
425 # if ALIB_CAMP
426 RegisterPrintable(typeid(system::SystemErrors), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<system::SystemErrors>(any)); });
427 # endif
428 #endif
429 #if ALIB_THREADMODEL && ALIB_ENUMRECORDS
430 RegisterPrintable(typeid(threadmodel::Priority), [](const std::any& any, std::string& s) { s+= NString256(std::any_cast<threadmodel::Priority>(any)); });
431 #endif
432
433 }
434
435 void printRegisteredAny(const std::any& any, const CallerInfo& ci) {
436 if (!any.has_value())
437 return;
438 auto it = registeredAnys.find(std::type_index(any.type()));
439 if (it != registeredAnys.end()) {
440 // Call the associated function
441 it->second(any, outBuffer);
442 } else {
443 std::cerr << "Internal Error using alib::assert::Assert(): No converter registered for type: <"
444 << lang::DbgTypeDemangler( any.type() ).Get()
445 << '>' << std::endl
446 << "at " << ci.File << ':' << ci.Line << std::endl;
447 assert(false);
448 }
449 }
450
451 const char* resolveMessageType(int msgType) {
452 if (msgType == 0) return "error";
453 if (msgType == 1) return "warning";
454 return "message";
455 }
456
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 ) {
460 // Start with the global format string
461 std::string_view format = FORMAT;
462
463 // Loop and process the format string
464 size_t start = 0;
465 while (start < format.size()) {
466 // Find the next placeholder starting from 'start'
467 size_t openBrace = format.find('{', start);
468 if (openBrace == std::string_view::npos) {
469 // No more placeholders, print the remaining part
470 os << format.substr(start);
471 break;
472 }
473
474 // Print everything before the '{'
475 os << format.substr(start, openBrace - start);
476
477 // Find the closing '}'
478 size_t closeBrace = format.find('}', openBrace + 1);
479 if (closeBrace == std::string_view::npos) {
480 // Invalid placeholder syntax (no closing '}'), just print raw text
481 os << format.substr(openBrace);
482 break;
483 }
484
485 // Extract the placeholder name
486 std::string_view placeholder = format.substr(openBrace + 1, closeBrace - openBrace - 1);
487
488 // Substitute the placeholder with the corresponding value
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 << "}"; // unknown placeholder
495
496 // Move past the closing '}'
497 start = closeBrace + 1;
498 }
499 os << std::endl;
500 } // writeMessage
501
502 class RecursionBlocker {
503 private:
504 static inline std::atomic<bool> isRecursing{false};
505 bool wasBlocked;
506
507 public:
508 RecursionBlocker() noexcept {
509 wasBlocked = isRecursing.exchange(true);
510 }
511
512 ~RecursionBlocker() {
513 if (!wasBlocked) {
514 isRecursing = false;
515 }
516 }
517
518 [[nodiscard]] bool blocked() const noexcept {
519 return wasBlocked;
520 }
521
522 // Delete copy operations to ensure RAII semantics
523 RecursionBlocker(const RecursionBlocker&) = delete;
524 RecursionBlocker& operator=(const RecursionBlocker&) = delete;
525 };
526
527#if ALIB_DEBUG_ASSERTION_PRINTABLES
528 struct Key { const char* str; // Pointer to the file name
529 int value; // Line number
530 bool operator==(const Key& other) const {
531 return str == other.str && value == other.value;
532 }};
533
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);
536 }};
537
538 std::unordered_set<Key, KeyHash> seenSourceLocations;
539#endif // ALIB_DEBUG_ASSERTION_PRINTABLES
540
541} // namespace [anonymous]
542
543void RegisterPrintable(std::type_index typeIndex, AnyConversionFunc func) {
544 registeredAnys[typeIndex] = func;
545}
546
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." )
549 void CheckArgsImpl( const CallerInfo& ci, const std::span<std::any>& args ) {
550 if ( !alib::NonCampModulesInitialized ) return;
551 if( !isInitialized ) initializeDefaultPrintables();
552
553 if (!seenSourceLocations.insert(Key{ci.File, ci.Line}).second)
554 return;
555
556
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()
562 << '>' << std::endl
563 << " at: " << ci.File << ':' << ci.Line << std::endl;
564 assert(false);
565 }}
566
567 raise(ci, -1, "ASSERTTEST", args );
568 }
569#endif
570
571#endif // !DOXYGEN
572
573TLD& GetHaltFlagAndCounters() { return HALT_FLAGS_AND_COUNTERS; }
574
575void raise( const CallerInfo& ci, int type, std::string_view domain,
576 const std::span<std::any>& args ) {
577
578 // lock parallel assertions if necessary
580 RecursionBlocker blocker;
581 if (blocker.blocked())
582 return;
583
584 // register printable types (once)
585 if( !isInitialized )
586 initializeDefaultPrintables();
587
588 // assemble message
589 outBuffer.clear();
590
591 // With ALox replacing this method (the usual thing), the first string might auto-detected
592 // as an ALox domain name. To keep this consistent, we do a similar effort here.
593 {
594 for( nchar c : domain ) {
595 if (! ( isdigit( c )
596 || ( c >= 'A' && c <= 'Z' )
597 || c == '-' || c == '_' || c == '/' || c == '.' ) ) {
598 std::cerr << "Illegal alib::assert::Assert() domain given: " << domain << std::endl;
599 assert(false);
600 }}}
601
602 size_t i = 0; // Index to track the current argument
603 while (i < args.size()) {
604 const std::any& arg = args[i];
605
606 if ( arg.type() == typeid(const char*)
607 || arg.type() == typeid(std::string)
608 || arg.type() == typeid(std::string_view) ) {
609
610 std::string_view str;
611
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;
616
617
618 // Lambda function to parse and print the format string
619 auto handle_format_string = [&]() {
620 size_t pos = 0; // Position to find "{}"
621 while ((pos = str.find("{}")) != std::string::npos) {
622 // Print the portion before the placeholder
623 outBuffer+= str.substr(0, pos);
624
625 // Move to the next argument for substitution
626 if (++i >= args.size())
627 {
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;
631 assert(false);
632 return;
633 }
634
635 // Print the argument substituted in place of "{}"
636 const std::any& placeholderArg = args[i];
637 printRegisteredAny(placeholderArg, ci);
638
639 // Remove the processed portion of the string
640 str = str.substr(pos + 2);
641 }
642
643 // Print the remaining part of the string (after all `{}` are replaced)
644 outBuffer+= str;
645
646 // End the lambda function
647 };
648
649 // Process the format string with the lambda
650 handle_format_string();
651 } else
652 printRegisteredAny(arg, ci);
653
654 ++i;
655 }
656
657 // if plugin hook, use it.
658 if( PLUGIN && type!= -1 ) // -1 = CheckArgs
659 PLUGIN( ci, type, domain, outBuffer.c_str() );
660
661 // Print the formatted message to the console.
662 else {
663 // check if io-streams is already locked by us. We can do this, because this is anyhow
664 // debug-code. This way, we avoid recursive locking.
665 // (If locked by somebody else, we do not care and still write to the ostream!)
666 #if !ALIB_SINGLE_THREADED
667 bool lockingIoStreams= !threads::STD_IOSTREAMS_LOCK.Dbg.IsOwnedByCurrentThread();
668 if( lockingIoStreams )
670 #endif
671
672 writeMessage( type == 0 ? *STREAM_ERRORS
673 : type == 1 ? *STREAM_WARNINGS
675 type, domain, ci.File, ci.Line, outBuffer);
676 #if !ALIB_SINGLE_THREADED
677 if( lockingIoStreams )
679 #endif
680 }
681
682 // Halt?
683 bool halt;
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 )
688 if( halt )
689 {
690 #if ALIB_CAMP
691 if ( BASECAMP.IsDebuggerPresent() )
692 DebugBreak();
693 else
694 #endif
695 assert( false );
696 }
697 #else
698 #if defined(__GNUC__) || defined(__clang__)
699 if (halt) __builtin_trap();
700 #elif defined ( _MSC_VER )
701 if (halt) __debugbreak();
702 #else
703 (void) halt; // for release compiles with ALIB_DEBUG set
704 assert( !halt );
705 #endif
706
707 #endif
708}
709}// namespace [alib::assert]
710
711# include "ALib.Lang.CIMethods.H"
712#endif // ALIB_DEBUG
713
714
715
716
717
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:329
#define ALIB_CALLER
Definition alib.inl:1001
#define ALIB_WARNINGS_RESTORE
Definition alib.inl:705
#define ALIB_STRINGS_TO_NARROW( src, dest, bufSize)
#define ALIB_ERROR(domain,...)
Definition alib.inl:1045
#define ALIB_LOCK_RECURSIVE_WITH(lock)
Definition alib.inl:1323
#define ALIB_WARNINGS_IGNORE_DEPRECATED
Definition alib.inl:651
This namespace exposes entities of module ALib Assert.
Definition assert.cpp:105
std::string_view FORMAT
Definition assert.cpp:175
std::ostream * STREAM_WARNINGS
Definition assert.cpp:177
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:176
ALIB_DLL void CheckArgsImpl(const CallerInfo &ci, const std::span< std::any > &args)
TLD & GetHaltFlagAndCounters()
Definition assert.cpp:573
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:575
std::ostream * STREAM_MESSAGES
Definition assert.cpp:178
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.
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:49
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:171
ALIB_DLL Lock STD_IOSTREAMS_LOCK
Definition locks.cpp:44
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:401
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:2396
characters::wchar wchar
Type alias in namespace alib.
strings::TString< nchar > NString
Type alias in namespace alib.
Definition string.inl:2390
strings::TAString< nchar, lang::HeapAllocator > NAString
Type alias in namespace alib.
strings::TCString< xchar > XCString
Type alias in namespace alib.
Definition cstring.inl:518
threads::Thread Thread
Type alias in namespace alib.
Definition thread.inl:389
strings::TString< wchar > WString
Type alias in namespace alib.
Definition string.inl:2393
strings::TCString< wchar > WCString
Type alias in namespace alib.
Definition cstring.inl:515
strings::TCString< nchar > NCString
Type alias in namespace alib.
Definition cstring.inl:512
characters::nchar nchar
Type alias in namespace alib.
boxing::Enum Enum
Type alias in namespace alib.
Definition enum.inl:211
boxing::Box Box
Type alias in namespace alib.
Definition box.inl:1216
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.