flatten 20260225

This commit is contained in:
Timothy Prepscius
2026-02-25 12:43:06 -05:00
commit 996151a56a
521 changed files with 46722 additions and 0 deletions

42
tjp/core/debug/Allocations.cpp Executable file
View File

@@ -0,0 +1,42 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include "Allocations.h"
#include <sstream>
namespace tjp::core::debug {
void Allocations::onAllocation (const type_index &t)
{
auto l = lock_of(mutex);
allocations[t.name()].count++;
}
void Allocations::onDeallocation (const type_index &t)
{
auto l = lock_of(mutex);
allocations[t.name()].count--;
}
String Allocations::log ()
{
std::ostringstream ss;
for (auto &[id, a]: allocations)
{
if (a.count)
ss << id << ": " << a.count << std::endl;
}
return ss.str();
}
Allocations *Allocations::shared()
{
static Allocations *allocations = new Allocations();
return allocations;
}
} // namespace

58
tjp/core/debug/Allocations.h Executable file
View File

@@ -0,0 +1,58 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "Debug.h"
#include <typeinfo>
#include "../containers/Map.h"
#include "../string/String.h"
#include "../threads/Lock.hpp"
#include "../algorithm/ExecuteOnDestruct.hpp"
#include "../rtti/RTTI.hpp"
namespace tjp::core::debug {
struct Allocations
{
struct Allocation {
int count = 0;
} ;
Mutex mutex;
Map<String, Allocation> allocations;
void onAllocation (const type_index &t);
void onDeallocation (const type_index &t);
String log ();
static Allocations *shared();
} ;
} // namespace
#if defined(_DEBUG)
#define ALLOC_RECORD(x) \
tjp::core::debug::Allocations::shared()->onAllocation(type_id(*x))
#define DEALLOC_RECORD(x) \
tjp::core::debug::Allocations::shared()->onDeallocation(type_id(*x))
#define SCOPE_RECORD(x) \
struct __ALLOC__##x __alloc__ {}; \
ALLOC_RECORD(&__alloc_); \
tjp::core::ExecuteOnDestruct __dealloc__([&]() { DEALLOC_RECORD(&__alloc__)); \
#define ALLOC_LOG() \
sLogRelease("alloc", tjp::core::debug::Allocations::shared()->log())
#else
#define ALLOC_RECORD(x)
#define DEALLOC_RECORD(x)
#define SCOPE_RECORD(x)
#define ALLOC_LOG()
#endif

View File

@@ -0,0 +1,25 @@
// TJP COPYRIGHT HEADER
#pragma once
#include "../system/Debug.h"
#include <typeinfo>
#include "../containers/Map.h"
#include "../string/String.h"
#include "../threads/Lock.hpp"
namespace timprepscius::core::debug {
struct Allocations
{
Mutex mutex;
Map<String, int> allocations;
void onAllocation (const std::type_info &t);
void onDeallocation (const std::type_info &t);
static Allocations *shared();
} ;
} // namespace

View File

@@ -0,0 +1,14 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
template<typename T, unsigned int N>
struct CompileTimeSizeOf_
{
unsigned char operator()() { return N + 256; } //deliberately causing overflow
};
#define COMPILE_TIME_SIZEOF(x) CompileTimeSizeOf_<x, sizeof(x)>()();

34
tjp/core/debug/Debug.h Executable file
View File

@@ -0,0 +1,34 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "../system/Debug.h"
#if defined(_DEBUG) || defined(DEBUG)
#define xDebugLine() { int x = 0; (void)x; }
#define IS_DEBUG() 1
#ifndef _DEBUG
#define _DEBUG
#endif
#ifndef DEBUG
#define DEBUG
#endif
#else
#define xDebugLine() (void)0;
#define IS_DEBUG() 0
#ifndef NDEBUG
#define NDEBUG
#endif
#endif
#if defined(DEBUG)
#define DEBUG_ONLY(...) __VA_ARGS__
#else
#define DEBUG_ONLY(...)
#endif

7
tjp/core/debug/RUN_IF.h Executable file
View File

@@ -0,0 +1,7 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#define RUN_IF(x, ...) if constexpr(x){ __VA_ARGS__; }

23
tjp/core/debug/Stack.h Executable file
View File

@@ -0,0 +1,23 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "../system/Debug.h"
#include "../system/System.h"
#include <string>
namespace tjp::core {
std::string getStackString(int maxStackDepth=32);
} // namespace
#ifdef TJP_CORE_HEADER_ONLY
#ifdef SYS_ANDROID
#include "android/Stack.cpp"
#else
#include "glib/Stack.cpp"
#endif
#endif

99
tjp/core/debug/StackUsage.cpp Executable file
View File

@@ -0,0 +1,99 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include "StackUsage.h"
#include <pthread.h>
#include <iostream>
#include <cstdint>
#include "../system/System.h"
#ifdef SYS_APPLE
#include <mach/mach.h>
#include <mach/thread_info.h>
#include <mach/thread_act.h>
#include <mach/mach_types.h>
#endif
namespace tjp {
namespace core {
#ifndef SYS_ANDROID
#ifdef SYS_APPLE
void *getStackBase ()
{
return pthread_get_stackaddr_np(pthread_self());
/*
uint64_t threadId;
pthread_threadid_np(nullptr, &threadId);
// Get thread info
mach_msg_type_number_t threadInfoCount = THREAD_BASIC_INFO_COUNT;
thread_basic_info_data_t threadInfo;
if (thread_info((thread_act_t)threadId, THREAD_BASIC_INFO, (thread_info_t)&threadInfo, &threadInfoCount) != KERN_SUCCESS) {
return 0;
}
// Get the stack base address
void* stackBase = (void*)threadInfo.stack_base;
return stackBase;
*/
}
#else
void *getStackBase()
{
pthread_attr_t attr;
pthread_getattr_np(pthread_self(), &attr);
// Get the stack base address
void* stackBase = nullptr;
pthread_attr_getstackaddr(&attr, &stackBase);
// Clean up thread attributes
pthread_attr_destroy(&attr);
return stackBase;
}
#endif
std::size_t getStackUsage() {
// Define a local variable
int localVariable;
void* stackBase = getStackBase();
// Calculate the current stack pointer (address of localVariable)
std::uintptr_t currentStackPointer = reinterpret_cast<std::uintptr_t>(&localVariable);
// Calculate the stack usage
std::size_t stackUsage = static_cast<std::size_t>(reinterpret_cast<std::uintptr_t>(stackBase) - currentStackPointer);
return stackUsage;
}
#else
std::size_t getStackUsage() {
pthread_attr_t attr;
pthread_getattr_np(pthread_self(), &attr);
size_t size = 0;
pthread_attr_getstacksize(&attr, &size);
return size;
}
#endif
} // namespace
} // namespace

13
tjp/core/debug/StackUsage.h Executable file
View File

@@ -0,0 +1,13 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include <stddef.h>
namespace tjp::core {
size_t getStackUsage();
} // namespace

View File

@@ -0,0 +1,81 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#ifdef TJP_CORE_HEADER_ONLY
#pragma once
#endif
#include "../../header_only/compile.h"
#include "../Stack.h"
#include "../../system/System.h"
#include <unwind.h>
#include <dlfcn.h>
#include <iomanip>
#include <sstream>
// https://stackoverflow.com/questions/8115192/android-ndk-getting-the-backtrace
struct BacktraceState
{
void** current;
void** end;
};
TJP_CORE_HEADER_ONLY_INLINE
static _Unwind_Reason_Code unwindCallback(struct _Unwind_Context* context, void* arg)
{
BacktraceState* state = static_cast<BacktraceState*>(arg);
uintptr_t pc = _Unwind_GetIP(context);
if (pc) {
if (state->current == state->end) {
return _URC_END_OF_STACK;
} else {
*state->current++ = reinterpret_cast<void*>(pc);
}
}
return _URC_NO_REASON;
}
TJP_CORE_HEADER_ONLY_INLINE
size_t captureBacktrace(void** buffer, size_t max)
{
BacktraceState state = {buffer, buffer + max};
_Unwind_Backtrace(unwindCallback, &state);
return state.current - buffer;
}
TJP_CORE_HEADER_ONLY_INLINE
void dumpBacktrace(std::ostream& os, void** buffer, size_t count)
{
for (size_t idx = 0; idx < count; ++idx) {
const void* addr = buffer[idx];
const char* symbol = "";
Dl_info info;
if (dladdr(addr, &info) && info.dli_sname) {
symbol = info.dli_sname;
}
os << " #" << std::setw(2) << idx << ": " << addr << " " << symbol << "\n";
}
}
namespace tjp::core {
TJP_CORE_HEADER_ONLY_INLINE
std::string getStackString(int maxStackDepth)
{
auto buffer = (void **)alloca(sizeof(void *) * maxStackDepth);
auto count = captureBacktrace(buffer, maxStackDepth);
std::ostringstream oss;
dumpBacktrace(oss, buffer, count);
return oss.str();
}
} // namespace

24
tjp/core/debug/debug_break.h Executable file
View File

@@ -0,0 +1,24 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "../system/Debug.h"
#include "../system/System.h"
namespace tjp::core {
#ifdef _DEBUG
inline void debug_break()
{
#ifdef SYS_APPLE
__asm__("brk #0");
#endif
}
#else
inline void debug_break() {};
#endif
} // namespace

43
tjp/core/debug/glib/Stack.cpp Executable file
View File

@@ -0,0 +1,43 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#ifdef TJP_CORE_HEADER_ONLY
#pragma once
#endif
#include "../../header_only/compile.h"
#include "../Stack.h"
#include "../../system/System.h"
#include <execinfo.h>
#include <sstream>
namespace tjp {
namespace core {
TJP_CORE_HEADER_ONLY_INLINE
std::string getStackString(int maxStackDepth)
{
void* trace[64];
if (maxStackDepth > 64) maxStackDepth = 64;
char** messages = NULL;
int trace_size = 0;
std::ostringstream out;
trace_size = backtrace( trace, maxStackDepth );
messages = backtrace_symbols( trace, trace_size );
for( int i = 2; i < trace_size; ++i ) {
out << "\t" << messages[i] << std::endl;
}
free (messages);
return out.str();
}
} // namespace
} // namespace