deargui-vpl/applications/nodehub/core/utils.h
2026-02-03 18:25:25 +01:00

184 lines
5.8 KiB
C

#ifndef NODEHUB_CORE_UTILS_H
#define NODEHUB_CORE_UTILS_H
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <pthread.h> // For mutex helpers
#include <threads.h> // For thread helpers (C11)
// From https://hwisnu.bearblog.dev/giving-c-a-superpower-custom-header-file-safe_ch/
//==============================================================================
// ATTRIBUTES & BUILTINS
//==============================================================================
// The magic behind CLEANUP: zero overhead, maximum safety
// NOTE: [[cleanup]] is a C23 feature. __attribute__((cleanup)) is a GCC/Clang extension.
// This will work in C++ with GCC/Clang but is not standard C++.
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
#define CLEANUP(func) [[cleanup(func)]]
#else
#define CLEANUP(func) __attribute__((cleanup(func)))
#endif
// Branch prediction that actually matters in hot paths
#ifdef __GNUC__
#define LIKELY(x) __builtin_expect(!!(x), 1)
#define UNLIKELY(x) __builtin_expect(!!(x), 0)
#else
#define LIKELY(x) (x)
#define UNLIKELY(x) (x)
#endif
//==============================================================================
// SMART POINTERS
//==============================================================================
// --- UniquePtr ---
// NOTE: The blog post did not define UNIQUE_PTR_INIT or unique_ptr_delete.
// A reasonable implementation is provided below.
typedef struct {
void* ptr;
void (*deleter)(void*);
} UniquePtr;
#define UNIQUE_PTR_INIT(p, d) {.ptr = p, .deleter = d}
static inline void unique_ptr_cleanup(UniquePtr* uptr) {
if (uptr && uptr->ptr && uptr->deleter) {
uptr->deleter(uptr->ptr);
uptr->ptr = NULL;
}
}
#define AUTO_UNIQUE_PTR(name, ptr, deleter) \
UniquePtr name CLEANUP(unique_ptr_cleanup) = UNIQUE_PTR_INIT(ptr, deleter)
// Manually release the resource, for reassignment.
static inline void unique_ptr_delete(UniquePtr* uptr) {
unique_ptr_cleanup(uptr);
}
// --- SharedPtr ---
// NOTE: The blog post mentioned shared_ptr_init, shared_ptr_copy, and shared_ptr_delete
// but did not provide their implementations. A reasonable implementation is provided below.
typedef struct {
void* ptr;
void (*deleter)(void*);
size_t* ref_count;
} SharedPtr;
static inline void shared_ptr_delete(SharedPtr* sptr); // Forward declare
static inline void shared_ptr_cleanup(SharedPtr* sptr) {
shared_ptr_delete(sptr); // Decrement and free if last reference
}
#define AUTO_SHARED_PTR(name) \
SharedPtr name CLEANUP(shared_ptr_cleanup) = {.ptr = NULL, .deleter = NULL, .ref_count = NULL}
static inline void shared_ptr_init(SharedPtr* sptr, void* ptr, void (*deleter)(void*)) {
if (!sptr) return;
sptr->ptr = ptr;
sptr->deleter = deleter;
if (ptr) {
sptr->ref_count = (size_t*)malloc(sizeof(size_t));
if (sptr->ref_count) {
*(sptr->ref_count) = 1;
}
} else {
sptr->ref_count = NULL;
}
}
static inline SharedPtr shared_ptr_copy(SharedPtr* sptr) {
SharedPtr new_sptr = { .ptr = NULL, .deleter = NULL, .ref_count = NULL };
if (sptr && sptr->ptr && sptr->ref_count) {
new_sptr.ptr = sptr->ptr;
new_sptr.deleter = sptr->deleter;
new_sptr.ref_count = sptr->ref_count;
(*(new_sptr.ref_count))++;
}
return new_sptr;
}
static inline void shared_ptr_delete(SharedPtr* sptr) {
if (sptr && sptr->ptr && sptr->ref_count) {
(*(sptr->ref_count))--;
if (*(sptr->ref_count) == 0) {
if (sptr->deleter) {
sptr->deleter(sptr->ptr);
}
free(sptr->ref_count);
}
sptr->ptr = NULL;
sptr->deleter = NULL;
sptr->ref_count = NULL;
}
}
//==============================================================================
// DYNAMIC ARRAYS (VECTORS)
//==============================================================================
// NOTE: The DEFINE_VECTOR_TYPE macro in the blog post was truncated ("... (6495 chars omitted)...").
// It cannot be fully reproduced from the article.
//==============================================================================
// SAFE STRING OPERATIONS
//==============================================================================
static inline bool safe_strcpy(char* dest, size_t dest_size, const char* src) {
if (!dest || dest_size == 0 || !src) return false;
size_t src_len = strlen(src);
if (src_len >= dest_size) return false;
memcpy(dest, src, src_len + 1);
return true;
}
//==============================================================================
// CONCURRENCY HELPERS
//==============================================================================
// --- RAII Mutexes ---
// RAII-style mutex locking using the CLEANUP attribute.
// The mutex is automatically unlocked when the pointer goes out of scope.
static inline void mutex_unlock_cleanup(pthread_mutex_t** lock) {
if (lock && *lock) {
pthread_mutex_unlock(*lock);
}
}
/* Example Usage:
pthread_mutex_t my_lock;
pthread_mutex_init(&my_lock, NULL);
...
{
pthread_mutex_t* lock_ptr CLEANUP(mutex_unlock_cleanup) = &my_lock;
pthread_mutex_lock(lock_ptr);
// ... critical section ...
if (some_error) return; // Mutex is automatically unlocked
}
*/
// --- Threading Macros ---
// NOTE: These use C11 threads (<threads.h>). Ensure your compiler supports it.
#define SPAWN_THREAD(name, func, arg) \
thrd_t name; \
if (thrd_create(&name, (thrd_start_t)(func), (arg)) != thrd_success) { /* handle error */ }
#define JOIN_THREAD(name) \
thrd_join(name, NULL)
#endif // NODEHUB_CORE_UTILS_H