Fixes
This commit is contained in:
@ -111,7 +111,6 @@ namespace IACore
|
||||
|
||||
// Check for ZLIB Magic Number (starts with 0x78)
|
||||
// 0x78 = Deflate compression with 32k window size
|
||||
// Valid second bytes: 0x01 (Fastest), 0x9C (Default), 0xDA (Best)
|
||||
if (data[0] == 0x78 && (data[1] == 0x01 || data[1] == 0x9C || data[1] == 0xDA))
|
||||
return CompressionType::Zlib;
|
||||
|
||||
@ -134,7 +133,6 @@ namespace IACore
|
||||
|
||||
Vector<UINT8> outBuffer;
|
||||
// Start with 2x input size.
|
||||
// Small packets compress well, so maybe 4x for very small inputs.
|
||||
size_t guessSize = data.size() < 1024 ? data.size() * 4 : data.size() * 2;
|
||||
outBuffer.resize(guessSize);
|
||||
|
||||
@ -282,7 +280,7 @@ namespace IACore
|
||||
zs.zfree = Z_NULL;
|
||||
zs.opaque = Z_NULL;
|
||||
|
||||
// WindowBits = 15 + 16 (31) -> This forces GZIP encoding
|
||||
// WindowBits = 15 + 16 (31) = Enforce GZIP encoding
|
||||
// MemLevel = 8 (default)
|
||||
// Strategy = Z_DEFAULT_STRATEGY
|
||||
if (deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 + 16, 8, Z_DEFAULT_STRATEGY) != Z_OK)
|
||||
|
||||
@ -182,7 +182,7 @@ namespace IACore
|
||||
|
||||
IPC_Manager::IPC_Manager()
|
||||
{
|
||||
// SocketOps is smart enough to handle multiple inits
|
||||
// SocketOps is smart enough to track multiple inits
|
||||
SocketOps::Initialize();
|
||||
|
||||
m_recieveBuffer.resize(UINT16_MAX + 1);
|
||||
@ -208,7 +208,7 @@ namespace IACore
|
||||
}
|
||||
m_pendingSessions.clear();
|
||||
|
||||
// SocketOps is smart enough to handle multiple terminates
|
||||
// SocketOps is smart enough to track multiple terminates
|
||||
SocketOps::Terminate();
|
||||
}
|
||||
|
||||
|
||||
@ -136,7 +136,7 @@ namespace IACore
|
||||
|
||||
BOOL success = CreateProcessA(NULL, commandLine.data(), NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
|
||||
|
||||
// Important: Close write end in parent, otherwise ReadFile never returns EOF!
|
||||
// Close write end in parent, otherwise ReadFile never returns EOF!
|
||||
CloseHandle(hWrite);
|
||||
|
||||
if (!success)
|
||||
@ -196,7 +196,6 @@ namespace IACore
|
||||
dup2(pipefd[1], STDERR_FILENO);
|
||||
close(pipefd[1]);
|
||||
|
||||
// --- ARGUMENT PARSING START ---
|
||||
std::vector<std::string> argStorage; // To keep strings alive
|
||||
std::vector<char *> argv;
|
||||
|
||||
@ -258,7 +257,6 @@ namespace IACore
|
||||
argv.push_back(s.data());
|
||||
}
|
||||
argv.push_back(nullptr);
|
||||
// --- ARGUMENT PARSING END ---
|
||||
|
||||
execvp(argv[0], argv.data());
|
||||
_exit(127);
|
||||
@ -312,7 +310,6 @@ namespace IACore
|
||||
}
|
||||
else
|
||||
{
|
||||
// Zero copy optimization for pure lines in one chunk
|
||||
if (i > start)
|
||||
Callback(StringView(data + start, i - start));
|
||||
}
|
||||
|
||||
@ -1,16 +1,16 @@
|
||||
// IACore-OSS; The Core Library for All IA Open Source Projects
|
||||
// IACore-OSS; The Core Library for All IA Open Source Projects
|
||||
// Copyright (C) 2025 IAS (ias@iasoft.dev)
|
||||
//
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
@ -19,30 +19,31 @@
|
||||
#include <IACore/PCH.hpp>
|
||||
|
||||
#if IA_PLATFORM_WINDOWS
|
||||
#include <libloaderapi.h>
|
||||
#include <errhandlingapi.h>
|
||||
# include <libloaderapi.h>
|
||||
# include <errhandlingapi.h>
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
# include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
namespace IACore {
|
||||
namespace IACore
|
||||
{
|
||||
|
||||
class DynamicLib {
|
||||
public:
|
||||
// ---------------------------------------------------------------------
|
||||
// Constructors / Destructors (Move Only)
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
DynamicLib() : m_handle(nullptr) {}
|
||||
class DynamicLib
|
||||
{
|
||||
public:
|
||||
DynamicLib() : m_handle(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
// Move Constructor: Steal ownership, nullify source
|
||||
DynamicLib(DynamicLib&& other) NOEXCEPT : m_handle(other.m_handle) {
|
||||
DynamicLib(DynamicLib &&other) NOEXCEPT : m_handle(other.m_handle)
|
||||
{
|
||||
other.m_handle = nullptr;
|
||||
}
|
||||
|
||||
// Move Assignment
|
||||
DynamicLib& operator=(DynamicLib&& other) NOEXCEPT {
|
||||
if (this != &other) {
|
||||
DynamicLib &operator=(DynamicLib &&other) NOEXCEPT
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
Unload(); // Free current if exists
|
||||
m_handle = other.m_handle;
|
||||
other.m_handle = nullptr;
|
||||
@ -50,135 +51,129 @@ namespace IACore {
|
||||
return *this;
|
||||
}
|
||||
|
||||
// No Copying allowed (Library handles are unique resources)
|
||||
DynamicLib(CONST DynamicLib&) = delete;
|
||||
DynamicLib& operator=(CONST DynamicLib&) = delete;
|
||||
DynamicLib(CONST DynamicLib &) = delete;
|
||||
DynamicLib &operator=(CONST DynamicLib &) = delete;
|
||||
|
||||
~DynamicLib() {
|
||||
~DynamicLib()
|
||||
{
|
||||
Unload();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Static Loader
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
// Automatically detects extension (.dll/.so) if not provided
|
||||
NO_DISCARD("Check for load errors")
|
||||
STATIC tl::expected<DynamicLib, String> Load(CONST String& searchPath, CONST String& name) {
|
||||
|
||||
STATIC tl::expected<DynamicLib, String> Load(CONST String &searchPath, CONST String &name)
|
||||
{
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
// 1. Build Path safely
|
||||
fs::path fullPath = fs::path(searchPath) / name;
|
||||
|
||||
// 2. Auto-append extension if missing
|
||||
if (!fullPath.has_extension()) {
|
||||
#if IA_PLATFORM_WINDOWS
|
||||
fullPath += ".dll";
|
||||
#elif IA_PLATFORM_MAC
|
||||
fullPath += ".dylib";
|
||||
#else
|
||||
fullPath += ".so";
|
||||
#endif
|
||||
if (!fullPath.has_extension())
|
||||
{
|
||||
#if IA_PLATFORM_WINDOWS
|
||||
fullPath += ".dll";
|
||||
#elif IA_PLATFORM_MAC
|
||||
fullPath += ".dylib";
|
||||
#else
|
||||
fullPath += ".so";
|
||||
#endif
|
||||
}
|
||||
|
||||
DynamicLib lib;
|
||||
|
||||
#if IA_PLATFORM_WINDOWS
|
||||
// Use LoadLibraryA (ANSI/UTF-8) assuming manifest is set for UTF-8
|
||||
HMODULE h = LoadLibraryA(fullPath.string().c_str());
|
||||
if (!h) {
|
||||
return tl::make_unexpected(GetWindowsError());
|
||||
}
|
||||
lib.m_handle = CAST(h, PVOID);
|
||||
#else
|
||||
// RTLD_LAZY: Resolve symbols only as code executes (Standard for plugins)
|
||||
// RTLD_NOW: Resolve all immediately (Safer for strict engines)
|
||||
void* h = dlopen(fullPath.c_str(), RTLD_LAZY | RTLD_LOCAL);
|
||||
if (!h) {
|
||||
// dlerror returns a string describing the last error
|
||||
const char* err = dlerror();
|
||||
return tl::make_unexpected(String(err ? err : "Unknown dlopen error"));
|
||||
}
|
||||
lib.m_handle = h;
|
||||
#endif
|
||||
|
||||
#if IA_PLATFORM_WINDOWS
|
||||
HMODULE h = LoadLibraryA(fullPath.string().c_str());
|
||||
if (!h)
|
||||
{
|
||||
return tl::make_unexpected(GetWindowsError());
|
||||
}
|
||||
lib.m_handle = CAST(h, PVOID);
|
||||
#else
|
||||
// RTLD_LAZY: Resolve symbols only as code executes (Standard for plugins)
|
||||
void *h = dlopen(fullPath.c_str(), RTLD_LAZY | RTLD_LOCAL);
|
||||
if (!h)
|
||||
{
|
||||
// dlerror returns a string describing the last error
|
||||
const char *err = dlerror();
|
||||
return tl::make_unexpected(String(err ? err : "Unknown dlopen error"));
|
||||
}
|
||||
lib.m_handle = h;
|
||||
#endif
|
||||
|
||||
return IA_MOVE(lib);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Symbol Access
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
NO_DISCARD("Check if symbol exists")
|
||||
tl::expected<PVOID, String> GetSymbol(CONST String& name) CONST {
|
||||
if (!m_handle) return tl::make_unexpected(String("Library not loaded"));
|
||||
|
||||
tl::expected<PVOID, String> GetSymbol(CONST String &name) CONST
|
||||
{
|
||||
if (!m_handle)
|
||||
return tl::make_unexpected(String("Library not loaded"));
|
||||
|
||||
PVOID sym = nullptr;
|
||||
|
||||
#if IA_PLATFORM_WINDOWS
|
||||
sym = CAST(GetProcAddress(CAST(m_handle, HMODULE), name.c_str()), PVOID);
|
||||
if (!sym) return tl::make_unexpected(GetWindowsError());
|
||||
#else
|
||||
// Clear any previous error
|
||||
dlerror();
|
||||
sym = dlsym(m_handle, name.c_str());
|
||||
const char* err = dlerror();
|
||||
if (err) return tl::make_unexpected(String(err));
|
||||
#endif
|
||||
#if IA_PLATFORM_WINDOWS
|
||||
sym = CAST(GetProcAddress(CAST(m_handle, HMODULE), name.c_str()), PVOID);
|
||||
if (!sym)
|
||||
return tl::make_unexpected(GetWindowsError());
|
||||
#else
|
||||
// Clear any previous error
|
||||
dlerror();
|
||||
sym = dlsym(m_handle, name.c_str());
|
||||
const char *err = dlerror();
|
||||
if (err)
|
||||
return tl::make_unexpected(String(err));
|
||||
#endif
|
||||
|
||||
return sym;
|
||||
}
|
||||
|
||||
// Template helper for casting
|
||||
template<typename FuncT>
|
||||
tl::expected<FuncT, String> GetFunction(CONST String& name) CONST {
|
||||
template<typename FuncT> tl::expected<FuncT, String> GetFunction(CONST String &name) CONST
|
||||
{
|
||||
auto res = GetSymbol(name);
|
||||
if (!res) return tl::make_unexpected(res.error());
|
||||
if (!res)
|
||||
return tl::make_unexpected(res.error());
|
||||
return REINTERPRET(*res, FuncT);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// State Management
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
VOID Unload() {
|
||||
if (m_handle) {
|
||||
#if IA_PLATFORM_WINDOWS
|
||||
FreeLibrary(CAST(m_handle, HMODULE));
|
||||
#else
|
||||
dlclose(m_handle);
|
||||
#endif
|
||||
VOID Unload()
|
||||
{
|
||||
if (m_handle)
|
||||
{
|
||||
#if IA_PLATFORM_WINDOWS
|
||||
FreeLibrary(CAST(m_handle, HMODULE));
|
||||
#else
|
||||
dlclose(m_handle);
|
||||
#endif
|
||||
m_handle = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL IsLoaded() CONST {
|
||||
BOOL IsLoaded() CONST
|
||||
{
|
||||
return m_handle != nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
PVOID m_handle;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Private Helpers
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
#if IA_PLATFORM_WINDOWS
|
||||
STATIC String GetWindowsError() {
|
||||
#if IA_PLATFORM_WINDOWS
|
||||
STATIC String GetWindowsError()
|
||||
{
|
||||
DWORD errorID = ::GetLastError();
|
||||
if(errorID == 0) return String();
|
||||
if (errorID == 0)
|
||||
return String();
|
||||
|
||||
LPSTR messageBuffer = nullptr;
|
||||
size_t size = FormatMessageA(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL, errorID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPSTR)&messageBuffer, 0, NULL
|
||||
);
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
|
||||
errorID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR) &messageBuffer, 0, NULL);
|
||||
|
||||
String message(messageBuffer, size);
|
||||
LocalFree(messageBuffer);
|
||||
return String("Win32 Error: ") + message;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
}
|
||||
} // namespace IACore
|
||||
@ -23,20 +23,14 @@ namespace IACore
|
||||
class Environment
|
||||
{
|
||||
public:
|
||||
// ---------------------------------------------------------------------
|
||||
// Getters
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
// Modern approach: Returns nullopt if variable doesn't exist
|
||||
STATIC std::optional<String> Find(CONST String &name)
|
||||
STATIC Optional<String> Find(CONST String &name)
|
||||
{
|
||||
#if IA_PLATFORM_WINDOWS
|
||||
// 1. Get required size (result includes null terminator if buffer is null/too small)
|
||||
DWORD bufferSize = GetEnvironmentVariableA(name.c_str(), nullptr, 0);
|
||||
|
||||
if (bufferSize == 0)
|
||||
{
|
||||
// DWORD 0 means failed (usually ERROR_ENVVAR_NOT_FOUND)
|
||||
// DWORD 0 means failed
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
@ -45,7 +39,7 @@ namespace IACore
|
||||
result.resize(bufferSize);
|
||||
|
||||
// 3. Fetch
|
||||
// Returns num chars written EXCLUDING null terminator
|
||||
// Returns num chars written excluding null terminator
|
||||
DWORD actualSize = GetEnvironmentVariableA(name.c_str(), result.data(), bufferSize);
|
||||
|
||||
if (actualSize == 0 || actualSize > bufferSize)
|
||||
@ -58,8 +52,7 @@ namespace IACore
|
||||
return result;
|
||||
|
||||
#else
|
||||
// POSIX (Linux/Mac)
|
||||
// getenv returns a pointer to the environment area. Do NOT free it.
|
||||
// getenv returns a pointer to the environment area
|
||||
const char *val = std::getenv(name.c_str());
|
||||
if (val == nullptr)
|
||||
{
|
||||
@ -69,17 +62,11 @@ namespace IACore
|
||||
#endif
|
||||
}
|
||||
|
||||
// Classic approach: Returns value or default (defaulting to "")
|
||||
// Matches your old API behavior but is safer
|
||||
STATIC String Get(CONST String &name, CONST String &defaultValue = "")
|
||||
{
|
||||
return Find(name).value_or(defaultValue);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Setters
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
STATIC BOOL Set(CONST String &name, CONST String &value)
|
||||
{
|
||||
if (name.empty())
|
||||
@ -88,7 +75,6 @@ namespace IACore
|
||||
#if IA_PLATFORM_WINDOWS
|
||||
return SetEnvironmentVariableA(name.c_str(), value.c_str()) != 0;
|
||||
#else
|
||||
// setenv(name, value, overwrite)
|
||||
// Returns 0 on success, -1 on error
|
||||
return setenv(name.c_str(), value.c_str(), 1) == 0;
|
||||
#endif
|
||||
@ -100,17 +86,12 @@ namespace IACore
|
||||
return FALSE;
|
||||
|
||||
#if IA_PLATFORM_WINDOWS
|
||||
// Windows unsets a variable by setting it to NULL
|
||||
return SetEnvironmentVariableA(name.c_str(), nullptr) != 0;
|
||||
#else
|
||||
return unsetenv(name.c_str()) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Utilities
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
STATIC BOOL Exists(CONST String &name)
|
||||
{
|
||||
#if IA_PLATFORM_WINDOWS
|
||||
|
||||
@ -28,7 +28,6 @@
|
||||
|
||||
# define valid_iatest_runner(type) iatest::_valid_iatest_runner<type>::value_type
|
||||
|
||||
// Internal macro to handle the return logic
|
||||
# define __iat_micro_test(call) \
|
||||
if (!(call)) \
|
||||
return FALSE
|
||||
@ -38,7 +37,6 @@
|
||||
# define IAT_CHECK_EQ(lhs, rhs) __iat_micro_test(_test_eq((lhs), (rhs), #lhs " == " #rhs))
|
||||
# define IAT_CHECK_NEQ(lhs, rhs) __iat_micro_test(_test_neq((lhs), (rhs), #lhs " != " #rhs))
|
||||
|
||||
// Float specific checks (Game dev essential)
|
||||
# define IAT_CHECK_APPROX(lhs, rhs) __iat_micro_test(_test_approx((lhs), (rhs), #lhs " ~= " #rhs))
|
||||
|
||||
# define IAT_UNIT(func) _test_unit([this]() { return this->func(); }, #func)
|
||||
@ -46,7 +44,6 @@
|
||||
|
||||
# define IAT_BLOCK(name) class name : public ia::iatest::block
|
||||
|
||||
// Concatenation fix for macros
|
||||
# define IAT_BEGIN_BLOCK(_group, _name) \
|
||||
class _group##_##_name : public ia::iatest::block \
|
||||
{ \
|
||||
@ -74,9 +71,6 @@
|
||||
|
||||
namespace ia::iatest
|
||||
{
|
||||
// -------------------------------------------------------------------------
|
||||
// Type Printing Helper (To show WHAT failed)
|
||||
// -------------------------------------------------------------------------
|
||||
template<typename T> std::string ToString(CONST T &value)
|
||||
{
|
||||
if constexpr (std::is_arithmetic_v<T>)
|
||||
@ -93,7 +87,6 @@ namespace ia::iatest
|
||||
}
|
||||
}
|
||||
|
||||
// Specialization for pointers
|
||||
template<typename T> std::string ToString(T *value)
|
||||
{
|
||||
if (value == NULLPTR)
|
||||
@ -103,10 +96,6 @@ namespace ia::iatest
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Core Structures
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
DEFINE_TYPE(functor_t, std::function<BOOL()>);
|
||||
|
||||
struct unit_t
|
||||
@ -128,7 +117,6 @@ namespace ia::iatest
|
||||
}
|
||||
|
||||
protected:
|
||||
// Generic Equality
|
||||
template<typename T1, typename T2> BOOL _test_eq(IN CONST T1 &lhs, IN CONST T2 &rhs, IN PCCHAR description)
|
||||
{
|
||||
if (lhs != rhs)
|
||||
@ -139,7 +127,6 @@ namespace ia::iatest
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Generic Inequality
|
||||
template<typename T1, typename T2> BOOL _test_neq(IN CONST T1 &lhs, IN CONST T2 &rhs, IN PCCHAR description)
|
||||
{
|
||||
if (lhs == rhs)
|
||||
@ -150,13 +137,12 @@ namespace ia::iatest
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Floating Point Approximation (Epsilon check)
|
||||
template<typename T> BOOL _test_approx(IN T lhs, IN T rhs, IN PCCHAR description)
|
||||
{
|
||||
static_assert(std::is_floating_point_v<T>, "Approx only works for floats/doubles");
|
||||
T diff = std::abs(lhs - rhs);
|
||||
if (diff > static_cast<T>(0.0001))
|
||||
{ // Default epsilon
|
||||
{
|
||||
print_fail(description, ToString(lhs), ToString(rhs));
|
||||
return FALSE;
|
||||
}
|
||||
@ -202,10 +188,6 @@ namespace ia::iatest
|
||||
template<typename block_class>
|
||||
concept valid_block_class = std::derived_from<block_class, block>;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Runner
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
template<BOOL stopOnFail = false, BOOL isVerbose = false> class runner
|
||||
{
|
||||
public:
|
||||
@ -253,7 +235,6 @@ namespace ia::iatest
|
||||
BOOL result = FALSE;
|
||||
try
|
||||
{
|
||||
// Execute the test function
|
||||
result = v.Functor();
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
@ -311,10 +292,6 @@ namespace ia::iatest
|
||||
{
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Global Test Registry
|
||||
// -------------------------------------------------------------------------
|
||||
// Standard runner configuration for the single executable
|
||||
using DefaultRunner = runner<false, true>;
|
||||
|
||||
class TestRegistry
|
||||
@ -352,7 +329,6 @@ namespace ia::iatest
|
||||
};
|
||||
} // namespace ia::iatest
|
||||
|
||||
// Usage: IAT_REGISTER_ENTRY(Core, Utils)
|
||||
# define IAT_REGISTER_ENTRY(Group, Name) static ia::iatest::AutoRegister<Group##_##Name> _iat_reg_##Group##_##Name;
|
||||
|
||||
#endif // __cplusplus
|
||||
@ -43,7 +43,7 @@ namespace IACore
|
||||
// SECTION 2: RING BUFFER CONTROL BLOCKS
|
||||
// =========================================================
|
||||
|
||||
// RingBufferView::ControlBlock is already 64-byte aligned internally.
|
||||
// RingBufferView ControlBlock is already 64-byte aligned internally.
|
||||
RingBufferView::ControlBlock MONI_Control;
|
||||
RingBufferView::ControlBlock MINO_Control;
|
||||
|
||||
|
||||
@ -54,8 +54,8 @@
|
||||
# define NOMINMAX
|
||||
# endif
|
||||
# include <windows.h>
|
||||
#undef VOID
|
||||
#undef ERROR
|
||||
# undef VOID
|
||||
# undef ERROR
|
||||
#elif IA_PLATFORM_UNIX
|
||||
# include <unistd.h>
|
||||
# include <sys/wait.h>
|
||||
@ -238,7 +238,6 @@
|
||||
|
||||
#define ALIGN(a) __attribute__((aligned(a)))
|
||||
|
||||
// Mark every explicit assembly instruction as volatile
|
||||
#define ASM(...) __asm__ volatile(__VA_ARGS__)
|
||||
|
||||
#ifndef NULL
|
||||
@ -539,7 +538,7 @@ STATIC CONST FLOAT64 FLOAT64_EPSILON = DBL_EPSILON;
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// C++ Containers and Helpers
|
||||
// Containers and Helpers
|
||||
// -------------------------------------------------------------------------
|
||||
#ifdef __cplusplus
|
||||
|
||||
|
||||
@ -43,7 +43,7 @@ using SocketHandle = int;
|
||||
|
||||
#else
|
||||
|
||||
# warning "IACore SocketOps is not supported on this platform."
|
||||
# error "IACore SocketOps is not supported on this platform."
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@ -55,7 +55,6 @@ namespace IACore
|
||||
char high = hex[i];
|
||||
char low = hex[i + 1];
|
||||
|
||||
// Quick helper to decode nibble
|
||||
auto fromHexChar = [](char c) -> int {
|
||||
if (c >= '0' && c <= '9')
|
||||
return c - '0';
|
||||
@ -95,16 +94,10 @@ namespace IACore
|
||||
return std::ranges::upper_bound(range, value);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Hash Combination Logic
|
||||
// Uses the "golden ratio" mix (similar to Boost) to preserve entropy.
|
||||
// -------------------------------------------------------------------------
|
||||
template<typename T> INLINE STATIC void HashCombine(UINT64 &seed, CONST T &v)
|
||||
{
|
||||
UINT64 h;
|
||||
|
||||
// 1. Compile-Time check: Can this be treated as a string view?
|
||||
// This catches "Literal Strings" (char[N]), const char*, and std::string
|
||||
if constexpr (std::is_constructible_v<std::string_view, T>)
|
||||
{
|
||||
std::string_view sv(v);
|
||||
@ -113,34 +106,24 @@ namespace IACore
|
||||
}
|
||||
else
|
||||
{
|
||||
// 2. Standard types (int, float, custom structs)
|
||||
auto hasher = ankerl::unordered_dense::hash<T>();
|
||||
h = hasher(v);
|
||||
}
|
||||
|
||||
// 0x9e3779b97f4a7c15 is the 64-bit golden ratio (phi) approximation
|
||||
seed ^= h + 0x9e3779b97f4a7c15 + (seed << 6) + (seed >> 2);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Variadic Hasher
|
||||
// Allows: IACore::ComputeHash(x, y, z);
|
||||
// -------------------------------------------------------------------------
|
||||
template<typename... Args> INLINE STATIC UINT64 ComputeHash(CONST Args &...args)
|
||||
{
|
||||
UINT64 seed = 0;
|
||||
(HashCombine(seed, args), ...); // C++17/20 Fold Expression
|
||||
(HashCombine(seed, args), ...);
|
||||
return seed;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Flat Hasher
|
||||
// Allows: IACore::ComputeHashFlat(x, y, z);
|
||||
// -------------------------------------------------------------------------
|
||||
template<typename T, typename... MemberPtrs> INLINE STATIC UINT64 ComputeHashFlat(CONST T &obj, MemberPtrs... members)
|
||||
template<typename T, typename... MemberPtrs>
|
||||
INLINE STATIC UINT64 ComputeHashFlat(CONST T &obj, MemberPtrs... members)
|
||||
{
|
||||
UINT64 seed = 0;
|
||||
// C++17 Fold Expression: applies (seed, obj.*ptr) for every ptr in members
|
||||
(HashCombine(seed, obj.*members), ...);
|
||||
return seed;
|
||||
}
|
||||
@ -156,15 +139,14 @@ namespace IACore
|
||||
// struct Vector3 { float x, y, z; };
|
||||
// IA_MAKE_HASHABLE(Vector3, &Vector3::x, &Vector3::y, &Vector3::z)
|
||||
// -----------------------------------------------------------------------------
|
||||
#define IA_MAKE_HASHABLE(Type, ...) \
|
||||
template<> struct ankerl::unordered_dense::hash<Type> \
|
||||
{ \
|
||||
using is_avalanching = void; \
|
||||
NO_DISCARD("Hash value should be used") \
|
||||
UINT64 operator()(CONST Type &v) const NOEXCEPT \
|
||||
{ \
|
||||
/* Pass the object and the list of member pointers */ \
|
||||
return IACore::Utils::ComputeHashFlat(v, __VA_ARGS__); \
|
||||
} \
|
||||
#define IA_MAKE_HASHABLE(Type, ...) \
|
||||
template<> struct ankerl::unordered_dense::hash<Type> \
|
||||
{ \
|
||||
using is_avalanching = void; \
|
||||
NO_DISCARD("Hash value should be used") \
|
||||
UINT64 operator()(CONST Type &v) const NOEXCEPT \
|
||||
{ \
|
||||
/* Pass the object and the list of member pointers */ \
|
||||
return IACore::Utils::ComputeHashFlat(v, __VA_ARGS__); \
|
||||
} \
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user