Major overhaul of DebugPrint

This commit is contained in:
2023-09-04 03:21:23 -04:00
parent 57ea8d8574
commit e3c20b3f1e
6 changed files with 262 additions and 53 deletions

View File

@@ -1,37 +1,150 @@
#include "CoreMinimal.h"
#include "engineutil.hpp"
namespace engineutil {
using DPrintCallback = DebugPrintControl::DPrintCallback;
//////////////////////////////////////////////////////////////
//
// DPrintState
//
// The global state of the DPrint routine. There is only
// ever one of these, and it is owned by DPrintAccess below.
//
//////////////////////////////////////////////////////////////
struct DPrintState {
// True if buffering is enabled.
bool Collect;
// The array of buffered messages.
TArray<FString> Messages;
// The array of callback functions.
TArray<DPrintCallback> Callbacks;
};
//////////////////////////////////////////////////////////////
//
// DPrintAccess
//
// This class grants you safe access to the global state
// of the DPrint routine. Constructing an object of
// class DPrintAccess will lock the global mutex and make
// sure that the DPrintState is initialized. Then it will
// give you unrestricted access to the DPrintState through
// operator right arrow.
//
//////////////////////////////////////////////////////////////
class DPrintAccess {
private:
// The Mutex that protects the global state.
static FCriticalSection Mutex;
// The Global State. A pointer, to avoid static init issues.
static DPrintState* State;
public:
// Constructor. Locks mutex and initializes state if necessary.
DPrintAccess() {
Mutex.Lock();
if (State == nullptr) {
State = new DPrintState;
State->Collect = false;
}
}
// Destructor. Releases mutex.
~DPrintAccess() {
Mutex.Unlock();
}
// Access the DPrintState.
DPrintState* operator ->() {
return State;
}
};
FCriticalSection DPrintAccess::Mutex;
DPrintState* DPrintAccess::State;
// The DPrint array. This stores the dprints
// until they can be collected by the console implementation.
static TArray<FString> dprint_array;
static FCriticalSection dprint_mutex;
//////////////////////////////////////////////////////////////
//
// Namespace DebugPrint.
//
// This contains all the various versions of the DPrint routine.
//
//////////////////////////////////////////////////////////////
void DPrint(const FString& fs) {
FScopeLock lk(&dprint_mutex);
dprint_array.Emplace(fs);
}
namespace DebugPrint {
void DPrint(const char* msg) {
FScopeLock lk(&dprint_mutex);
dprint_array.Emplace(msg);
}
// DPrint. Invoke all the callbacks, and store the message.
void DPrint(const FString& fs) {
DPrintAccess state;
for (DPrintCallback cb : state->Callbacks) {
cb(fs);
}
if (state->Collect) {
state->Messages.Emplace(fs);
}
}
void DPrintHook(const char* msg, size_t len) {
FScopeLock lk(&dprint_mutex);
dprint_array.Emplace(len, (const UTF8CHAR*)msg);
}
// Alternative interface to the dispatcher.
void DPrint(const char* msg) {
DPrint(FString(msg));
}
TArray<FString> DPrintGetStored() {
FScopeLock lk(&dprint_mutex);
TArray<FString> result = std::move(dprint_array);
dprint_array.Empty();
return result;
}
// Alternative interface to the dispatcher.
void DPrint(const char* msg, size_t len) {
DPrint(FString(len, (const UTF8CHAR*)msg));
}
void ConsoleOutput::Append(const FString& text) {
} // namespace DebugPrint
//////////////////////////////////////////////////////////////
//
// Namespace DebugPrintControl.
//
// Configuration and control for the DPrint routine.
//
//////////////////////////////////////////////////////////////
namespace DebugPrintControl {
// Register a callback. Check for duplication.
void RegisterCallback(DPrintCallback cb) {
DPrintAccess state;
for (DPrintCallback old : state->Callbacks) {
if (cb == old) return;
}
state->Callbacks.Add(cb);
}
// Set the collection bit in the global state.
void EnableCollection() {
DPrintAccess state;
state->Collect = true;
}
// Get the array of collected messages, if any.
TArray<FString> GetStored() {
DPrintAccess state;
TArray<FString> result = std::move(state->Messages);
state->Messages.Empty();
return result;
}
};
//////////////////////////////////////////////////////////////
//
// ConsoleOutput
//
// Storing the text that goes in the unreal console.
//
//////////////////////////////////////////////////////////////
void FConsoleOutput::Append(const FString& text) {
if (!text.IsEmpty()) {
Content += text;
Truncate();
@@ -39,7 +152,7 @@ void ConsoleOutput::Append(const FString& text) {
}
}
void ConsoleOutput::AppendLine(const FString& text) {
void FConsoleOutput::AppendLine(const FString& text) {
int csize = Content.Len();
if ((csize > 0) && (Content[csize - 1] != '\n')) {
Content += TEXT("\n");
@@ -50,7 +163,7 @@ void ConsoleOutput::AppendLine(const FString& text) {
Dirty = true;
}
void ConsoleOutput::Truncate() {
void FConsoleOutput::Truncate() {
int lines = 50;
int csize = Content.Len();
int total = 0;
@@ -65,5 +178,3 @@ void ConsoleOutput::Truncate() {
}
}
} // namespace engineutil