Compare commits
4 Commits
8ada521aa2
...
008283e1f8
| Author | SHA1 | Date | |
|---|---|---|---|
| 008283e1f8 | |||
| 7d993fbc3d | |||
| 39cbd6d096 | |||
| 4ee117cdb7 |
+1
-1
@@ -52,7 +52,7 @@ foreach(src ${SEALLIB_SOURCES})
|
|||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
if (SEALLIB_HAS_SOURCES)
|
if (SEALLIB_HAS_SOURCES)
|
||||||
SEALLIB_HAS_SOURCES(seallib STATIC ${SEALLIB_SOURCES})
|
add_library(seallib STATIC ${SEALLIB_SOURCES})
|
||||||
else()
|
else()
|
||||||
add_library(seallib INTERFACE)
|
add_library(seallib INTERFACE)
|
||||||
target_sources(seallib INTERFACE ${SEALLIB_SOURCES})
|
target_sources(seallib INTERFACE ${SEALLIB_SOURCES})
|
||||||
|
|||||||
@@ -77,6 +77,8 @@ Toggle features by setting these variables to ``ON`` or ``OFF`` in your CMake co
|
|||||||
### 1. Logging
|
### 1. Logging
|
||||||
The Log module uses a Sink architecture. You create a Logger, attach an ILogSink, and log messages using std::format syntax.
|
The Log module uses a Sink architecture. You create a Logger, attach an ILogSink, and log messages using std::format syntax.
|
||||||
|
|
||||||
|
|
||||||
|
#### Example
|
||||||
```C++
|
```C++
|
||||||
#include <seallib/log.h>
|
#include <seallib/log.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@@ -104,11 +106,54 @@ int main() {
|
|||||||
```
|
```
|
||||||
|
|
||||||
### 2. Assert
|
### 2. Assert
|
||||||
(Documentation pending implementation)
|
The assert module provides diagnostic macros made to trap critical logic failures.
|
||||||
|
|
||||||
|
#### Macros and their behavior
|
||||||
|
| Macro | Debug Mode (`_DEBUG`) | Release Mode |
|
||||||
|
| :--- | :--- | :--- |
|
||||||
|
| `ASSERT(cond, msg)` | Evaluates `cond`. If `false`, logs the error location, pops up an interactive modal error box, drops a debugger breakpoint trap, and calls `std::exit`. | Evaluates to a compiler optimization hint informing the optimizer that `cond` is always `true`. |
|
||||||
|
| `PANIC(msg)` | Logs the error, displays an interactive modal error box, breaks execution, and terminates. | Logs the error, displays an interactive modal error box, breaks execution, and terminates. **Always halts execution.** |
|
||||||
|
#### Example
|
||||||
|
```c++
|
||||||
|
#include <seallib/assert.h>
|
||||||
|
|
||||||
|
void processSystemData(void* dataPtr, int size) {
|
||||||
|
// 1. Defensively check states that should literally be impossible in a valid run
|
||||||
|
ASSERT(dataPtr != nullptr, "Managed data pointer cannot be null during processing pipe");
|
||||||
|
|
||||||
|
// 2. Asserts behave as optimizer hints in Release mode.
|
||||||
|
// The compiler now optimizes this function knowing 'size' can never be less than zero.
|
||||||
|
ASSERT(size >= 0, "Buffer stream size constraint violation");
|
||||||
|
|
||||||
|
if (size == 0) {
|
||||||
|
return; // Valid empty state
|
||||||
|
}
|
||||||
|
|
||||||
|
// Processing logic...
|
||||||
|
}
|
||||||
|
|
||||||
|
void processNetworkPacket(int packetId) {
|
||||||
|
switch (packetId) {
|
||||||
|
case 1: /* Handle read */ break;
|
||||||
|
case 2: /* Handle write */ break;
|
||||||
|
default:
|
||||||
|
// 3. Use PANIC for unrecoverable structural states that must crash
|
||||||
|
// the software immediately in both Debug and Release builds.
|
||||||
|
PANIC("Critical Error: Received completely unhandled or corrupted packet opcode");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
// Fails in debug: triggers a modal error window detailing the file and line number
|
||||||
|
processSystemData(nullptr, -1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
### 3. Events
|
### 3. Events
|
||||||
The Events module provides a thread and type safe signal/slot mechanism. It allows you to define custom events with any number of parameters and subscribe to them using callbacks.
|
The Events module provides a thread and type safe signal/slot mechanism. It allows you to define custom events with any number of parameters and subscribe to them using callbacks.
|
||||||
#### Basic Usage
|
#### Example
|
||||||
```cpp
|
```cpp
|
||||||
#include <seallib/event.h>
|
#include <seallib/event.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@@ -146,6 +191,8 @@ The VFS (Virtual File System) module provides a unified interface for file opera
|
|||||||
|
|
||||||
#### Implementing a file provider
|
#### Implementing a file provider
|
||||||
To create a new storage backend (e.g., a zip loader, encrypted volume, etc), you must inherit from `IFileProvider`.
|
To create a new storage backend (e.g., a zip loader, encrypted volume, etc), you must inherit from `IFileProvider`.
|
||||||
|
|
||||||
|
#### Example provider implementation
|
||||||
```cpp
|
```cpp
|
||||||
#include <seallib/vfs.h>
|
#include <seallib/vfs.h>
|
||||||
|
|
||||||
@@ -196,7 +243,7 @@ public:
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Example usage
|
#### Example provider usage
|
||||||
```c++
|
```c++
|
||||||
#include <seallib/vfs.h>
|
#include <seallib/vfs.h>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
#include "assert.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
// from: WinUser.h
|
||||||
|
#ifndef MB_ICONHAND
|
||||||
|
#define MB_ICONHAND 0x00000010L
|
||||||
|
#define MB_ICONERROR MB_ICONHAND
|
||||||
|
|
||||||
|
#define MB_SYSTEMMODAL 0x00001000L
|
||||||
|
|
||||||
|
#define MB_OK 0x00000000L
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
__declspec(dllimport) void* __stdcall GetModuleHandleA(const char* lpModuleName);
|
||||||
|
__declspec(dllimport) void* __stdcall LoadLibraryA(const char* lpLibFileName);
|
||||||
|
__declspec(dllimport) int(__stdcall* __stdcall GetProcAddress(void* hModule, const char* lpProcName))();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __linux
|
||||||
|
#include <cstdlib>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::string safeShellEscape(const std::string& input)
|
||||||
|
{
|
||||||
|
std::string escaped;
|
||||||
|
for (char c : input)
|
||||||
|
{
|
||||||
|
if (c == '"' || c == '\\' || c == '`' || c == '$') escaped += '\\';
|
||||||
|
escaped += c;
|
||||||
|
}
|
||||||
|
return escaped;
|
||||||
|
}
|
||||||
|
|
||||||
|
void seallib::displayError(const char* msg, const char* file, int line)
|
||||||
|
{
|
||||||
|
std::string fullError = std::string(msg) + "\n\nFile: " + file + "\nLine: " + std::to_string(line);
|
||||||
|
std::cerr << "[FATAL ERROR] " << fullError << std::endl;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
typedef int(__stdcall * fnMessageBoxA)(void*, const char*, const char*, unsigned int);
|
||||||
|
if (void* hUser32 = GetModuleHandleA("user32.dll") ? GetModuleHandleA("user32.dll") : LoadLibraryA("user32.dll"))
|
||||||
|
{
|
||||||
|
auto msgBoxA = reinterpret_cast<fnMessageBoxA>(GetProcAddress(hUser32, "MessageBoxA"));
|
||||||
|
if (msgBoxA) msgBoxA(nullptr, fullError.c_str(), "Fatal Error Occurred", MB_ICONERROR | MB_OK | MB_SYSTEMMODAL);
|
||||||
|
}
|
||||||
|
#elif __linux__
|
||||||
|
std::string safeMsg = safeShellEscape(fullError);
|
||||||
|
if (std::system("which zenity > /dev/null 2>&1") == 0)
|
||||||
|
std::system(("zenity --error --text=\"" + safeMsg + "\" --title=\"Fatal Error\" 2>/dev/null").c_str());
|
||||||
|
else if (std::system("which kdialog > /dev/null 2>&1") == 0)
|
||||||
|
std::system(("kdialog --error \"" + safeMsg + "\" 2>/dev/null").c_str());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#define SEALLIB_DEBUGBREAK() __debugbreak()
|
||||||
|
#define SEALLIB_ASSUME(cond) __assume(cond)
|
||||||
|
#elif defined(__GNUC__) || defined(__clang__)
|
||||||
|
#define SEALLIB_DEBUGBREAK() __builtin_trap()
|
||||||
|
#define SEALLIB_ASSUME(cond) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
if (!(cond)) __builtin_unreachable(); \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
#define SEALLIB_DEBUGBREAK() \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
} while (0)
|
||||||
|
#define SEALLIB_ASSUME(cond) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
#define ASSERT(cond, msg) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
if (!(cond)) \
|
||||||
|
{ \
|
||||||
|
seallib::displayError(msg, __FILE__, __LINE__); \
|
||||||
|
SEALLIB_DEBUGBREAK(); \
|
||||||
|
std::exit(EXIT_FAILURE); \
|
||||||
|
} \
|
||||||
|
SEALLIB_ASSUME(cond); \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
#define ASSERT(cond, msg) SEALLIB_ASSUME(cond)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define PANIC(msg) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
seallib::displayError(msg, __FILE__, __LINE__); \
|
||||||
|
SEALLIB_DEBUGBREAK(); \
|
||||||
|
std::exit(EXIT_FAILURE); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
namespace seallib
|
||||||
|
{
|
||||||
|
void displayError(const char* msg, const char* file, int line);
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
#include "tests.h"
|
||||||
|
|
||||||
|
#include <seallib/assert.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
commented out for obvious reasons
|
||||||
|
*/
|
||||||
|
#if 0
|
||||||
|
|
||||||
|
class AssertTest : ITest
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AssertTest() : ITest() {};
|
||||||
|
|
||||||
|
virtual void run() override
|
||||||
|
{
|
||||||
|
int a = 2;
|
||||||
|
int b = 5;
|
||||||
|
|
||||||
|
logInfo("trying true assertions");
|
||||||
|
ASSERT(a * b == 10, "Invalid assertion");
|
||||||
|
ASSERT(true, "Invalid assertion");
|
||||||
|
|
||||||
|
logInfo("trying false assertion");
|
||||||
|
ASSERT(false, "Valid assertion");
|
||||||
|
ASSERT(a * b == a, "Valid assertion");
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual const char* getName() override { return "Assertion test"; }
|
||||||
|
};
|
||||||
|
|
||||||
|
static AssertTest g_assertTest;
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user