1
0
forked from Alepha/Alepha
Files
Alepha/error.h

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;
}