forked from Alepha/Alepha
69 lines
2.4 KiB
C++
69 lines
2.4 KiB
C++
static_assert( __cplusplus > 2020'99 );
|
|
|
|
#pragma once
|
|
|
|
#include <Alepha/Alepha.h>
|
|
|
|
#include <iostream>
|
|
#include <mutex>
|
|
|
|
namespace Alepha::Hydrogen ::detail:: error_m
|
|
{
|
|
inline namespace exports {}
|
|
|
|
struct SecretMutex : std::recursive_mutex {};
|
|
|
|
namespace exports
|
|
{
|
|
/*!
|
|
* Returns a locked reference to the global debug error stream.
|
|
*
|
|
* The stream returned by this function may not be self-flushing, so `std::endl` should be
|
|
* used at the end of debug-printing lines. This function causes (through some C++ magic)
|
|
* a global mutex lock to be held for the duration of the "line" wherein it is executed.
|
|
* This lock prevents multiple debug streams from interlacing with each other, when
|
|
* streaming various data together. For instance:
|
|
*
|
|
* ```
|
|
* Alepha::error() << "The number of calls was: " << count << std::endl;
|
|
* ```
|
|
*
|
|
* Under normal circumstances, `std::cerr` (or other streams) could cause interlacing of
|
|
* output among threads to show up between the string and the `count` value being printed.
|
|
* The lock held (until the semicolon) means that such print lines will appear atomically,
|
|
* in output. This can help in reading debug messages in threaded programs.
|
|
*
|
|
* @note The lock parameter should NOT ever be passed by the caller. Instead, AAAA
|
|
* (ADAM's Anonymous Argument Allocation) is responsible for taking the lock.
|
|
*
|
|
* @note The resulting stream is just a normal `std::ostream`, the lock is only held for
|
|
* the duration of the temporary constructed in this call. Capturing that stream to a
|
|
* local named variable is going to cause the lock to be released. While this is not
|
|
* a fatal problem, it can result in torn error lines, once again.
|
|
*/
|
|
template< typename ... Args >
|
|
std::ostream &error( Args..., const std::lock_guard< SecretMutex > & );
|
|
|
|
// Not threadsafe. Set in or before main, before starting any threads.
|
|
void setErrorStream( std::ostream &os );
|
|
}
|
|
|
|
inline SecretMutex access;
|
|
|
|
// The default is `std::cerr`, but any `std::ostream` will do.
|
|
inline std::ostream *errorStream= &std::cerr;
|
|
|
|
template< typename ... Args >
|
|
requires( sizeof...( Args ) == 0 )
|
|
inline std::ostream &
|
|
exports::error( Args..., const std::lock_guard< SecretMutex > & = std::lock_guard{ access } )
|
|
{
|
|
return *errorStream;
|
|
}
|
|
}
|
|
|
|
namespace Alepha::Hydrogen::inline exports::inline error_m
|
|
{
|
|
using namespace detail::error_m::exports;
|
|
}
|