10 using namespace std::chrono_literals;
14 constexpr
int NumTries = 2;
17 return std::unique_lock<MutexType>(
LockMutex);
20 std::unique_lock<MutexType> lock(
LockMutex, std::defer_lock);
22 for (
auto i = NumTries; i > 0; --i)
23 if (lock.try_lock_for(
Timeout / NumTries))
35 while (!MutexCanBeDestroyed)
36 std::this_thread::yield();
41 bool TimeoutOccurred =
false;
44 std::unique_lock<decltype(Mutex)> Lock(Mutex);
48 "There is already a waiting thread. Only one thread can await this notifier.");
49 SomeoneIsWaiting =
true;
50 MutexCanBeDestroyed =
false;
53 TimeoutOccurred = !ConditionVariable.wait_for(Lock,
Timeout, [
this]() {
return EventOccurred; });
55 ConditionVariable.wait(Lock, [
this]() {
return EventOccurred; });
58 EventOccurred =
false;
59 SomeoneIsWaiting =
false;
64 MutexCanBeDestroyed =
true;
66 return TimeoutOccurred;
72 std::unique_lock<decltype(Mutex)> Lock(Mutex);
76 ConditionVariable.notify_one();
81 std::unique_lock<decltype(Mutex)> Lock(Mutex);
82 EventOccurred =
false;
86 : DataSize(Other.DataSize)
96 : DataPtr(std::move(Other.DataPtr)), DataSize(Other.DataSize)
112 DataPtr = std::move(Other.DataPtr);
152 return std::strong_ordering::equal;
157 return std::strong_ordering::greater;
159 return std::strong_ordering::less;
166 static const std::regex VersionRegex(
"(\\d+)\\.(\\d+)(?:\\.(\\d+))?");
168 std::regex_search(Str.data(), Results, VersionRegex);
169 if (Results.length() <= 1 || Results.length() > 5)
173 for (
size_t i = 1; i < Results.size(); ++i)
175 if (!Results[i].matched)
180 case 1: Version.
Major = Util::StrToT<decltype(VersionType::Major)>(Results[i].str());
break;
181 case 2: Version.
Minor = Util::StrToT<decltype(VersionType::Minor)>(Results[i].str());
break;
182 case 3: Version.
Patch = Util::StrToT<decltype(VersionType::Patch)>(Results[i].str());
196 std::rethrow_exception(ExceptionPtr);
198 catch (
const std::exception& e)
204 return "Unknown exception.";
210 std::string LowerStr;
211 LowerStr.resize(Str.size());
213 std::transform(Str.cbegin(), Str.cend(), LowerStr.begin(),
214 [](
unsigned char c) { return std::tolower(c); }
220 std::vector<std::complex<double>>
FFT(
const std::vector<std::complex<double>>& Data,
bool InverseTransform)
222 if (Data.size() > std::numeric_limits<size_t>::max() / 2)
223 throw OverflowException(
"Size of Data vector must not exceed half the capacity of size_t.");
225 std::vector<double> RawData;
226 RawData.resize(2 * Data.size());
227 for (
size_t i = 0; i < Data.size(); ++i)
229 RawData[2 * i] = Data[i].real();
230 RawData[2 * i + 1] = Data[i].imag();
233 gsl_fft_complex_workspace* Workspace = gsl_fft_complex_workspace_alloc(Data.size());
234 gsl_fft_complex_wavetable* Wavetable = gsl_fft_complex_wavetable_alloc(Data.size());
238 if (!Workspace || !Wavetable)
241 if (gsl_fft_complex_transform(RawData.data(), 1, Data.size(), Wavetable, Workspace,
242 InverseTransform ? gsl_fft_direction::gsl_fft_backward : gsl_fft_direction::gsl_fft_forward))
245 gsl_fft_complex_wavetable_free(Wavetable);
246 gsl_fft_complex_workspace_free(Workspace);
248 std::vector<std::complex<double>> Result;
249 Result.resize(Data.size());
250 for (
size_t i = 0; i < Result.size(); ++i)
251 Result[i] = { RawData[2 * i], RawData[2 * i + 1] };
258 gsl_fft_complex_wavetable_free(Wavetable);
260 gsl_fft_complex_workspace_free(Workspace);
268 auto other_lock = Other.AcquireLock();
270 Data.swap(Other.Data);
277 Data = std::make_unique<WarningData>();
291 auto lock = AcquireLock();
293 Data.swap(Other.Data);
306 LogFile.exceptions(std::ofstream::failbit | std::ofstream::badbit);
310 const size_t Line,
const std::string& Function,
const std::string& File,
const int ErrorCode
312 ,
const std::stacktrace& Trace
320 auto lock = AcquireLock(LogOperationTimeout);
322 LogEntry Entry(FormatLog(Message, Line, Function, Filename, ErrorCode,
false), Type, std::chrono::system_clock::now());
323 LogEntries.emplace_back(std::move(Entry));
328 LogFile << FormatLogHTML(Message, Type, Line, Function, Filename, ErrorCode
344 Log(E.what(), E.Type, E.Line, E.Function, E.File, E.ErrorCode
357 Log(Data.Description,
ErrorType::Warning, Data.Line, Data.Function, Data.File, Data.ErrorCode);
366 const std::string& Function,
const std::string& Filename,
const int ErrorCode,
const bool PrefixMessage)
368 std::stringstream stream;
370 if (!
Filename.empty() || !Function.empty())
375 stream <<
Filename << ((!Line && !Function.empty()) ?
" " :
"");
377 stream <<
":" <<
ToStr(Line) << (!Function.empty() ?
" " :
"");
379 if (!Function.empty())
380 stream <<
"in " << Function <<
"()";
381 stream <<
")" << (PrefixMessage ?
"" :
": ");
383 stream << (PrefixMessage ?
": " :
"") << Message;
385 stream <<
" (Code " <<
ToStr(ErrorCode) <<
")";
391 const size_t Line,
const std::string& Function,
const std::string& Filename,
const int ErrorCode
393 ,
const std::stacktrace& Trace
400 std::stringstream stream;
403 #ifdef DYNEXP_HAS_STACKTRACE
406 "<div class=\"entry_no_details\">"
407 #ifdef DYNEXP_HAS_STACKTRACE
408 :
"<details><summary class=\"entry_details\">")
411 <<
"<span class=\"entry_label\"><span class=\"label\" style=\"color:" << ColorString <<
"\">" << Label <<
"</span></span>"
412 <<
"<span class=\"entry_text\">";
413 if (!
Filename.empty() || !Function.empty())
415 stream <<
"<span class=\"origin\">(";
420 stream <<
":" << Line << (!Function.empty() ?
" " :
"");
422 if (!Function.empty())
423 stream <<
"in " << QString::fromStdString(Function).toHtmlEscaped().toStdString();
424 stream <<
")</span><br>";
426 stream <<
"<span class=\"msg\">" << QString::fromStdString(Message).toHtmlEscaped().toStdString() <<
"</span>";
428 stream <<
" <span class=\"errno\">(Code " << ErrorCode <<
")</span>";
429 stream <<
"\n</span>";
431 #ifdef DYNEXP_HAS_STACKTRACE
434 stream <<
"\n</summary><div class=\"trace\"><ol>\n";
435 for (
const auto& entry : Trace)
436 stream <<
"<li>" << QString::fromStdString(std::to_string(entry)).toHtmlEscaped().toStdString() <<
"</li>\n";
437 stream <<
"</ol></div></details>";
441 stream <<
"\n</div>";
457 <<
"<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<style>\n"
458 <<
"body {background-color:white; font-family:sans-serif}\n"
459 <<
".version {font-style:italic}\n"
460 <<
".trace {margin-left: 18em}\n"
461 <<
"summary::marker {content:none}\n"
462 <<
"summary::before {content:\"+\"; font-weight:bold; float:left; position:absolute; left:.9em}\n"
463 <<
"details[open] summary::before {content:\"-\"}\n"
464 <<
".entry_no_details {margin-left:1.4em; margin-block:.2em}\n"
465 <<
".entry_details {margin-left:1.4em; list-style-position:outside}\n"
466 <<
".entry_label, .entry_text {display:table-cell; padding-right:1em; vertical-align:top; min-width:6em}\n"
467 <<
".entry_time {display:table-cell; padding-right:1em; vertical-align:top; min-width:10em}\n"
468 <<
"div.entry_no_details:hover, summary.entry_details:hover {background-color:lightgray}\n"
469 <<
".label {font-weight:bold}\n"
470 <<
".origin {font-family:monospace}\n"
471 <<
".errno {font-style:italic}\n"
472 <<
".trace ol {font-family:monospace; margin-block-start:.2em; margin-left:2em}\n"
473 <<
".end {font-style:italic}\n"
474 <<
"</style>\n<title>DynExp Logfile</title>\n</head>\n<body>\n"
475 <<
"<h1>DynExp Logfile</h1>\n"
481 <<
"<div class=\"entries\">";
501 LogFile <<
"\n</div>\n<p class=\"end\">*** Logfile end.</p>\n</body>\n</html>";
Provides general utilities within DynExp's Util namespace.
Data type which manages a binary large object. The reserved memory is freed upon destruction.
void Reserve(size_t Size)
Reserves Size bytes of memory freeing any previously reserved memory.
size_t DataSize
Size of the stored data in bytes.
unsigned char[] DataType
Type of the buffer's data.
DataPtrType::element_type * Release() noexcept
Releases ownership of the stored buffer returning a pointer to it and leaving this instance empty.
DataPtrType DataPtr
Pointer to the buffer.
auto Size() const noexcept
Returns the size of the stored data in bytes.
void Reset()
Frees any reserved memory.
BlobDataType()=default
Constructs an empty object.
void Assign(size_t Size, const DataType Data)
Copies Size bytes from Data to the buffer freeing any previously reserved memory.
BlobDataType & operator=(const BlobDataType &Other)
Copy-assigns data from Other.
Logs events like errors and writes them immediately to a HTML file in a human-readable format....
bool IsOpenUnsafe() const
static constexpr auto LogOperationTimeout
Internal timeout for locking the mutex which synchronizes the calls to member function calls....
void Log(const std::string &Message, const ErrorType Type=ErrorType::Info, const size_t Line=0, const std::string &Function="", const std::string &File="", const int ErrorCode=0, const std::stacktrace &Trace={}) noexcept
Logs an event from information specified manually.
void CloseLogFileUnsafe()
std::ofstream LogFile
Stream object to write to the log file on disk.
std::string Filename
Filename and path to the log file on disk.
static std::string FormatLogHTML(const std::string &Message, const ErrorType Type=ErrorType::Info, const size_t Line=0, const std::string &Function="", const std::string &Filename="", const int ErrorCode=0, const std::stacktrace &Trace={})
Formats a log entry as HTML code to be displayed in a web browser.
EventLogger()
Constructs the event logger without opening a log file on disk. Events are only stored in the interna...
static std::string FormatLog(const std::string &Message, const size_t Line=0, const std::string &Function="", const std::string &Filename="", const int ErrorCode=0, const bool PrefixMessage=true)
Formats a log entry as plain text to be displayed within DynExp.
std::vector< LogEntry > LogEntries
Internally stored log entries.
std::vector< LogEntry > GetLog(size_t FirstElement=0) const
Returns the internal event log starting from the n-th stored element.
void OpenLogFile(std::string Filename)
Opens the HTML log file on disk. If it already exists, the file gets overwritten.
DynExp exceptions are derived from this class. It contains basic information about the cause of the e...
const std::string File
Source code file where the exception occurred.
const size_t Line
Line in source code where the exception occurred.
constexpr const char * GetErrorLabel() const
const std::string Function
Function in source code where the exception occurred
const int ErrorCode
DynExp error code from DynExpErrorCodes::DynExpErrorCodes
constexpr const char * GetErrorLabelColor() const
LockType AcquireLock(const std::chrono::milliseconds Timeout=DefaultTimeout) const
Locks the internal mutex. Blocks until the mutex is locked or until the timeout duration is exceeded.
MutexType LockMutex
Internal mutex used for locking.
Thrown when a function call is not allowed to a specific thread in a multi-threading context.
Data to operate on is invalid for a specific purpose. This indicates a corrupted data structure or fu...
Thrown when some operation or feature is temporarily or permanently not available.
bool Wait(const std::chrono::milliseconds Timeout=std::chrono::milliseconds(0))
Makes current thread wait until it is notified or until given timeout duration is exceeded....
void Notify()
Set notification to stop waiting (sets EventOccurred to true).
void Ignore()
Ignore last notification (sets EventOccurred to false).
Thrown when an argument passed to a function exceeds the valid range.
Thrown when a numeric operation would result in an overflow (e.g. due to incompatible data types)
Thrown when an operation timed out before it could be completed, especially used for locking shared d...
Class to store information about warnings in a thread-safe manner (deriving from ILockable)....
void Reset()
Clears the warning data.
WarningData Get() const
Returns a copy of the warning data.
Warning()
Constructs an empty Warning.
Warning & operator=(const Exception &e)
Retrives the warning data from an exception e derived from Exception.
std::unique_ptr< WarningData > Data
Pointer to warning data. Must never be nullptr.
constexpr auto DynExpVersion
DynExp's version string
DynExp's Util namespace contains commonly used functions and templates as well as extensions to Qt an...
std::string ToStr(const T &Value, int Precision=-1)
Converts a (numeric) value of type T to a std::string using operator<< of std::stringstream.
auto FilenameFromPath(std::string Path)
Extracts the filename from a path.
std::string ExceptionToStr(const std::exception_ptr ExceptionPtr)
Returns the what() information of an exception derived from std::exception and stored in an exception...
auto CurrentTimeAndDateString()
Returns a human-readable string describing the current time and date in the current time zone.
VersionType VersionFromString(std::string_view Str)
Extracts a program version from a string.
EventLogger & EventLog()
This function holds a static EventLogger instance and returns a reference to it. DynExp uses only one...
std::strong_ordering operator<=>(const VersionType &lhs, const VersionType &rhs)
Compares two program version types with each other.
std::vector< std::complex< double > > FFT(const std::vector< std::complex< double >> &Data, bool InverseTransform)
Computes the Fast Fourier Transform (FFT) a vector of complex values.
std::string ToLower(std::string_view Str)
Transforms a string into lower case.
ErrorType
DynExp's error types
Data type describing DynExp's program version in the form Major.Minor.Patch.
Accumulates include statements to provide a precompiled header.
#define DYNEXP_HAS_STACKTRACE
Data type of a single entry in DynExp's log.
Data associated with a warning. The class is convertible to bool (true if it describes an error/warni...