From 21a474b6f92e17a5af5c98538157ab382355e3f5 Mon Sep 17 00:00:00 2001 From: dev0 Date: Mon, 26 Jan 2026 22:55:39 +0530 Subject: [PATCH] [FIX]: Window Build Fix --- .clang-format | 8 +- .github/workflows/ci.yaml | 21 + CMake/FindDeps.cmake | 2 + CMake/IAProjectConfig.cmake | 2 + ...-windows.cmake => x64-windows-clang.cmake} | 2 + .../Toolchains/x64-windows-cross-clang.cmake | 48 + CMakePresets.json | 19 +- Src/IACore/CMakeLists.txt | 7 +- Src/IACore/imp/cpp/AsyncOps.cpp | 349 ++++--- Src/IACore/imp/cpp/CLI.cpp | 17 +- Src/IACore/imp/cpp/DataOps.cpp | 744 +++++++------- Src/IACore/imp/cpp/FileOps.cpp | 938 ++++++++++-------- Src/IACore/imp/cpp/Http/Client.cpp | 239 ++--- Src/IACore/imp/cpp/Http/Common.cpp | 187 ++-- Src/IACore/imp/cpp/Http/Server.cpp | 286 +++--- Src/IACore/imp/cpp/IACore.cpp | 61 +- Src/IACore/imp/cpp/IPC.cpp | 802 +++++++-------- Src/IACore/imp/cpp/JSON.cpp | 4 +- Src/IACore/imp/cpp/Logger.cpp | 115 ++- Src/IACore/imp/cpp/Platform.cpp | 169 ++-- Src/IACore/imp/cpp/ProcessOps.cpp | 532 +++++----- Src/IACore/imp/cpp/SIMD.cpp | 4 +- Src/IACore/imp/cpp/SocketOps.cpp | 232 ++--- Src/IACore/imp/cpp/StreamReader.cpp | 116 ++- Src/IACore/imp/cpp/StreamWriter.cpp | 253 ++--- Src/IACore/imp/cpp/StringOps.cpp | 194 ++-- Src/IACore/imp/cpp/Utils.cpp | 178 ++-- Src/IACore/imp/cpp/XML.cpp | 125 +-- Src/IACore/inc/IACore/ADT/RingBuffer.hpp | 390 ++++---- Src/IACore/inc/IACore/AsyncOps.hpp | 72 +- Src/IACore/inc/IACore/CLI.hpp | 79 +- Src/IACore/inc/IACore/DataOps.hpp | 39 +- Src/IACore/inc/IACore/DynamicLib.hpp | 197 ++-- Src/IACore/inc/IACore/Environment.hpp | 124 ++- Src/IACore/inc/IACore/FileOps.hpp | 127 +-- Src/IACore/inc/IACore/Http/Client.hpp | 99 +- Src/IACore/inc/IACore/Http/Common.hpp | 238 ++--- Src/IACore/inc/IACore/Http/Server.hpp | 205 ++-- Src/IACore/inc/IACore/IACore.hpp | 87 +- Src/IACore/inc/IACore/IATest.hpp | 441 ++++---- Src/IACore/inc/IACore/IPC.hpp | 242 +++-- Src/IACore/inc/IACore/JSON.hpp | 145 +-- Src/IACore/inc/IACore/Logger.hpp | 159 +-- Src/IACore/inc/IACore/PCH.hpp | 137 +-- Src/IACore/inc/IACore/Platform.hpp | 43 +- Src/IACore/inc/IACore/ProcessOps.hpp | 61 +- Src/IACore/inc/IACore/SIMD.hpp | 408 ++++---- Src/IACore/inc/IACore/SocketOps.hpp | 140 +-- Src/IACore/inc/IACore/StreamReader.hpp | 137 +-- Src/IACore/inc/IACore/StreamWriter.hpp | 101 +- Src/IACore/inc/IACore/StringOps.hpp | 12 +- Src/IACore/inc/IACore/Utils.hpp | 131 +-- Src/IACore/inc/IACore/XML.hpp | 24 +- Tests/Subjects/LongProcess/Main.cpp | 12 +- Tests/Unit/AsyncOps.cpp | 49 +- Tests/Unit/CLI.cpp | 12 +- Tests/Unit/CMakeLists.txt | 6 +- Tests/Unit/DataOps.cpp | 27 +- Tests/Unit/Environment.cpp | 36 +- Tests/Unit/FileOps.cpp | 30 +- Tests/Unit/IPC.cpp | 54 +- Tests/Unit/JSON.cpp | 32 +- Tests/Unit/Logger.cpp | 33 +- Tests/Unit/Main.cpp | 13 +- Tests/Unit/Platform.cpp | 23 +- Tests/Unit/ProcessOps.cpp | 84 +- Tests/Unit/RingBuffer.cpp | 15 +- Tests/Unit/SIMD/FloatVec4.cpp | 12 +- Tests/Unit/SIMD/IntVec4.cpp | 17 +- Tests/Unit/SocketOps.cpp | 25 +- Tests/Unit/StreamReader.cpp | 20 +- Tests/Unit/StreamWriter.cpp | 18 +- Tests/Unit/StringOps.cpp | 21 +- Tests/Unit/Utils.cpp | 24 +- Tests/Unit/XML.cpp | 18 +- 75 files changed, 5430 insertions(+), 4643 deletions(-) rename CMake/Toolchains/{x64-windows.cmake => x64-windows-clang.cmake} (89%) create mode 100644 CMake/Toolchains/x64-windows-cross-clang.cmake diff --git a/.clang-format b/.clang-format index 97a556b..f7493c6 100644 --- a/.clang-format +++ b/.clang-format @@ -1,10 +1,9 @@ ---- Language: Cpp Standard: c++20 BasedOnStyle: Microsoft -IndentWidth: 4 -TabWidth: 4 +IndentWidth: 2 +TabWidth: 2 UseTab: Never AccessModifierOffset: -4 @@ -28,5 +27,4 @@ SpaceInEmptyParentheses: false SpacesInAngles: false SeparateDefinitionBlocks: Always -SortIncludes: false ---- \ No newline at end of file +SortIncludes: Never \ No newline at end of file diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 3b1a226..3362fbc 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -18,6 +18,7 @@ jobs: fail-fast: false matrix: target: [x64-linux] + steps: - uses: actions/checkout@v4 @@ -29,3 +30,23 @@ jobs: - name: Build run: cmake --build --preset ${{ matrix.target }} --config Release + + build-windows: + runs-on: windows-latest + permissions: + contents: read + strategy: + fail-fast: false + matrix: + target: [x64-windows] + + steps: + - uses: actions/checkout@v4 + + - uses: ilammy/msvc-dev-cmd@v1 + + - name: Configure + run: cmake --preset ${{ matrix.target }} + + - name: Build + run: cmake --build --preset ${{ matrix.target }} --config Release \ No newline at end of file diff --git a/CMake/FindDeps.cmake b/CMake/FindDeps.cmake index 3ae114f..af5213d 100644 --- a/CMake/FindDeps.cmake +++ b/CMake/FindDeps.cmake @@ -92,6 +92,8 @@ FetchContent_Declare( EXCLUDE_FROM_ALL ) +set(PUGIXML_NO_EXCEPTIONS ON) + FetchContent_Declare( pugixml GIT_REPOSITORY https://github.com/zeux/pugixml.git diff --git a/CMake/IAProjectConfig.cmake b/CMake/IAProjectConfig.cmake index 869134f..5e4ad18 100644 --- a/CMake/IAProjectConfig.cmake +++ b/CMake/IAProjectConfig.cmake @@ -18,6 +18,8 @@ macro(iacore_setup_project) add_compile_options(-Wall -Wextra -Wpedantic -Wno-language-extension-token) endif() + add_compile_options(-Wno-missing-field-initializers -Wno-missing-designated-field-initializers) + if(CMAKE_SYSTEM_PROCESSOR MATCHES "amd64|x86_64|AMD64") set(IACORE_ARCH_X64 TRUE CACHE INTERNAL "") elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|arm64|ARM64") diff --git a/CMake/Toolchains/x64-windows.cmake b/CMake/Toolchains/x64-windows-clang.cmake similarity index 89% rename from CMake/Toolchains/x64-windows.cmake rename to CMake/Toolchains/x64-windows-clang.cmake index cde73b9..ab57ef5 100644 --- a/CMake/Toolchains/x64-windows.cmake +++ b/CMake/Toolchains/x64-windows-clang.cmake @@ -4,6 +4,8 @@ set(CMAKE_C_COMPILER clang-cl) set(CMAKE_CXX_COMPILER clang-cl) set(CMAKE_RC_COMPILER llvm-rc) +set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded") + set(triple x86_64-pc-windows-msvc) set(CMAKE_C_COMPILER_TARGET ${triple}) set(CMAKE_CXX_COMPILER_TARGET ${triple}) diff --git a/CMake/Toolchains/x64-windows-cross-clang.cmake b/CMake/Toolchains/x64-windows-cross-clang.cmake new file mode 100644 index 0000000..a1ef1f1 --- /dev/null +++ b/CMake/Toolchains/x64-windows-cross-clang.cmake @@ -0,0 +1,48 @@ +set(CMAKE_SYSTEM_NAME Windows) +set(CMAKE_SYSTEM_PROCESSOR AMD64) +set(CMAKE_C_COMPILER clang-cl) +set(CMAKE_CXX_COMPILER clang-cl) +set(CMAKE_RC_COMPILER llvm-rc) + +set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded") + +set(triple x86_64-pc-windows-msvc) +set(CMAKE_C_COMPILER_TARGET ${triple}) +set(CMAKE_CXX_COMPILER_TARGET ${triple}) + +set(CMAKE_LINKER lld-link) + +string(APPEND CMAKE_C_FLAGS " /arch:AVX2 /clang:-mfma") +string(APPEND CMAKE_CXX_FLAGS " /arch:AVX2 /clang:-mfma") + +# --------------------------------------------------------------------- +# WinSDK directory can be splatted on linux using 'xwin' cargo package +# Please also ensure to place OpenSSL windows binaries in WINSDK_PATH/openssl/x64 +# OpenSSL minimum required version is 3.0.0 + +if(NOT DEFINED ENV{WINSDK_PATH} OR "$ENV{WINSDK_PATH}" STREQUAL "") + message(FATAL_ERROR "Environment variable WINSDK_PATH is not set. Please set it before running the cross toolchain.") +endif() + +message(STATUS "Using Windows SDK at : $ENV{WINSDK_PATH}") + +set(OPENSSL_ROOT_DIR "$ENV{WINSDK_PATH}/openssl/x64") +set(OPENSSL_USE_STATIC_LIBS TRUE) + +if(NOT EXISTS "${OPENSSL_ROOT_DIR}") + message(FATAL_ERROR "OpenSSL directory not found: ${OPENSSL_ROOT_DIR}") +elseif(NOT IS_DIRECTORY "${OPENSSL_ROOT_DIR}") + message(FATAL_ERROR "OpenSSL path exists but is not a directory: ${OPENSSL_ROOT_DIR}") +endif() + +string(APPEND CMAKE_C_FLAGS " /imsvc $ENV{WINSDK_PATH}/crt/include /imsvc $ENV{WINSDK_PATH}/sdk/include/ucrt /imsvc $ENV{WINSDK_PATH}/sdk/include/um /imsvc $ENV{WINSDK_PATH}/sdk/include/shared") +string(APPEND CMAKE_CXX_FLAGS " /imsvc $ENV{WINSDK_PATH}/crt/include /imsvc $ENV{WINSDK_PATH}/sdk/include/ucrt /imsvc $ENV{WINSDK_PATH}/sdk/include/um /imsvc $ENV{WINSDK_PATH}/sdk/include/shared") + +set(CRT_LIB_PATH "$ENV{WINSDK_PATH}/crt/lib/x86_64") +set(SDK_LIB_PATH "$ENV{WINSDK_PATH}/sdk/lib") + +set(CMAKE_EXE_LINKER_FLAGS + "${CMAKE_EXE_LINKER_FLAGS} /libpath:\"${CRT_LIB_PATH}\" /libpath:\"${SDK_LIB_PATH}/ucrt/x86_64\" /libpath:\"${SDK_LIB_PATH}/um/x86_64\"" +) + +# --------------------------------------------------------------------- diff --git a/CMakePresets.json b/CMakePresets.json index ab3a685..0db6ce4 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -47,10 +47,19 @@ } }, { - "name": "wasm", + "name": "wasm32-emscripten", "displayName": "IACore WebAssembly (Clang)", "inherits": "iacore-base", "cacheVariables": {} + }, + { + "name": "x64-windows-cross", + "displayName": "IACore Windows x64 Cross (Linux Host) (Clang)", + "inherits": "iacore-base", + "cacheVariables": { + "CMAKE_C_COMPILER": "clang-cl", + "CMAKE_CXX_COMPILER": "clang-cl" + } } ], "buildPresets": [ @@ -71,8 +80,12 @@ "configurePreset": "arm64-windows" }, { - "name": "wasm", - "configurePreset": "wasm" + "name": "wasm32-emscripten", + "configurePreset": "wasm32-emscripten" + }, + { + "name": "x64-windows-cross", + "configurePreset": "x64-windows-cross" } ] } \ No newline at end of file diff --git a/Src/IACore/CMakeLists.txt b/Src/IACore/CMakeLists.txt index 3a77c31..d88cfea 100644 --- a/Src/IACore/CMakeLists.txt +++ b/Src/IACore/CMakeLists.txt @@ -57,7 +57,11 @@ endif() target_precompile_headers(IACore PUBLIC inc/IACore/PCH.hpp) -set(NO_EXCEPT_FLAG "$,/EHs-c-,-fno-exceptions>") +if(MSVC) + set(NO_EXCEPT_FLAG "/EHs-c-") +else() + set(NO_EXCEPT_FLAG "-fno-exceptions") +endif() target_compile_options(IACore PRIVATE ${NO_EXCEPT_FLAG}) target_compile_options(IACore INTERFACE $<$>>:${NO_EXCEPT_FLAG}> @@ -71,6 +75,7 @@ define_property(TARGET PROPERTY USE_EXCEPTIONS target_compile_definitions(IACore PRIVATE CPPHTTPLIB_OPENSSL_SUPPORT CPPHTTPLIB_ZLIB_SUPPORT + _CRT_SECURE_NO_WARNINGS NOMINMAX ) diff --git a/Src/IACore/imp/cpp/AsyncOps.cpp b/Src/IACore/imp/cpp/AsyncOps.cpp index 04ebea7..631f219 100644 --- a/Src/IACore/imp/cpp/AsyncOps.cpp +++ b/Src/IACore/imp/cpp/AsyncOps.cpp @@ -15,185 +15,220 @@ #include -namespace IACore { -Mut AsyncOps::s_queue_mutex; -Mut AsyncOps::s_wake_condition; -Mut> AsyncOps::s_schedule_workers; -Mut> AsyncOps::s_high_priority_queue; -Mut> AsyncOps::s_normal_priority_queue; +namespace IACore +{ + Mut AsyncOps::s_queue_mutex; + Mut AsyncOps::s_wake_condition; + Mut> AsyncOps::s_schedule_workers; + Mut> AsyncOps::s_high_priority_queue; + Mut> AsyncOps::s_normal_priority_queue; -auto AsyncOps::run_task(Mut> task) -> void { - std::jthread(std::move(task)).detach(); -} + auto AsyncOps::run_task(Mut> task) -> void + { + std::jthread(std::move(task)).detach(); + } -auto AsyncOps::initialize_scheduler(Mut worker_count) -> Result { - if (worker_count == 0) { - const u32 hw_concurrency = std::thread::hardware_concurrency(); - Mut threads = 2; - if (hw_concurrency > 2) { - threads = hw_concurrency - 2; + auto AsyncOps::initialize_scheduler(Mut worker_count) -> Result + { + if (worker_count == 0) + { + const u32 hw_concurrency = std::thread::hardware_concurrency(); + Mut threads = 2; + if (hw_concurrency > 2) + { + threads = hw_concurrency - 2; + } + + if (threads > 255) + { + threads = 255; + } + worker_count = static_cast(threads); } - if (threads > 255) { - threads = 255; + for (Mut i = 0; i < worker_count; ++i) + { + s_schedule_workers.emplace_back(schedule_worker_loop, static_cast(i + 1)); } - worker_count = static_cast(threads); + + return {}; } - for (Mut i = 0; i < worker_count; ++i) { - s_schedule_workers.emplace_back(schedule_worker_loop, - static_cast(i + 1)); - } - - return {}; -} - -auto AsyncOps::terminate_scheduler() -> void { - for (MutRef worker : s_schedule_workers) { - worker.request_stop(); - } - - s_wake_condition.notify_all(); - - for (MutRef worker : s_schedule_workers) { - if (worker.joinable()) { - worker.join(); + auto AsyncOps::terminate_scheduler() -> void + { + for (MutRef worker : s_schedule_workers) + { + worker.request_stop(); } + + s_wake_condition.notify_all(); + + for (MutRef worker : s_schedule_workers) + { + if (worker.joinable()) + { + worker.join(); + } + } + + s_schedule_workers.clear(); } - s_schedule_workers.clear(); -} + auto AsyncOps::schedule_task(Mut> task, const TaskTag tag, Schedule *schedule, + const Priority priority) -> void + { + ensure(!s_schedule_workers.empty(), "Scheduler must be initialized before calling schedule_task"); -auto AsyncOps::schedule_task(Mut> task, - const TaskTag tag, Schedule *schedule, - const Priority priority) -> void { - ensure(!s_schedule_workers.empty(), - "Scheduler must be initialized before calling schedule_task"); + schedule->counter.fetch_add(1); + { + const std::lock_guard lock(s_queue_mutex); + if (priority == Priority::High) + { + s_high_priority_queue.emplace_back(ScheduledTask{tag, schedule, std::move(task)}); + } + else + { + s_normal_priority_queue.emplace_back(ScheduledTask{tag, schedule, std::move(task)}); + } + } + s_wake_condition.notify_one(); + } - schedule->counter.fetch_add(1); + auto AsyncOps::cancel_tasks_of_tag(const TaskTag tag) -> void { const std::lock_guard lock(s_queue_mutex); - if (priority == Priority::High) { - s_high_priority_queue.emplace_back( - ScheduledTask{tag, schedule, std::move(task)}); - } else { - s_normal_priority_queue.emplace_back( - ScheduledTask{tag, schedule, std::move(task)}); - } - } - s_wake_condition.notify_one(); -} -auto AsyncOps::cancel_tasks_of_tag(const TaskTag tag) -> void { - const std::lock_guard lock(s_queue_mutex); - - { - MutRef> queue = s_high_priority_queue; - for (Mut::iterator> it = queue.begin(); - it != queue.end(); - /* no incr */) { - if (it->tag == tag) { - if (it->schedule_handle->counter.fetch_sub(1) == 1) { - it->schedule_handle->counter.notify_all(); - } - it = queue.erase(it); - } else { - ++it; - } - } - } - - { - MutRef> queue = s_normal_priority_queue; - for (Mut::iterator> it = queue.begin(); - it != queue.end(); - /* no incr */) { - if (it->tag == tag) { - if (it->schedule_handle->counter.fetch_sub(1) == 1) { - it->schedule_handle->counter.notify_all(); - } - it = queue.erase(it); - } else { - ++it; - } - } - } -} - -auto AsyncOps::wait_for_schedule_completion(Schedule *schedule) -> void { - ensure(!s_schedule_workers.empty(), "Scheduler must be initialized before " - "calling wait_for_schedule_completion"); - - while (schedule->counter.load() > 0) { - Mut task; - Mut found_task = false; { - Mut> lock(s_queue_mutex); - if (!s_high_priority_queue.empty()) { - task = std::move(s_high_priority_queue.front()); - s_high_priority_queue.pop_front(); - found_task = true; - } else if (!s_normal_priority_queue.empty()) { - task = std::move(s_normal_priority_queue.front()); - s_normal_priority_queue.pop_front(); - found_task = true; + MutRef> queue = s_high_priority_queue; + for (Mut::iterator> it = queue.begin(); it != queue.end(); + /* no incr */) + { + if (it->tag == tag) + { + if (it->schedule_handle->counter.fetch_sub(1) == 1) + { + it->schedule_handle->counter.notify_all(); + } + it = queue.erase(it); + } + else + { + ++it; + } } } - if (found_task) { - task.task(MAIN_THREAD_WORKER_ID); - if (task.schedule_handle->counter.fetch_sub(1) == 1) { - task.schedule_handle->counter.notify_all(); - } - } else { - const u32 current_val = schedule->counter.load(); - if (current_val > 0) { - schedule->counter.wait(current_val); - } - } - } -} - -auto AsyncOps::get_worker_count() -> WorkerId { - return static_cast(s_schedule_workers.size()); -} - -auto AsyncOps::schedule_worker_loop(const std::stop_token stop_token, - const WorkerId worker_id) -> void { - while (!stop_token.stop_requested()) { - Mut task; - Mut found_task = false; { - Mut> lock(s_queue_mutex); - - s_wake_condition.wait(lock, [&stop_token] { - return !s_high_priority_queue.empty() || - !s_normal_priority_queue.empty() || stop_token.stop_requested(); - }); - - if (stop_token.stop_requested() && s_high_priority_queue.empty() && - s_normal_priority_queue.empty()) { - return; - } - - if (!s_high_priority_queue.empty()) { - task = std::move(s_high_priority_queue.front()); - s_high_priority_queue.pop_front(); - found_task = true; - } else if (!s_normal_priority_queue.empty()) { - task = std::move(s_normal_priority_queue.front()); - s_normal_priority_queue.pop_front(); - found_task = true; - } - } - - if (found_task) { - task.task(worker_id); - if (task.schedule_handle->counter.fetch_sub(1) == 1) { - task.schedule_handle->counter.notify_all(); + MutRef> queue = s_normal_priority_queue; + for (Mut::iterator> it = queue.begin(); it != queue.end(); + /* no incr */) + { + if (it->tag == tag) + { + if (it->schedule_handle->counter.fetch_sub(1) == 1) + { + it->schedule_handle->counter.notify_all(); + } + it = queue.erase(it); + } + else + { + ++it; + } + } + } + } + + auto AsyncOps::wait_for_schedule_completion(Schedule *schedule) -> void + { + ensure(!s_schedule_workers.empty(), "Scheduler must be initialized before " + "calling wait_for_schedule_completion"); + + while (schedule->counter.load() > 0) + { + Mut task; + Mut found_task = false; + { + Mut> lock(s_queue_mutex); + if (!s_high_priority_queue.empty()) + { + task = std::move(s_high_priority_queue.front()); + s_high_priority_queue.pop_front(); + found_task = true; + } + else if (!s_normal_priority_queue.empty()) + { + task = std::move(s_normal_priority_queue.front()); + s_normal_priority_queue.pop_front(); + found_task = true; + } + } + + if (found_task) + { + task.task(MAIN_THREAD_WORKER_ID); + if (task.schedule_handle->counter.fetch_sub(1) == 1) + { + task.schedule_handle->counter.notify_all(); + } + } + else + { + const u32 current_val = schedule->counter.load(); + if (current_val > 0) + { + schedule->counter.wait(current_val); + } + } + } + } + + auto AsyncOps::get_worker_count() -> WorkerId + { + return static_cast(s_schedule_workers.size()); + } + + auto AsyncOps::schedule_worker_loop(const std::stop_token stop_token, const WorkerId worker_id) -> void + { + while (!stop_token.stop_requested()) + { + Mut task; + Mut found_task = false; + { + Mut> lock(s_queue_mutex); + + s_wake_condition.wait(lock, [&stop_token] { + return !s_high_priority_queue.empty() || !s_normal_priority_queue.empty() || stop_token.stop_requested(); + }); + + if (stop_token.stop_requested() && s_high_priority_queue.empty() && s_normal_priority_queue.empty()) + { + return; + } + + if (!s_high_priority_queue.empty()) + { + task = std::move(s_high_priority_queue.front()); + s_high_priority_queue.pop_front(); + found_task = true; + } + else if (!s_normal_priority_queue.empty()) + { + task = std::move(s_normal_priority_queue.front()); + s_normal_priority_queue.pop_front(); + found_task = true; + } + } + + if (found_task) + { + task.task(worker_id); + if (task.schedule_handle->counter.fetch_sub(1) == 1) + { + task.schedule_handle->counter.notify_all(); + } } } } -} } // namespace IACore \ No newline at end of file diff --git a/Src/IACore/imp/cpp/CLI.cpp b/Src/IACore/imp/cpp/CLI.cpp index 37f3a32..c14ec99 100644 --- a/Src/IACore/imp/cpp/CLI.cpp +++ b/Src/IACore/imp/cpp/CLI.cpp @@ -15,13 +15,16 @@ #include -namespace IACore { -CLIParser::CLIParser(const Span args) : m_arg_list(args) { - m_current_arg = m_arg_list.begin(); +namespace IACore +{ + CLIParser::CLIParser(const Span args) : m_arg_list(args) + { + m_current_arg = m_arg_list.begin(); - // Skip executable path - if (m_current_arg != m_arg_list.end()) { - m_current_arg++; + // Skip executable path + if (m_current_arg != m_arg_list.end()) + { + m_current_arg++; + } } -} } // namespace IACore \ No newline at end of file diff --git a/Src/IACore/imp/cpp/DataOps.cpp b/Src/IACore/imp/cpp/DataOps.cpp index eab4d1c..e824e60 100644 --- a/Src/IACore/imp/cpp/DataOps.cpp +++ b/Src/IACore/imp/cpp/DataOps.cpp @@ -22,429 +22,471 @@ #include #if IA_ARCH_X64 -#include +# include #endif #if IA_ARCH_ARM64 -#include +# include #endif -namespace IACore { -template -[[nodiscard]] inline auto read_unaligned(const u8 *ptr) -> T { - Mut v; - std::memcpy(&v, ptr, sizeof(T)); - return v; -} - -struct Crc32Tables { - Mut table[8][256] = {}; - - consteval Crc32Tables() { - constexpr const u32 T = 0x82F63B78; - - for (Mut i = 0; i < 256; i++) { - Mut crc = i; - for (Mut j = 0; j < 8; j++) { - crc = (crc >> 1) ^ ((crc & 1) ? T : 0); - } - table[0][i] = crc; - } - - for (Mut i = 0; i < 256; i++) { - for (Mut slice = 1; slice < 8; slice++) { - const u32 prev = table[slice - 1][i]; - table[slice][i] = (prev >> 8) ^ table[0][prev & 0xFF]; - } - } +namespace IACore +{ + template [[nodiscard]] inline auto read_unaligned(const u8 *ptr) -> T + { + Mut v; + std::memcpy(&v, ptr, sizeof(T)); + return v; } -}; -static constexpr const Crc32Tables CRC32_TABLES{}; + struct Crc32Tables + { + Mut table[8][256] = {}; + + consteval Crc32Tables() + { + constexpr const u32 T = 0x82F63B78; + + for (Mut i = 0; i < 256; i++) + { + Mut crc = i; + for (Mut j = 0; j < 8; j++) + { + crc = (crc >> 1) ^ ((crc & 1) ? T : 0); + } + table[0][i] = crc; + } + + for (Mut i = 0; i < 256; i++) + { + for (Mut slice = 1; slice < 8; slice++) + { + const u32 prev = table[slice - 1][i]; + table[slice][i] = (prev >> 8) ^ table[0][prev & 0xFF]; + } + } + } + }; + + static constexpr const Crc32Tables CRC32_TABLES{}; #if IA_ARCH_X64 -inline auto crc32_x64_hw(Ref> data) -> u32 { - Mut p = data.data(); + inline auto crc32_x64_hw(Ref> data) -> u32 + { + Mut p = data.data(); - Mut crc = 0xFFFFFFFF; - Mut len = data.size(); + Mut crc = 0xFFFFFFFF; + Mut len = data.size(); - while (len >= 8) { - const u64 chunk = read_unaligned(p); - crc = static_cast(_mm_crc32_u64(static_cast(crc), chunk)); - p += 8; - len -= 8; + while (len >= 8) + { + const u64 chunk = read_unaligned(p); + crc = static_cast(_mm_crc32_u64(static_cast(crc), chunk)); + p += 8; + len -= 8; + } + + while (len--) + { + crc = _mm_crc32_u8(crc, *p++); + } + + return ~crc; } - - while (len--) { - crc = _mm_crc32_u8(crc, *p++); - } - - return ~crc; -} #endif #if IA_ARCH_ARM64 -__attribute__((target("+crc"))) inline auto -crc32_arm64_hw(Ref> data) -> u32 { - Mut p = data.data(); + __attribute__((target("+crc"))) inline auto crc32_arm64_hw(Ref> data) -> u32 + { + Mut p = data.data(); - Mut crc = 0xFFFFFFFF; - Mut len = data.size(); + Mut crc = 0xFFFFFFFF; + Mut len = data.size(); - while (len >= 8) { - const u64 chunk = read_unaligned(p); - crc = __crc32cd(crc, chunk); - p += 8; - len -= 8; + while (len >= 8) + { + const u64 chunk = read_unaligned(p); + crc = __crc32cd(crc, chunk); + p += 8; + len -= 8; + } + + while (len--) + { + crc = __crc32cb(crc, *p++); + } + + return ~crc; } - - while (len--) { - crc = __crc32cb(crc, *p++); - } - - return ~crc; -} #endif -inline auto crc32_software_slice8(Ref> data) -> u32 { - Mut p = data.data(); - Mut crc = 0xFFFFFFFF; - Mut len = data.size(); + inline auto crc32_software_slice8(Ref> data) -> u32 + { + Mut p = data.data(); + Mut crc = 0xFFFFFFFF; + Mut len = data.size(); - while (len >= 8) { - const u32 term1 = crc ^ read_unaligned(p); - const u32 term2 = read_unaligned(p + 4); + while (len >= 8) + { + const u32 term1 = crc ^ read_unaligned(p); + const u32 term2 = read_unaligned(p + 4); - crc = CRC32_TABLES.table[7][term1 & 0xFF] ^ - CRC32_TABLES.table[6][(term1 >> 8) & 0xFF] ^ - CRC32_TABLES.table[5][(term1 >> 16) & 0xFF] ^ - CRC32_TABLES.table[4][(term1 >> 24)] ^ - CRC32_TABLES.table[3][term2 & 0xFF] ^ - CRC32_TABLES.table[2][(term2 >> 8) & 0xFF] ^ - CRC32_TABLES.table[1][(term2 >> 16) & 0xFF] ^ - CRC32_TABLES.table[0][(term2 >> 24)]; + crc = CRC32_TABLES.table[7][term1 & 0xFF] ^ CRC32_TABLES.table[6][(term1 >> 8) & 0xFF] ^ + CRC32_TABLES.table[5][(term1 >> 16) & 0xFF] ^ CRC32_TABLES.table[4][(term1 >> 24)] ^ + CRC32_TABLES.table[3][term2 & 0xFF] ^ CRC32_TABLES.table[2][(term2 >> 8) & 0xFF] ^ + CRC32_TABLES.table[1][(term2 >> 16) & 0xFF] ^ CRC32_TABLES.table[0][(term2 >> 24)]; - p += 8; - len -= 8; + p += 8; + len -= 8; + } + + while (len--) + { + crc = (crc >> 8) ^ CRC32_TABLES.table[0][(crc ^ *p++) & 0xFF]; + } + + return ~crc; } - while (len--) { - crc = (crc >> 8) ^ CRC32_TABLES.table[0][(crc ^ *p++) & 0xFF]; - } - - return ~crc; -} - -auto DataOps::crc32(Ref> data) -> u32 { + auto DataOps::crc32(Ref> data) -> u32 + { #if IA_ARCH_X64 - // IACore mandates AVX2 so no need to check - return crc32_x64_hw(data); + // IACore mandates AVX2 so no need to check + return crc32_x64_hw(data); #elif IA_ARCH_ARM64 - if (Platform::GetCapabilities().HardwareCRC32) { - return crc32_arm64_hw(data); - } + if (Platform::GetCapabilities().HardwareCRC32) + { + return crc32_arm64_hw(data); + } #endif - return crc32_software_slice8(data); -} + return crc32_software_slice8(data); + } -constexpr const u32 XXH_PRIME32_1 = 0x9E3779B1U; -constexpr const u32 XXH_PRIME32_2 = 0x85EBCA77U; -constexpr const u32 XXH_PRIME32_3 = 0xC2B2AE3DU; -constexpr const u32 XXH_PRIME32_4 = 0x27D4EB2FU; -constexpr const u32 XXH_PRIME32_5 = 0x165667B1U; + constexpr const u32 XXH_PRIME32_1 = 0x9E3779B1U; + constexpr const u32 XXH_PRIME32_2 = 0x85EBCA77U; + constexpr const u32 XXH_PRIME32_3 = 0xC2B2AE3DU; + constexpr const u32 XXH_PRIME32_4 = 0x27D4EB2FU; + constexpr const u32 XXH_PRIME32_5 = 0x165667B1U; -inline auto xxh32_round(Mut seed, const u32 input) -> u32 { - seed += input * XXH_PRIME32_2; - seed = std::rotl(seed, 13); - seed *= XXH_PRIME32_1; - return seed; -} + inline auto xxh32_round(Mut seed, const u32 input) -> u32 + { + seed += input * XXH_PRIME32_2; + seed = std::rotl(seed, 13); + seed *= XXH_PRIME32_1; + return seed; + } -auto DataOps::hash_xxhash(Ref string, const u32 seed) -> u32 { - return hash_xxhash(Span(reinterpret_cast(string.data()), - string.length()), - seed); -} + auto DataOps::hash_xxhash(Ref string, const u32 seed) -> u32 + { + return hash_xxhash(Span(reinterpret_cast(string.data()), string.length()), seed); + } -auto DataOps::hash_xxhash(Ref> data, const u32 seed) -> u32 { - Mut p = data.data(); - const u8 *b_end = p + data.size(); - Mut h32{}; + auto DataOps::hash_xxhash(Ref> data, const u32 seed) -> u32 + { + Mut p = data.data(); + const u8 *b_end = p + data.size(); + Mut h32{}; - if (data.size() >= 16) { - const u8 *limit = b_end - 16; + if (data.size() >= 16) + { + const u8 *limit = b_end - 16; - Mut v1 = seed + XXH_PRIME32_1 + XXH_PRIME32_2; - Mut v2 = seed + XXH_PRIME32_2; - Mut v3 = seed + 0; - Mut v4 = seed - XXH_PRIME32_1; + Mut v1 = seed + XXH_PRIME32_1 + XXH_PRIME32_2; + Mut v2 = seed + XXH_PRIME32_2; + Mut v3 = seed + 0; + Mut v4 = seed - XXH_PRIME32_1; - do { - v1 = xxh32_round(v1, read_unaligned(p)); + do + { + v1 = xxh32_round(v1, read_unaligned(p)); + p += 4; + v2 = xxh32_round(v2, read_unaligned(p)); + p += 4; + v3 = xxh32_round(v3, read_unaligned(p)); + p += 4; + v4 = xxh32_round(v4, read_unaligned(p)); + p += 4; + } while (p <= limit); + + h32 = std::rotl(v1, 1) + std::rotl(v2, 7) + std::rotl(v3, 12) + std::rotl(v4, 18); + } + else + { + h32 = seed + XXH_PRIME32_5; + } + + h32 += static_cast(data.size()); + + while (p + 4 <= b_end) + { + const u32 t = read_unaligned(p) * XXH_PRIME32_3; + h32 += t; + h32 = std::rotl(h32, 17) * XXH_PRIME32_4; p += 4; - v2 = xxh32_round(v2, read_unaligned(p)); - p += 4; - v3 = xxh32_round(v3, read_unaligned(p)); - p += 4; - v4 = xxh32_round(v4, read_unaligned(p)); - p += 4; - } while (p <= limit); + } - h32 = std::rotl(v1, 1) + std::rotl(v2, 7) + std::rotl(v3, 12) + - std::rotl(v4, 18); - } else { - h32 = seed + XXH_PRIME32_5; + while (p < b_end) + { + h32 += (*p++) * XXH_PRIME32_5; + h32 = std::rotl(h32, 11) * XXH_PRIME32_1; + } + + h32 ^= h32 >> 15; + h32 *= XXH_PRIME32_2; + h32 ^= h32 >> 13; + h32 *= XXH_PRIME32_3; + h32 ^= h32 >> 16; + + return h32; } - h32 += static_cast(data.size()); + constexpr const u32 FNV1A_32_PRIME = 0x01000193; + constexpr const u32 FNV1A_32_OFFSET = 0x811c9dc5; - while (p + 4 <= b_end) { - const u32 t = read_unaligned(p) * XXH_PRIME32_3; - h32 += t; - h32 = std::rotl(h32, 17) * XXH_PRIME32_4; - p += 4; + auto DataOps::hash_fnv1a(Ref string) -> u32 + { + Mut hash = FNV1A_32_OFFSET; + for (const char c : string) + { + hash ^= static_cast(c); + hash *= FNV1A_32_PRIME; + } + return hash; } - while (p < b_end) { - h32 += (*p++) * XXH_PRIME32_5; - h32 = std::rotl(h32, 11) * XXH_PRIME32_1; + auto DataOps::hash_fnv1a(Ref> data) -> u32 + { + Mut hash = FNV1A_32_OFFSET; + const u8 *ptr = data.data(); + + for (Mut i = 0; i < data.size(); ++i) + { + hash ^= ptr[i]; + hash *= FNV1A_32_PRIME; + } + return hash; } - h32 ^= h32 >> 15; - h32 *= XXH_PRIME32_2; - h32 ^= h32 >> 13; - h32 *= XXH_PRIME32_3; - h32 ^= h32 >> 16; + auto DataOps::detect_compression(const Span data) -> CompressionType + { + if (data.size() < 2) + { + return CompressionType::None; + } - return h32; -} + if (data[0] == 0x1F && data[1] == 0x8B) + { + return CompressionType::Gzip; + } -constexpr const u32 FNV1A_32_PRIME = 0x01000193; -constexpr const u32 FNV1A_32_OFFSET = 0x811c9dc5; + if (data[0] == 0x78 && (data[1] == 0x01 || data[1] == 0x9C || data[1] == 0xDA)) + { + return CompressionType::Zlib; + } -auto DataOps::hash_fnv1a(Ref string) -> u32 { - Mut hash = FNV1A_32_OFFSET; - for (const char c : string) { - hash ^= static_cast(c); - hash *= FNV1A_32_PRIME; - } - return hash; -} - -auto DataOps::hash_fnv1a(Ref> data) -> u32 { - Mut hash = FNV1A_32_OFFSET; - const u8 *ptr = data.data(); - - for (Mut i = 0; i < data.size(); ++i) { - hash ^= ptr[i]; - hash *= FNV1A_32_PRIME; - } - return hash; -} - -auto DataOps::detect_compression(const Span data) -> CompressionType { - if (data.size() < 2) { return CompressionType::None; } - if (data[0] == 0x1F && data[1] == 0x8B) { - return CompressionType::Gzip; - } + auto DataOps::zlib_inflate(Ref> data) -> Result> + { + Mut zs{}; + zs.zalloc = Z_NULL; + zs.zfree = Z_NULL; + zs.opaque = Z_NULL; - if (data[0] == 0x78 && - (data[1] == 0x01 || data[1] == 0x9C || data[1] == 0xDA)) { - return CompressionType::Zlib; - } - - return CompressionType::None; -} - -auto DataOps::zlib_inflate(Ref> data) -> Result> { - Mut zs{}; - zs.zalloc = Z_NULL; - zs.zfree = Z_NULL; - zs.opaque = Z_NULL; - - if (inflateInit2(&zs, 15 + 32) != Z_OK) { - return fail("Failed to initialize zlib inflate"); - } - - zs.next_in = const_cast(data.data()); - zs.avail_in = static_cast(data.size()); - - Mut> out_buffer; - const usize guess_size = - data.size() < 1024 ? data.size() * 4 : data.size() * 2; - out_buffer.resize(guess_size); - - zs.next_out = reinterpret_cast(out_buffer.data()); - zs.avail_out = static_cast(out_buffer.size()); - - Mut ret; - do { - if (zs.avail_out == 0) { - const usize current_pos = zs.total_out; - const usize new_size = out_buffer.size() * 2; - out_buffer.resize(new_size); - - zs.next_out = reinterpret_cast(out_buffer.data() + current_pos); - zs.avail_out = static_cast(new_size - current_pos); + if (inflateInit2(&zs, 15 + 32) != Z_OK) + { + return fail("Failed to initialize zlib inflate"); } - ret = inflate(&zs, Z_NO_FLUSH); + zs.next_in = const_cast(data.data()); + zs.avail_in = static_cast(data.size()); - } while (ret == Z_OK); - - inflateEnd(&zs); - - if (ret != Z_STREAM_END) { - return fail("Failed to inflate: corrupt data or stream error"); - } - - out_buffer.resize(zs.total_out); - - return out_buffer; -} - -auto DataOps::zlib_deflate(Ref> data) -> Result> { - Mut zs{}; - zs.zalloc = Z_NULL; - zs.zfree = Z_NULL; - zs.opaque = Z_NULL; - - if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) != Z_OK) { - return fail("Failed to initialize zlib deflate"); - } - - zs.next_in = const_cast(data.data()); - zs.avail_in = static_cast(data.size()); - - Mut> out_buffer; - out_buffer.resize(deflateBound(&zs, static_cast(data.size()))); - - zs.next_out = reinterpret_cast(out_buffer.data()); - zs.avail_out = static_cast(out_buffer.size()); - - const int ret = deflate(&zs, Z_FINISH); - - if (ret != Z_STREAM_END) { - deflateEnd(&zs); - return fail("Failed to deflate, ran out of buffer memory"); - } - - out_buffer.resize(zs.total_out); - - deflateEnd(&zs); - return out_buffer; -} - -auto DataOps::zstd_inflate(Ref> data) -> Result> { - const unsigned long long content_size = - ZSTD_getFrameContentSize(data.data(), data.size()); - - if (content_size == ZSTD_CONTENTSIZE_ERROR) { - return fail("Failed to inflate: Not valid ZSTD compressed data"); - } - - if (content_size != ZSTD_CONTENTSIZE_UNKNOWN) { Mut> out_buffer; - out_buffer.resize(static_cast(content_size)); + const usize guess_size = data.size() < 1024 ? data.size() * 4 : data.size() * 2; + out_buffer.resize(guess_size); - const usize d_size = ZSTD_decompress(out_buffer.data(), out_buffer.size(), - data.data(), data.size()); + zs.next_out = reinterpret_cast(out_buffer.data()); + zs.avail_out = static_cast(out_buffer.size()); - if (ZSTD_isError(d_size)) { - return fail("Failed to inflate: {}", ZSTD_getErrorName(d_size)); + Mut ret; + do + { + if (zs.avail_out == 0) + { + const usize current_pos = zs.total_out; + const usize new_size = out_buffer.size() * 2; + out_buffer.resize(new_size); + + zs.next_out = reinterpret_cast(out_buffer.data() + current_pos); + zs.avail_out = static_cast(new_size - current_pos); + } + + ret = inflate(&zs, Z_NO_FLUSH); + + } while (ret == Z_OK); + + inflateEnd(&zs); + + if (ret != Z_STREAM_END) + { + return fail("Failed to inflate: corrupt data or stream error"); } + out_buffer.resize(zs.total_out); + return out_buffer; } - Mut dctx = ZSTD_createDCtx(); - Mut> out_buffer; - out_buffer.resize(data.size() * 2); + auto DataOps::zlib_deflate(Ref> data) -> Result> + { + Mut zs{}; + zs.zalloc = Z_NULL; + zs.zfree = Z_NULL; + zs.opaque = Z_NULL; - Mut input = {data.data(), data.size(), 0}; - Mut output = {out_buffer.data(), out_buffer.size(), 0}; - - Mut ret; - do { - ret = ZSTD_decompressStream(dctx, &output, &input); - - if (ZSTD_isError(ret)) { - ZSTD_freeDCtx(dctx); - return fail("Failed to inflate: {}", ZSTD_getErrorName(ret)); + if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) != Z_OK) + { + return fail("Failed to initialize zlib deflate"); } - if (output.pos == output.size) { - const usize new_size = out_buffer.size() * 2; - out_buffer.resize(new_size); - output.dst = out_buffer.data(); - output.size = new_size; + zs.next_in = const_cast(data.data()); + zs.avail_in = static_cast(data.size()); + + Mut> out_buffer; + out_buffer.resize(deflateBound(&zs, static_cast(data.size()))); + + zs.next_out = reinterpret_cast(out_buffer.data()); + zs.avail_out = static_cast(out_buffer.size()); + + const int ret = deflate(&zs, Z_FINISH); + + if (ret != Z_STREAM_END) + { + deflateEnd(&zs); + return fail("Failed to deflate, ran out of buffer memory"); } - } while (ret != 0); + out_buffer.resize(zs.total_out); - out_buffer.resize(output.pos); - ZSTD_freeDCtx(dctx); - - return out_buffer; -} - -auto DataOps::zstd_deflate(Ref> data) -> Result> { - const usize max_dst_size = ZSTD_compressBound(data.size()); - - Mut> out_buffer; - out_buffer.resize(max_dst_size); - - const usize compressed_size = ZSTD_compress(out_buffer.data(), max_dst_size, - data.data(), data.size(), 3); - - if (ZSTD_isError(compressed_size)) { - return fail("Failed to deflate: {}", ZSTD_getErrorName(compressed_size)); - } - - out_buffer.resize(compressed_size); - return out_buffer; -} - -auto DataOps::gzip_deflate(Ref> data) -> Result> { - Mut zs{}; - zs.zalloc = Z_NULL; - zs.zfree = Z_NULL; - zs.opaque = Z_NULL; - - if (deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 + 16, 8, - Z_DEFAULT_STRATEGY) != Z_OK) { - return fail("Failed to initialize gzip deflate"); - } - - zs.next_in = const_cast(data.data()); - zs.avail_in = static_cast(data.size()); - - Mut> out_buffer; - - out_buffer.resize(deflateBound(&zs, static_cast(data.size())) + 1024); - - zs.next_out = reinterpret_cast(out_buffer.data()); - zs.avail_out = static_cast(out_buffer.size()); - - const int ret = deflate(&zs, Z_FINISH); - - if (ret != Z_STREAM_END) { deflateEnd(&zs); - return fail("Failed to deflate"); + return out_buffer; } - out_buffer.resize(zs.total_out); + auto DataOps::zstd_inflate(Ref> data) -> Result> + { + const unsigned long long content_size = ZSTD_getFrameContentSize(data.data(), data.size()); - deflateEnd(&zs); - return out_buffer; -} + if (content_size == ZSTD_CONTENTSIZE_ERROR) + { + return fail("Failed to inflate: Not valid ZSTD compressed data"); + } -auto DataOps::gzip_inflate(Ref> data) -> Result> { - return zlib_inflate(data); -} + if (content_size != ZSTD_CONTENTSIZE_UNKNOWN) + { + Mut> out_buffer; + out_buffer.resize(static_cast(content_size)); + + const usize d_size = ZSTD_decompress(out_buffer.data(), out_buffer.size(), data.data(), data.size()); + + if (ZSTD_isError(d_size)) + { + return fail("Failed to inflate: {}", ZSTD_getErrorName(d_size)); + } + + return out_buffer; + } + + Mut dctx = ZSTD_createDCtx(); + Mut> out_buffer; + out_buffer.resize(data.size() * 2); + + Mut input = {data.data(), data.size(), 0}; + Mut output = {out_buffer.data(), out_buffer.size(), 0}; + + Mut ret; + do + { + ret = ZSTD_decompressStream(dctx, &output, &input); + + if (ZSTD_isError(ret)) + { + ZSTD_freeDCtx(dctx); + return fail("Failed to inflate: {}", ZSTD_getErrorName(ret)); + } + + if (output.pos == output.size) + { + const usize new_size = out_buffer.size() * 2; + out_buffer.resize(new_size); + output.dst = out_buffer.data(); + output.size = new_size; + } + + } while (ret != 0); + + out_buffer.resize(output.pos); + ZSTD_freeDCtx(dctx); + + return out_buffer; + } + + auto DataOps::zstd_deflate(Ref> data) -> Result> + { + const usize max_dst_size = ZSTD_compressBound(data.size()); + + Mut> out_buffer; + out_buffer.resize(max_dst_size); + + const usize compressed_size = ZSTD_compress(out_buffer.data(), max_dst_size, data.data(), data.size(), 3); + + if (ZSTD_isError(compressed_size)) + { + return fail("Failed to deflate: {}", ZSTD_getErrorName(compressed_size)); + } + + out_buffer.resize(compressed_size); + return out_buffer; + } + + auto DataOps::gzip_deflate(Ref> data) -> Result> + { + Mut zs{}; + zs.zalloc = Z_NULL; + zs.zfree = Z_NULL; + zs.opaque = Z_NULL; + + if (deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 + 16, 8, Z_DEFAULT_STRATEGY) != Z_OK) + { + return fail("Failed to initialize gzip deflate"); + } + + zs.next_in = const_cast(data.data()); + zs.avail_in = static_cast(data.size()); + + Mut> out_buffer; + + out_buffer.resize(deflateBound(&zs, static_cast(data.size())) + 1024); + + zs.next_out = reinterpret_cast(out_buffer.data()); + zs.avail_out = static_cast(out_buffer.size()); + + const int ret = deflate(&zs, Z_FINISH); + + if (ret != Z_STREAM_END) + { + deflateEnd(&zs); + return fail("Failed to deflate"); + } + + out_buffer.resize(zs.total_out); + + deflateEnd(&zs); + return out_buffer; + } + + auto DataOps::gzip_inflate(Ref> data) -> Result> + { + return zlib_inflate(data); + } } // namespace IACore \ No newline at end of file diff --git a/Src/IACore/imp/cpp/FileOps.cpp b/Src/IACore/imp/cpp/FileOps.cpp index 19e2ffb..f515aa6 100644 --- a/Src/IACore/imp/cpp/FileOps.cpp +++ b/Src/IACore/imp/cpp/FileOps.cpp @@ -18,522 +18,582 @@ #include #if IA_PLATFORM_UNIX -#include -#include -#include -#include +# include +# include +# include +# include #endif -namespace IACore { +namespace IACore +{ -Mut>> - FileOps::s_mapped_files; + Mut>> FileOps::s_mapped_files; -auto FileOps::unmap_file(const u8 *mapped_ptr) -> void { - if (!s_mapped_files.contains(mapped_ptr)) { - return; - } + auto FileOps::unmap_file(const u8 *mapped_ptr) -> void + { + if (!s_mapped_files.contains(mapped_ptr)) + { + return; + } - Mut it = s_mapped_files.find(mapped_ptr); - const std::tuple handles = it->second; - s_mapped_files.erase(it); + Mut it = s_mapped_files.find(mapped_ptr); + const std::tuple handles = it->second; + s_mapped_files.erase(it); #if IA_PLATFORM_WINDOWS - ::UnmapViewOfFile(std::get<1>(handles)); - ::CloseHandle(static_cast(std::get<2>(handles))); + ::UnmapViewOfFile(std::get<1>(handles)); + ::CloseHandle(static_cast(std::get<2>(handles))); - const HANDLE handle = static_cast(std::get<0>(handles)); - if (handle != INVALID_HANDLE_VALUE) { - ::CloseHandle(handle); - } + const HANDLE handle = static_cast(std::get<0>(handles)); + if (handle != INVALID_HANDLE_VALUE) + { + ::CloseHandle(handle); + } #elif IA_PLATFORM_UNIX - ::munmap(std::get<1>(handles), (usize)std::get<2>(handles)); - const i32 fd = (i32)((u64)std::get<0>(handles)); - if (fd != -1) { - ::close(fd); - } + ::munmap(std::get<1>(handles), (usize) std::get<2>(handles)); + const i32 fd = (i32) ((u64) std::get<0>(handles)); + if (fd != -1) + { + ::close(fd); + } #endif -} + } -auto FileOps::map_shared_memory(Ref name, const usize size, - const bool is_owner) -> Result { + auto FileOps::map_shared_memory(Ref name, const usize size, const bool is_owner) -> Result + { #if IA_PLATFORM_WINDOWS - const int wchars_num = - MultiByteToWideChar(CP_UTF8, 0, name.c_str(), -1, NULL, 0); - Mut w_name(wchars_num, 0); - MultiByteToWideChar(CP_UTF8, 0, name.c_str(), -1, &w_name[0], wchars_num); + const int wchars_num = MultiByteToWideChar(CP_UTF8, 0, name.c_str(), -1, NULL, 0); + Mut w_name(wchars_num, 0); + MultiByteToWideChar(CP_UTF8, 0, name.c_str(), -1, &w_name[0], wchars_num); - Mut h_map = NULL; - if (is_owner) { - h_map = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, - (DWORD)(size >> 32), (DWORD)(size & 0xFFFFFFFF), - w_name.c_str()); - } else { - h_map = OpenFileMappingW(FILE_MAP_ALL_ACCESS, false, w_name.c_str()); - } + Mut h_map = NULL; + if (is_owner) + { + h_map = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, (DWORD) (size >> 32), + (DWORD) (size & 0xFFFFFFFF), w_name.c_str()); + } + else + { + h_map = OpenFileMappingW(FILE_MAP_ALL_ACCESS, false, w_name.c_str()); + } - if (h_map == NULL) { - return fail("Failed to {} shared memory '{}'", - is_owner ? "owner" : "consumer", name); - } + if (h_map == NULL) + { + return fail("Failed to {} shared memory '{}'", is_owner ? "owner" : "consumer", name); + } - Mut result = - static_cast(MapViewOfFile(h_map, FILE_MAP_ALL_ACCESS, 0, 0, size)); - if (result == NULL) { - CloseHandle(h_map); - return fail("Failed to map view of shared memory '{}'", name); - } + Mut result = static_cast(MapViewOfFile(h_map, FILE_MAP_ALL_ACCESS, 0, 0, size)); + if (result == NULL) + { + CloseHandle(h_map); + return fail("Failed to map view of shared memory '{}'", name); + } - s_mapped_files[result] = std::make_tuple((void *)INVALID_HANDLE_VALUE, - (void *)result, (void *)h_map); - return result; + s_mapped_files[result] = std::make_tuple((void *) INVALID_HANDLE_VALUE, (void *) result, (void *) h_map); + return result; #elif IA_PLATFORM_UNIX - Mut fd = -1; - if (is_owner) { - fd = shm_open(name.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0666); - if (fd != -1) { - if (ftruncate(fd, size) == -1) { - close(fd); - shm_unlink(name.c_str()); - return fail("Failed to truncate shared memory '{}'", name); + Mut fd = -1; + if (is_owner) + { + fd = shm_open(name.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0666); + if (fd != -1) + { + if (ftruncate(fd, size) == -1) + { + close(fd); + shm_unlink(name.c_str()); + return fail("Failed to truncate shared memory '{}'", name); + } } } - } else { - fd = shm_open(name.c_str(), O_RDWR, 0666); - } + else + { + fd = shm_open(name.c_str(), O_RDWR, 0666); + } - if (fd == -1) { - return fail("Failed to {} shared memory '{}'", - is_owner ? "owner" : "consumer", name); - } + if (fd == -1) + { + return fail("Failed to {} shared memory '{}'", is_owner ? "owner" : "consumer", name); + } - Mut addr = - mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (addr == MAP_FAILED) { - close(fd); - return fail("Failed to mmap shared memory '{}'", name); - } + Mut addr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (addr == MAP_FAILED) + { + close(fd); + return fail("Failed to mmap shared memory '{}'", name); + } - Mut result = static_cast(addr); + Mut result = static_cast(addr); - s_mapped_files[result] = - std::make_tuple((void *)((u64)fd), (void *)addr, (void *)size); - return result; + s_mapped_files[result] = std::make_tuple((void *) ((u64) fd), (void *) addr, (void *) size); + return result; #endif -} - -auto FileOps::unlink_shared_memory(Ref name) -> void { - if (name.empty()) { - return; } + + auto FileOps::unlink_shared_memory(Ref name) -> void + { + if (name.empty()) + { + return; + } #if IA_PLATFORM_UNIX - shm_unlink(name.c_str()); + shm_unlink(name.c_str()); #endif -} + } -auto FileOps::map_file(Ref path, MutRef size) - -> Result { + auto FileOps::map_file(Ref path, MutRef size) -> Result + { #if IA_PLATFORM_WINDOWS - const HANDLE handle = CreateFileA( - path.string().c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); + const HANDLE handle = CreateFileA(path.string().c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); - if (handle == INVALID_HANDLE_VALUE) { - return fail("Failed to open {} for memory mapping", path.string()); - } + if (handle == INVALID_HANDLE_VALUE) + { + return fail("Failed to open {} for memory mapping", path.string()); + } - Mut file_size; - if (!GetFileSizeEx(handle, &file_size)) { - CloseHandle(handle); - return fail("Failed to get size of {} for memory mapping", path.string()); - } - size = static_cast(file_size.QuadPart); - if (size == 0) { - CloseHandle(handle); - return fail("Failed to get size of {} for memory mapping", path.string()); - } + Mut file_size; + if (!GetFileSizeEx(handle, &file_size)) + { + CloseHandle(handle); + return fail("Failed to get size of {} for memory mapping", path.string()); + } + size = static_cast(file_size.QuadPart); + if (size == 0) + { + CloseHandle(handle); + return fail("Failed to get size of {} for memory mapping", path.string()); + } - Mut h_map = - CreateFileMappingW(handle, NULL, PAGE_READONLY, 0, 0, NULL); - if (h_map == NULL) { - CloseHandle(handle); - return fail("Failed to memory map {}", path.string()); - } + Mut h_map = CreateFileMappingW(handle, NULL, PAGE_READONLY, 0, 0, NULL); + if (h_map == NULL) + { + CloseHandle(handle); + return fail("Failed to memory map {}", path.string()); + } - const u8 *result = - static_cast(MapViewOfFile(h_map, FILE_MAP_READ, 0, 0, 0)); - if (result == NULL) { - CloseHandle(handle); - CloseHandle(h_map); - return fail("Failed to memory map {}", path.string()); - } - s_mapped_files[result] = std::make_tuple( - (void *)handle, (void *)const_cast(result), (void *)h_map); - return result; + const u8 *result = static_cast(MapViewOfFile(h_map, FILE_MAP_READ, 0, 0, 0)); + if (result == NULL) + { + CloseHandle(handle); + CloseHandle(h_map); + return fail("Failed to memory map {}", path.string()); + } + s_mapped_files[result] = std::make_tuple((void *) handle, (void *) const_cast(result), (void *) h_map); + return result; #elif IA_PLATFORM_UNIX - const int handle = open(path.string().c_str(), O_RDONLY); - if (handle == -1) { - return fail("Failed to open {} for memory mapping", path.string()); - } - Mut sb; - if (fstat(handle, &sb) == -1) { - close(handle); - return fail("Failed to get stats of {} for memory mapping", path.string()); - } - size = static_cast(sb.st_size); - if (size == 0) { - close(handle); - return fail("Failed to get size of {} for memory mapping", path.string()); - } - Mut addr = mmap(nullptr, size, PROT_READ, MAP_PRIVATE, handle, 0); - if (addr == MAP_FAILED) { - close(handle); - return fail("Failed to memory map {}", path.string()); - } - const u8 *result = static_cast(addr); - madvise(addr, size, MADV_SEQUENTIAL); - s_mapped_files[result] = - std::make_tuple((void *)((u64)handle), (void *)addr, (void *)size); - return result; + const int handle = open(path.string().c_str(), O_RDONLY); + if (handle == -1) + { + return fail("Failed to open {} for memory mapping", path.string()); + } + Mut sb; + if (fstat(handle, &sb) == -1) + { + close(handle); + return fail("Failed to get stats of {} for memory mapping", path.string()); + } + size = static_cast(sb.st_size); + if (size == 0) + { + close(handle); + return fail("Failed to get size of {} for memory mapping", path.string()); + } + Mut addr = mmap(nullptr, size, PROT_READ, MAP_PRIVATE, handle, 0); + if (addr == MAP_FAILED) + { + close(handle); + return fail("Failed to memory map {}", path.string()); + } + const u8 *result = static_cast(addr); + madvise(addr, size, MADV_SEQUENTIAL); + s_mapped_files[result] = std::make_tuple((void *) ((u64) handle), (void *) addr, (void *) size); + return result; #endif -} + } -auto FileOps::stream_to_file(Ref path, const bool overwrite) - -> Result { - if (!overwrite && std::filesystem::exists(path)) { - return fail("File already exists: {}", path.string()); - } - return StreamWriter::create_from_file(path); -} - -auto FileOps::stream_from_file(Ref path) -> Result { - if (!std::filesystem::exists(path)) { - return fail("File does not exist: {}", path.string()); - } - return StreamReader::create_from_file(path); -} - -auto FileOps::read_text_file(Ref path) -> Result { - Mut f = fopen(path.string().c_str(), "r"); - if (!f) { - return fail("Failed to open file: {}", path.string()); - } - Mut result; - fseek(f, 0, SEEK_END); - const long len = ftell(f); - if (len > 0) { - result.resize(static_cast(len)); - fseek(f, 0, SEEK_SET); - fread(result.data(), 1, result.size(), f); - } - fclose(f); - return result; -} - -auto FileOps::read_binary_file(Ref path) -> Result> { - Mut f = fopen(path.string().c_str(), "rb"); - if (!f) { - return fail("Failed to open file: {}", path.string()); - } - Mut> result; - fseek(f, 0, SEEK_END); - const long len = ftell(f); - if (len > 0) { - result.resize(static_cast(len)); - fseek(f, 0, SEEK_SET); - fread(result.data(), 1, result.size(), f); - } - fclose(f); - return result; -} - -auto FileOps::write_text_file(Ref path, Ref contents, - const bool overwrite) -> Result { - const char *mode = overwrite ? "w" : "wx"; - Mut f = fopen(path.string().c_str(), mode); - if (!f) { - if (!overwrite && errno == EEXIST) { + auto FileOps::stream_to_file(Ref path, const bool overwrite) -> Result + { + if (!overwrite && std::filesystem::exists(path)) + { return fail("File already exists: {}", path.string()); } - return fail("Failed to write to file: {}", path.string()); + return StreamWriter::create_from_file(path); } - const usize result = fwrite(contents.data(), 1, contents.size(), f); - fclose(f); - return result; -} -auto FileOps::write_binary_file(Ref path, const Span contents, - const bool overwrite) -> Result { - const char *mode = overwrite ? "w" : "wx"; - Mut f = fopen(path.string().c_str(), mode); - if (!f) { - if (!overwrite && errno == EEXIST) { - return fail("File already exists: {}", path.string()); + auto FileOps::stream_from_file(Ref path) -> Result + { + if (!std::filesystem::exists(path)) + { + return fail("File does not exist: {}", path.string()); } - return fail("Failed to write to file: {}", path.string()); - } - const usize result = fwrite(contents.data(), 1, contents.size(), f); - fclose(f); - return result; -} - -auto FileOps::normalize_executable_path(Ref path) -> Path { - Mut result = path; - -#if IA_PLATFORM_WINDOWS - if (!result.has_extension()) { - result.replace_extension(".exe"); - } -#elif IA_PLATFORM_UNIX - if (result.extension() == ".exe") { - result.replace_extension(""); + return StreamReader::create_from_file(path); } - if (result.is_relative()) { - Mut path_str = result.string(); - if (!path_str.starts_with("./") && !path_str.starts_with("../")) { - result = "./" + path_str; + auto FileOps::read_text_file(Ref path) -> Result + { + Mut f = fopen(path.string().c_str(), "r"); + if (!f) + { + return fail("Failed to open file: {}", path.string()); } - } -#endif - return result; -} - -auto FileOps::native_open_file(Ref path, const FileAccess access, - const FileMode mode, const u32 permissions) - -> Result { -#if IA_PLATFORM_WINDOWS - Mut dw_access = 0; - Mut dw_share = FILE_SHARE_READ; - Mut dw_disposition = 0; - Mut dw_flags_and_attributes = FILE_ATTRIBUTE_NORMAL; - - switch (access) { - case FileAccess::Read: - dw_access = GENERIC_READ; - break; - case FileAccess::Write: - dw_access = GENERIC_WRITE; - break; - case FileAccess::ReadWrite: - dw_access = GENERIC_READ | GENERIC_WRITE; - break; + Mut result; + fseek(f, 0, SEEK_END); + const long len = ftell(f); + if (len > 0) + { + result.resize(static_cast(len)); + fseek(f, 0, SEEK_SET); + const usize read_length = fread(result.data(), 1, result.size(), f); + result.resize(read_length); + } + fclose(f); + return result; } - switch (mode) { - case FileMode::OpenExisting: - dw_disposition = OPEN_EXISTING; - break; - case FileMode::OpenAlways: - dw_disposition = OPEN_ALWAYS; - break; - case FileMode::CreateNew: - dw_disposition = CREATE_NEW; - break; - case FileMode::CreateAlways: - dw_disposition = CREATE_ALWAYS; - break; - case FileMode::TruncateExisting: - dw_disposition = TRUNCATE_EXISTING; - break; + auto FileOps::read_binary_file(Ref path) -> Result> + { + Mut f = fopen(path.string().c_str(), "rb"); + if (!f) + { + return fail("Failed to open file: {}", path.string()); + } + Mut> result; + fseek(f, 0, SEEK_END); + const long len = ftell(f); + if (len > 0) + { + result.resize(static_cast(len)); + fseek(f, 0, SEEK_SET); + fread(result.data(), 1, result.size(), f); + } + fclose(f); + return result; } - Mut h_file = - CreateFileA(path.string().c_str(), dw_access, dw_share, NULL, - dw_disposition, dw_flags_and_attributes, NULL); - - if (h_file == INVALID_HANDLE_VALUE) { - return fail("Failed to open file '{}': {}", path.string(), GetLastError()); + auto FileOps::write_text_file(Ref path, Ref contents, const bool overwrite) -> Result + { + const char *mode = overwrite ? "w" : "wx"; + Mut f = fopen(path.string().c_str(), mode); + if (!f) + { + if (!overwrite && errno == EEXIST) + { + return fail("File already exists: {}", path.string()); + } + return fail("Failed to write to file: {}", path.string()); + } + const usize result = fwrite(contents.data(), 1, contents.size(), f); + fclose(f); + return result; } - return h_file; - -#elif IA_PLATFORM_UNIX - Mut flags = 0; - - switch (access) { - case FileAccess::Read: - flags = O_RDONLY; - break; - case FileAccess::Write: - flags = O_WRONLY; - break; - case FileAccess::ReadWrite: - flags = O_RDWR; - break; + auto FileOps::write_binary_file(Ref path, const Span contents, const bool overwrite) -> Result + { + const char *mode = overwrite ? "w" : "wx"; + Mut f = fopen(path.string().c_str(), mode); + if (!f) + { + if (!overwrite && errno == EEXIST) + { + return fail("File already exists: {}", path.string()); + } + return fail("Failed to write to file: {}", path.string()); + } + const usize result = fwrite(contents.data(), 1, contents.size(), f); + fclose(f); + return result; } - switch (mode) { - case FileMode::OpenExisting: - break; - case FileMode::OpenAlways: - flags |= O_CREAT; - break; - case FileMode::CreateNew: - flags |= O_CREAT | O_EXCL; - break; - case FileMode::CreateAlways: - flags |= O_CREAT | O_TRUNC; - break; - case FileMode::TruncateExisting: - flags |= O_TRUNC; - break; - } - - Mut fd = open(path.string().c_str(), flags, permissions); - - if (fd == -1) { - return fail("Failed to open file '{}': {}", path.string(), errno); - } - - return fd; -#endif -} - -auto FileOps::native_close_file(const NativeFileHandle handle) -> void { - if (handle == INVALID_FILE_HANDLE) { - return; - } + auto FileOps::normalize_executable_path(Ref path) -> Path + { + Mut result = path; #if IA_PLATFORM_WINDOWS - CloseHandle(handle); + if (!result.has_extension()) + { + result.replace_extension(".exe"); + } #elif IA_PLATFORM_UNIX - close(handle); + if (result.extension() == ".exe") + { + result.replace_extension(""); + } + + if (result.is_relative()) + { + Mut path_str = result.string(); + if (!path_str.starts_with("./") && !path_str.starts_with("../")) + { + result = "./" + path_str; + } + } #endif -} + return result; + } -FileOps::MemoryMappedRegion::~MemoryMappedRegion() { unmap(); } + auto FileOps::native_open_file(Ref path, const FileAccess access, const FileMode mode, const u32 permissions) + -> Result + { +#if IA_PLATFORM_WINDOWS + AU_UNUSED(permissions); -FileOps::MemoryMappedRegion::MemoryMappedRegion( - ForwardRef other) noexcept { - *this = std::move(other); -} + Mut dw_access = 0; + Mut dw_share = FILE_SHARE_READ; + Mut dw_disposition = 0; + Mut dw_flags_and_attributes = FILE_ATTRIBUTE_NORMAL; -auto FileOps::MemoryMappedRegion::operator=( - ForwardRef other) noexcept - -> MutRef { - if (this != &other) { + switch (access) + { + case FileAccess::Read: + dw_access = GENERIC_READ; + break; + case FileAccess::Write: + dw_access = GENERIC_WRITE; + break; + case FileAccess::ReadWrite: + dw_access = GENERIC_READ | GENERIC_WRITE; + break; + } + + switch (mode) + { + case FileMode::OpenExisting: + dw_disposition = OPEN_EXISTING; + break; + case FileMode::OpenAlways: + dw_disposition = OPEN_ALWAYS; + break; + case FileMode::CreateNew: + dw_disposition = CREATE_NEW; + break; + case FileMode::CreateAlways: + dw_disposition = CREATE_ALWAYS; + break; + case FileMode::TruncateExisting: + dw_disposition = TRUNCATE_EXISTING; + break; + } + + Mut h_file = + CreateFileA(path.string().c_str(), dw_access, dw_share, NULL, dw_disposition, dw_flags_and_attributes, NULL); + + if (h_file == INVALID_HANDLE_VALUE) + { + return fail("Failed to open file '{}': {}", path.string(), GetLastError()); + } + + return h_file; + +#elif IA_PLATFORM_UNIX + Mut flags = 0; + + switch (access) + { + case FileAccess::Read: + flags = O_RDONLY; + break; + case FileAccess::Write: + flags = O_WRONLY; + break; + case FileAccess::ReadWrite: + flags = O_RDWR; + break; + } + + switch (mode) + { + case FileMode::OpenExisting: + break; + case FileMode::OpenAlways: + flags |= O_CREAT; + break; + case FileMode::CreateNew: + flags |= O_CREAT | O_EXCL; + break; + case FileMode::CreateAlways: + flags |= O_CREAT | O_TRUNC; + break; + case FileMode::TruncateExisting: + flags |= O_TRUNC; + break; + } + + Mut fd = open(path.string().c_str(), flags, permissions); + + if (fd == -1) + { + return fail("Failed to open file '{}': {}", path.string(), errno); + } + + return fd; +#endif + } + + auto FileOps::native_close_file(const NativeFileHandle handle) -> void + { + if (handle == INVALID_FILE_HANDLE) + { + return; + } + +#if IA_PLATFORM_WINDOWS + CloseHandle(handle); +#elif IA_PLATFORM_UNIX + close(handle); +#endif + } + + FileOps::MemoryMappedRegion::~MemoryMappedRegion() + { unmap(); - m_ptr = other.m_ptr; - m_size = other.m_size; + } + + FileOps::MemoryMappedRegion::MemoryMappedRegion(ForwardRef other) noexcept + { + *this = std::move(other); + } + + auto FileOps::MemoryMappedRegion::operator=(ForwardRef other) noexcept + -> MutRef + { + if (this != &other) + { + unmap(); + m_ptr = other.m_ptr; + m_size = other.m_size; #if IA_PLATFORM_WINDOWS - m_map_handle = other.m_map_handle; - other.m_map_handle = NULL; + m_map_handle = other.m_map_handle; + other.m_map_handle = NULL; #endif - other.m_ptr = nullptr; - other.m_size = 0; - } - return *this; -} - -auto FileOps::MemoryMappedRegion::map(const NativeFileHandle handle, - const u64 offset, const usize size) - -> Result { - unmap(); - - if (handle == INVALID_FILE_HANDLE) { - return fail("Invalid file handle provided to Map"); + other.m_ptr = nullptr; + other.m_size = 0; + } + return *this; } - if (size == 0) { - return fail("Cannot map region of size 0"); - } + auto FileOps::MemoryMappedRegion::map(const NativeFileHandle handle, const u64 offset, const usize size) + -> Result + { + unmap(); -#if IA_PLATFORM_WINDOWS - Mut file_size; - if (!GetFileSizeEx(handle, &file_size)) { - return fail("Failed to get file size"); - } - - const u64 end_offset = offset + size; - if (static_cast(file_size.QuadPart) < end_offset) { - Mut new_size; - new_size.QuadPart = static_cast(end_offset); - if (!SetFilePointerEx(handle, new_size, NULL, FILE_BEGIN)) { - return fail("Failed to seek to new end of file"); + if (handle == INVALID_FILE_HANDLE) + { + return fail("Invalid file handle provided to Map"); } - if (!SetEndOfFile(handle)) { - return fail("Failed to extend file for mapping"); + if (size == 0) + { + return fail("Cannot map region of size 0"); } - } - - m_map_handle = CreateFileMappingW(handle, NULL, PAGE_READWRITE, 0, 0, NULL); - if (m_map_handle == NULL) { - return fail("CreateFileMapping failed: {}", GetLastError()); - } - - const DWORD offset_high = static_cast(offset >> 32); - const DWORD offset_low = static_cast(offset & 0xFFFFFFFF); - - m_ptr = static_cast(MapViewOfFile(m_map_handle, FILE_MAP_WRITE, - offset_high, offset_low, size)); - if (m_ptr == NULL) { - CloseHandle(m_map_handle); - m_map_handle = NULL; - return fail("MapViewOfFile failed (Offset: {}, Size: {}): {}", offset, size, - GetLastError()); - } - m_size = size; - -#elif IA_PLATFORM_UNIX - Mut sb; - if (fstat(handle, &sb) == -1) { - return fail("Failed to fstat file"); - } - - const u64 end_offset = offset + size; - if (static_cast(sb.st_size) < end_offset) { - if (ftruncate(handle, static_cast(end_offset)) == -1) { - return fail("Failed to ftruncate (extend) file"); - } - } - - Mut ptr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, - handle, static_cast(offset)); - if (ptr == MAP_FAILED) { - return fail("mmap failed: {}", errno); - } - - m_ptr = static_cast(ptr); - m_size = size; - - madvise(m_ptr, m_size, MADV_SEQUENTIAL); -#endif - - return {}; -} - -auto FileOps::MemoryMappedRegion::unmap() -> void { - if (!m_ptr) { - return; - } #if IA_PLATFORM_WINDOWS - UnmapViewOfFile(m_ptr); - if (m_map_handle) { - CloseHandle(m_map_handle); - m_map_handle = NULL; - } -#elif IA_PLATFORM_UNIX - munmap(m_ptr, m_size); -#endif - m_ptr = nullptr; - m_size = 0; -} + Mut file_size; + if (!GetFileSizeEx(handle, &file_size)) + { + return fail("Failed to get file size"); + } -auto FileOps::MemoryMappedRegion::flush() -> void { - if (!m_ptr) { - return; + const u64 end_offset = offset + size; + if (static_cast(file_size.QuadPart) < end_offset) + { + Mut new_size; + new_size.QuadPart = static_cast(end_offset); + if (!SetFilePointerEx(handle, new_size, NULL, FILE_BEGIN)) + { + return fail("Failed to seek to new end of file"); + } + + if (!SetEndOfFile(handle)) + { + return fail("Failed to extend file for mapping"); + } + } + + m_map_handle = CreateFileMappingW(handle, NULL, PAGE_READWRITE, 0, 0, NULL); + if (m_map_handle == NULL) + { + return fail("CreateFileMapping failed: {}", GetLastError()); + } + + const DWORD offset_high = static_cast(offset >> 32); + const DWORD offset_low = static_cast(offset & 0xFFFFFFFF); + + m_ptr = static_cast(MapViewOfFile(m_map_handle, FILE_MAP_WRITE, offset_high, offset_low, size)); + if (m_ptr == NULL) + { + CloseHandle(m_map_handle); + m_map_handle = NULL; + return fail("MapViewOfFile failed (Offset: {}, Size: {}): {}", offset, size, GetLastError()); + } + m_size = size; + +#elif IA_PLATFORM_UNIX + Mut sb; + if (fstat(handle, &sb) == -1) + { + return fail("Failed to fstat file"); + } + + const u64 end_offset = offset + size; + if (static_cast(sb.st_size) < end_offset) + { + if (ftruncate(handle, static_cast(end_offset)) == -1) + { + return fail("Failed to ftruncate (extend) file"); + } + } + + Mut ptr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, handle, static_cast(offset)); + if (ptr == MAP_FAILED) + { + return fail("mmap failed: {}", errno); + } + + m_ptr = static_cast(ptr); + m_size = size; + + madvise(m_ptr, m_size, MADV_SEQUENTIAL); +#endif + + return {}; } + auto FileOps::MemoryMappedRegion::unmap() -> void + { + if (!m_ptr) + { + return; + } + #if IA_PLATFORM_WINDOWS - FlushViewOfFile(m_ptr, m_size); + UnmapViewOfFile(m_ptr); + if (m_map_handle) + { + CloseHandle(m_map_handle); + m_map_handle = NULL; + } #elif IA_PLATFORM_UNIX - msync(m_ptr, m_size, MS_SYNC); + munmap(m_ptr, m_size); #endif -} + m_ptr = nullptr; + m_size = 0; + } + + auto FileOps::MemoryMappedRegion::flush() -> void + { + if (!m_ptr) + { + return; + } + +#if IA_PLATFORM_WINDOWS + FlushViewOfFile(m_ptr, m_size); +#elif IA_PLATFORM_UNIX + msync(m_ptr, m_size, MS_SYNC); +#endif + } } // namespace IACore \ No newline at end of file diff --git a/Src/IACore/imp/cpp/Http/Client.cpp b/Src/IACore/imp/cpp/Http/Client.cpp index 2c228cc..db8eb1b 100644 --- a/Src/IACore/imp/cpp/Http/Client.cpp +++ b/Src/IACore/imp/cpp/Http/Client.cpp @@ -16,132 +16,145 @@ #include #include -namespace IACore { -auto HttpClient::create(Ref host) -> Result> { - return make_box_protected(httplib::Client(host)); -} +namespace IACore +{ + auto HttpClient::create(Ref host) -> Result> + { + return make_box_protected(httplib::Client(host)); + } -static auto build_headers(Span headers, - const char *default_content_type) - -> httplib::Headers { - Mut out; - Mut has_content_type = false; + static auto build_headers(Span headers, const char *default_content_type) + -> httplib::Headers + { + Mut out; + Mut has_content_type = false; - for (Ref h : headers) { - out.emplace(h.first, h.second); + for (Ref h : headers) + { + out.emplace(h.first, h.second); - if (h.first == HttpClient::header_type_to_string( - HttpClient::EHeaderType::CONTENT_TYPE)) { - has_content_type = true; + if (h.first == HttpClient::header_type_to_string(HttpClient::EHeaderType::CONTENT_TYPE)) + { + has_content_type = true; + } } - } - if (!has_content_type && default_content_type) { - out.emplace("Content-Type", default_content_type); - } - return out; -} - -HttpClient::HttpClient(ForwardRef client) - : m_client(std::move(client)), - m_last_response_code(EResponseCode::INTERNAL_SERVER_ERROR) { - m_client.enable_server_certificate_verification(true); -} - -HttpClient::~HttpClient() = default; - -auto HttpClient::enable_certificate_verification() -> void { - m_client.enable_server_certificate_verification(true); -} - -auto HttpClient::disable_certificate_verification() -> void { - m_client.enable_server_certificate_verification(false); -} - -auto HttpClient::preprocess_response(Ref response) -> String { - const Span response_bytes = { - reinterpret_cast(response.data()), response.size()}; - const DataOps::CompressionType compression = - DataOps::detect_compression(response_bytes); - - switch (compression) { - case DataOps::CompressionType::Gzip: { - const Result> data = DataOps::gzip_inflate(response_bytes); - if (!data) { - return response; + if (!has_content_type && default_content_type) + { + out.emplace("Content-Type", default_content_type); } - return String(reinterpret_cast(data->data()), data->size()); + return out; } - case DataOps::CompressionType::Zlib: { - const Result> data = DataOps::zlib_inflate(response_bytes); - if (!data) { - return response; + HttpClient::HttpClient(ForwardRef client) + : m_client(std::move(client)), m_last_response_code(EResponseCode::INTERNAL_SERVER_ERROR) + { + m_client.enable_server_certificate_verification(true); + } + + HttpClient::~HttpClient() = default; + + auto HttpClient::enable_certificate_verification() -> void + { + m_client.enable_server_certificate_verification(true); + } + + auto HttpClient::disable_certificate_verification() -> void + { + m_client.enable_server_certificate_verification(false); + } + + auto HttpClient::preprocess_response(Ref response) -> String + { + const Span response_bytes = {reinterpret_cast(response.data()), response.size()}; + const DataOps::CompressionType compression = DataOps::detect_compression(response_bytes); + + switch (compression) + { + case DataOps::CompressionType::Gzip: { + const Result> data = DataOps::gzip_inflate(response_bytes); + if (!data) + { + return response; + } + return String(reinterpret_cast(data->data()), data->size()); } - return String(reinterpret_cast(data->data()), data->size()); - } - case DataOps::CompressionType::None: - default: - break; - } - return response; -} - -auto HttpClient::raw_get(Ref path, Span headers, - const char *default_content_type) -> Result { - const httplib::Headers http_headers = - build_headers(headers, default_content_type); - - Mut adjusted_path = path; - if (!path.empty() && path[0] != '/') { - adjusted_path = "/" + path; - } - - const httplib::Result res = m_client.Get(adjusted_path.c_str(), http_headers); - - if (res) { - m_last_response_code = static_cast(res->status); - if (res->status >= 200 && res->status < 300) { - return preprocess_response(res->body); + case DataOps::CompressionType::Zlib: { + const Result> data = DataOps::zlib_inflate(response_bytes); + if (!data) + { + return response; + } + return String(reinterpret_cast(data->data()), data->size()); } - return fail("HTTP Error {} : {}", res->status, res->body); - } - return fail("Network Error: {}", httplib::to_string(res.error())); -} - -auto HttpClient::raw_post(Ref path, Span headers, - Ref body, const char *default_content_type) - -> Result { - Mut http_headers = - build_headers(headers, default_content_type); - - Mut content_type = default_content_type; - if (http_headers.count("Content-Type")) { - const httplib::Headers::iterator t = http_headers.find("Content-Type"); - content_type = t->second; - http_headers.erase(t); - } - - m_client.set_keep_alive(true); - - Mut adjusted_path = path; - if (!path.empty() && path[0] != '/') { - adjusted_path = "/" + path; - } - - const httplib::Result res = m_client.Post(adjusted_path.c_str(), http_headers, - body, content_type.c_str()); - - if (res) { - m_last_response_code = static_cast(res->status); - if (res->status >= 200 && res->status < 300) { - return preprocess_response(res->body); + case DataOps::CompressionType::None: + default: + break; } - return fail("HTTP Error {} : {}", res->status, res->body); + return response; } - return fail("Network Error: {}", httplib::to_string(res.error())); -} + auto HttpClient::raw_get(Ref path, Span headers, const char *default_content_type) + -> Result + { + const httplib::Headers http_headers = build_headers(headers, default_content_type); + + Mut adjusted_path = path; + if (!path.empty() && path[0] != '/') + { + adjusted_path = "/" + path; + } + + const httplib::Result res = m_client.Get(adjusted_path.c_str(), http_headers); + + if (res) + { + m_last_response_code = static_cast(res->status); + if (res->status >= 200 && res->status < 300) + { + return preprocess_response(res->body); + } + return fail("HTTP Error {} : {}", res->status, res->body); + } + + return fail("Network Error: {}", httplib::to_string(res.error())); + } + + auto HttpClient::raw_post(Ref path, Span headers, Ref body, + const char *default_content_type) -> Result + { + Mut http_headers = build_headers(headers, default_content_type); + + Mut content_type = default_content_type; + if (http_headers.count("Content-Type")) + { + const httplib::Headers::iterator t = http_headers.find("Content-Type"); + content_type = t->second; + http_headers.erase(t); + } + + m_client.set_keep_alive(true); + + Mut adjusted_path = path; + if (!path.empty() && path[0] != '/') + { + adjusted_path = "/" + path; + } + + const httplib::Result res = m_client.Post(adjusted_path.c_str(), http_headers, body, content_type.c_str()); + + if (res) + { + m_last_response_code = static_cast(res->status); + if (res->status >= 200 && res->status < 300) + { + return preprocess_response(res->body); + } + return fail("HTTP Error {} : {}", res->status, res->body); + } + + return fail("Network Error: {}", httplib::to_string(res.error())); + } } // namespace IACore \ No newline at end of file diff --git a/Src/IACore/imp/cpp/Http/Common.cpp b/Src/IACore/imp/cpp/Http/Common.cpp index 082be41..3fa0e70 100644 --- a/Src/IACore/imp/cpp/Http/Common.cpp +++ b/Src/IACore/imp/cpp/Http/Common.cpp @@ -15,103 +15,110 @@ #include -namespace IACore { -auto HttpCommon::url_encode(Ref value) -> String { - Mut escaped; - escaped.fill('0'); - escaped << std::hex << std::uppercase; +namespace IACore +{ + auto HttpCommon::url_encode(Ref value) -> String + { + Mut escaped; + escaped.fill('0'); + escaped << std::hex << std::uppercase; - for (const char c : value) { - if (std::isalnum(static_cast(c)) || c == '-' || c == '_' || - c == '.' || c == '~') - escaped << c; - else - escaped << '%' << std::setw(2) - << static_cast(static_cast(c)); + for (const char c : value) + { + if (std::isalnum(static_cast(c)) || c == '-' || c == '_' || c == '.' || c == '~') + escaped << c; + else + escaped << '%' << std::setw(2) << static_cast(static_cast(c)); + } + + return escaped.str(); } - return escaped.str(); -} + auto HttpCommon::url_decode(Ref value) -> String + { + Mut result; + result.reserve(value.length()); -auto HttpCommon::url_decode(Ref value) -> String { - Mut result; - result.reserve(value.length()); + for (Mut i = 0; i < value.length(); ++i) + { + if (value[i] == '%' && i + 2 < value.length()) + { + const std::string hex_str = value.substr(i + 1, 2); + const char decoded_char = static_cast(std::strtol(hex_str.c_str(), nullptr, 16)); + result += decoded_char; + i += 2; + } + else if (value[i] == '+') + result += ' '; + else + result += value[i]; + } - for (Mut i = 0; i < value.length(); ++i) { - if (value[i] == '%' && i + 2 < value.length()) { - const std::string hex_str = value.substr(i + 1, 2); - const char decoded_char = - static_cast(std::strtol(hex_str.c_str(), nullptr, 16)); - result += decoded_char; - i += 2; - } else if (value[i] == '+') - result += ' '; - else - result += value[i]; + return result; } - return result; -} - -auto HttpCommon::header_type_to_string(const EHeaderType type) -> String { - switch (type) { - case EHeaderType::ACCEPT: - return "Accept"; - case EHeaderType::ACCEPT_CHARSET: - return "Accept-Charset"; - case EHeaderType::ACCEPT_ENCODING: - return "Accept-Encoding"; - case EHeaderType::ACCEPT_LANGUAGE: - return "Accept-Language"; - case EHeaderType::AUTHORIZATION: - return "Authorization"; - case EHeaderType::CACHE_CONTROL: - return "Cache-Control"; - case EHeaderType::CONNECTION: - return "Connection"; - case EHeaderType::CONTENT_LENGTH: - return "Content-Length"; - case EHeaderType::CONTENT_TYPE: - return "Content-Type"; - case EHeaderType::COOKIE: - return "Cookie"; - case EHeaderType::DATE: - return "Date"; - case EHeaderType::EXPECT: - return "Expect"; - case EHeaderType::HOST: - return "Host"; - case EHeaderType::IF_MATCH: - return "If-Match"; - case EHeaderType::IF_MODIFIED_SINCE: - return "If-Modified-Since"; - case EHeaderType::IF_NONE_MATCH: - return "If-None-Match"; - case EHeaderType::ORIGIN: - return "Origin"; - case EHeaderType::PRAGMA: - return "Pragma"; - case EHeaderType::PROXY_AUTHORIZATION: - return "Proxy-Authorization"; - case EHeaderType::RANGE: - return "Range"; - case EHeaderType::REFERER: - return "Referer"; - case EHeaderType::TE: - return "TE"; - case EHeaderType::UPGRADE: - return "Upgrade"; - case EHeaderType::USER_AGENT: - return "User-Agent"; - case EHeaderType::VIA: - return "Via"; - case EHeaderType::WARNING: - return "Warning"; + auto HttpCommon::header_type_to_string(const EHeaderType type) -> String + { + switch (type) + { + case EHeaderType::ACCEPT: + return "Accept"; + case EHeaderType::ACCEPT_CHARSET: + return "Accept-Charset"; + case EHeaderType::ACCEPT_ENCODING: + return "Accept-Encoding"; + case EHeaderType::ACCEPT_LANGUAGE: + return "Accept-Language"; + case EHeaderType::AUTHORIZATION: + return "Authorization"; + case EHeaderType::CACHE_CONTROL: + return "Cache-Control"; + case EHeaderType::CONNECTION: + return "Connection"; + case EHeaderType::CONTENT_LENGTH: + return "Content-Length"; + case EHeaderType::CONTENT_TYPE: + return "Content-Type"; + case EHeaderType::COOKIE: + return "Cookie"; + case EHeaderType::DATE: + return "Date"; + case EHeaderType::EXPECT: + return "Expect"; + case EHeaderType::HOST: + return "Host"; + case EHeaderType::IF_MATCH: + return "If-Match"; + case EHeaderType::IF_MODIFIED_SINCE: + return "If-Modified-Since"; + case EHeaderType::IF_NONE_MATCH: + return "If-None-Match"; + case EHeaderType::ORIGIN: + return "Origin"; + case EHeaderType::PRAGMA: + return "Pragma"; + case EHeaderType::PROXY_AUTHORIZATION: + return "Proxy-Authorization"; + case EHeaderType::RANGE: + return "Range"; + case EHeaderType::REFERER: + return "Referer"; + case EHeaderType::TE: + return "TE"; + case EHeaderType::UPGRADE: + return "Upgrade"; + case EHeaderType::USER_AGENT: + return "User-Agent"; + case EHeaderType::VIA: + return "Via"; + case EHeaderType::WARNING: + return "Warning"; + } + return ""; } - return ""; -} -auto HttpCommon::is_success_response_code(const EResponseCode code) -> bool { - return (i32)code >= 200 && (i32)code < 300; -} + auto HttpCommon::is_success_response_code(const EResponseCode code) -> bool + { + return (i32) code >= 200 && (i32) code < 300; + } } // namespace IACore \ No newline at end of file diff --git a/Src/IACore/imp/cpp/Http/Server.cpp b/Src/IACore/imp/cpp/Http/Server.cpp index 2a39d49..4bbbe36 100644 --- a/Src/IACore/imp/cpp/Http/Server.cpp +++ b/Src/IACore/imp/cpp/Http/Server.cpp @@ -15,144 +15,186 @@ #include -namespace IACore { +namespace IACore +{ -auto HttpServer::Request::get_header(Ref key) const -> String { - if (auto it = headers.find(key); it != headers.end()) { - return it->second; + auto HttpServer::Request::get_header(Ref key) const -> String + { + if (auto it = headers.find(key); it != headers.end()) + { + return it->second; + } + return ""; } - return ""; -} -auto HttpServer::Request::get_param(Ref key) const -> String { - if (auto it = params.find(key); it != params.end()) { - return it->second; + auto HttpServer::Request::get_param(Ref key) const -> String + { + if (auto it = params.find(key); it != params.end()) + { + return it->second; + } + return ""; } - return ""; -} -auto HttpServer::Request::get_path_param(Ref key) const -> String { - if (auto it = path_params.find(key); it != path_params.end()) { - return it->second; + auto HttpServer::Request::get_path_param(Ref key) const -> String + { + if (auto it = path_params.find(key); it != path_params.end()) + { + return it->second; + } + return ""; } - return ""; -} -auto HttpServer::Request::has_header(Ref key) const -> bool { - return headers.contains(key); -} - -auto HttpServer::Request::has_param(Ref key) const -> bool { - return params.contains(key); -} - -auto HttpServer::Request::has_path_param(Ref key) const -> bool { - return path_params.contains(key); -} - -void HttpServer::Response::set_content(Ref content, Ref type) { - body = content; - content_type = type; -} - -void HttpServer::Response::set_status(const EResponseCode status_code) { - code = status_code; -} - -void HttpServer::Response::add_header(Ref key, Ref value) { - headers[key] = value; -} - -struct PublicHttpServer : public HttpServer { - PublicHttpServer() = default; -}; - -HttpServer::HttpServer() = default; - -HttpServer::~HttpServer() { stop(); } - -auto HttpServer::create() -> Result> { - return make_box(); -} - -auto HttpServer::listen(Ref host, const u32 port) -> Result { - if (!m_server.listen(host.c_str(), static_cast(port))) { - return fail("Failed to start HTTP server on {}:{}", host, port); + auto HttpServer::Request::has_header(Ref key) const -> bool + { + return headers.contains(key); } - return {}; -} -void HttpServer::stop() { - if (m_server.is_running()) { - m_server.stop(); + auto HttpServer::Request::has_param(Ref key) const -> bool + { + return params.contains(key); } -} -auto HttpServer::is_running() const -> bool { return m_server.is_running(); } - -void HttpServer::register_handler(Ref method, Ref pattern, - const Handler handler) { - const httplib::Server::Handler wrapper = - [handler](Ref req, MutRef res) { - Mut ia_req; - ia_req.path = req.path; - ia_req.method = req.method; - ia_req.body = req.body; - - for (Ref> item : req.headers) { - ia_req.headers[item.first] = item.second; - } - - for (Ref> item : req.params) { - ia_req.params[item.first] = item.second; - } - - for (Ref> item : req.path_params) { - ia_req.path_params[item.first] = item.second; - } - - Mut ia_res; - handler(ia_req, ia_res); - - res.status = static_cast(ia_res.code); - res.set_content(ia_res.body, ia_res.content_type.c_str()); - - for (Ref> item : ia_res.headers) { - res.set_header(item.first.c_str(), item.second.c_str()); - } - }; - - if (method == "GET") { - m_server.Get(pattern.c_str(), wrapper); - } else if (method == "POST") { - m_server.Post(pattern.c_str(), wrapper); - } else if (method == "PUT") { - m_server.Put(pattern.c_str(), wrapper); - } else if (method == "DELETE") { - m_server.Delete(pattern.c_str(), wrapper); - } else if (method == "OPTIONS") { - m_server.Options(pattern.c_str(), wrapper); + auto HttpServer::Request::has_path_param(Ref key) const -> bool + { + return path_params.contains(key); } -} -void HttpServer::get(Ref pattern, const Handler handler) { - register_handler("GET", pattern, handler); -} + void HttpServer::Response::set_content(Ref content, Ref type) + { + body = content; + content_type = type; + } -void HttpServer::post(Ref pattern, const Handler handler) { - register_handler("POST", pattern, handler); -} + void HttpServer::Response::set_status(const EResponseCode status_code) + { + code = status_code; + } -void HttpServer::put(Ref pattern, const Handler handler) { - register_handler("PUT", pattern, handler); -} + void HttpServer::Response::add_header(Ref key, Ref value) + { + headers[key] = value; + } -void HttpServer::del(Ref pattern, const Handler handler) { - register_handler("DELETE", pattern, handler); -} + struct PublicHttpServer : public HttpServer + { + PublicHttpServer() = default; + }; -void HttpServer::options(Ref pattern, const Handler handler) { - register_handler("OPTIONS", pattern, handler); -} + HttpServer::HttpServer() = default; + + HttpServer::~HttpServer() + { + stop(); + } + + auto HttpServer::create() -> Result> + { + return make_box(); + } + + auto HttpServer::listen(Ref host, const u32 port) -> Result + { + if (!m_server.listen(host.c_str(), static_cast(port))) + { + return fail("Failed to start HTTP server on {}:{}", host, port); + } + return {}; + } + + void HttpServer::stop() + { + if (m_server.is_running()) + { + m_server.stop(); + } + } + + auto HttpServer::is_running() const -> bool + { + return m_server.is_running(); + } + + void HttpServer::register_handler(Ref method, Ref pattern, const Handler handler) + { + const httplib::Server::Handler wrapper = [handler](Ref req, MutRef res) { + Mut ia_req; + ia_req.path = req.path; + ia_req.method = req.method; + ia_req.body = req.body; + + for (Ref> item : req.headers) + { + ia_req.headers[item.first] = item.second; + } + + for (Ref> item : req.params) + { + ia_req.params[item.first] = item.second; + } + + for (Ref> item : req.path_params) + { + ia_req.path_params[item.first] = item.second; + } + + Mut ia_res; + handler(ia_req, ia_res); + + res.status = static_cast(ia_res.code); + res.set_content(ia_res.body, ia_res.content_type.c_str()); + + for (Ref> item : ia_res.headers) + { + res.set_header(item.first.c_str(), item.second.c_str()); + } + }; + + if (method == "GET") + { + m_server.Get(pattern.c_str(), wrapper); + } + else if (method == "POST") + { + m_server.Post(pattern.c_str(), wrapper); + } + else if (method == "PUT") + { + m_server.Put(pattern.c_str(), wrapper); + } + else if (method == "DELETE") + { + m_server.Delete(pattern.c_str(), wrapper); + } + else if (method == "OPTIONS") + { + m_server.Options(pattern.c_str(), wrapper); + } + } + + void HttpServer::get(Ref pattern, const Handler handler) + { + register_handler("GET", pattern, handler); + } + + void HttpServer::post(Ref pattern, const Handler handler) + { + register_handler("POST", pattern, handler); + } + + void HttpServer::put(Ref pattern, const Handler handler) + { + register_handler("PUT", pattern, handler); + } + + void HttpServer::del(Ref pattern, const Handler handler) + { + register_handler("DELETE", pattern, handler); + } + + void HttpServer::options(Ref pattern, const Handler handler) + { + register_handler("OPTIONS", pattern, handler); + } } // namespace IACore \ No newline at end of file diff --git a/Src/IACore/imp/cpp/IACore.cpp b/Src/IACore/imp/cpp/IACore.cpp index a759c81..1698b14 100644 --- a/Src/IACore/imp/cpp/IACore.cpp +++ b/Src/IACore/imp/cpp/IACore.cpp @@ -19,38 +19,47 @@ #include #include -namespace IACore { -Mut g_start_time = {}; +namespace IACore +{ + Mut g_start_time = {}; -static Mut g_main_thread_id = {}; -static Mut g_core_init_count = 0; + static Mut g_main_thread_id = {}; + static Mut g_core_init_count = 0; -auto initialize() -> void { - g_core_init_count++; - if (g_core_init_count > 1) { - return; + auto initialize() -> void + { + g_core_init_count++; + if (g_core_init_count > 1) + { + return; + } + + g_main_thread_id = std::this_thread::get_id(); + g_start_time = std::chrono::high_resolution_clock::now(); + + Logger::initialize(); + + mi_option_set(mi_option_verbose, 0); } - g_main_thread_id = std::this_thread::get_id(); - g_start_time = std::chrono::high_resolution_clock::now(); + auto terminate() -> void + { + g_core_init_count--; + if (g_core_init_count > 0) + { + return; + } - Logger::initialize(); - - mi_option_set(mi_option_verbose, 0); -} - -auto terminate() -> void { - g_core_init_count--; - if (g_core_init_count > 0) { - return; + Logger::terminate(); } - Logger::terminate(); -} + auto is_initialized() -> bool + { + return g_core_init_count > 0; + } -auto is_initialized() -> bool { return g_core_init_count > 0; } - -auto is_main_thread() -> bool { - return std::this_thread::get_id() == g_main_thread_id; -} + auto is_main_thread() -> bool + { + return std::this_thread::get_id() == g_main_thread_id; + } } // namespace IACore \ No newline at end of file diff --git a/Src/IACore/imp/cpp/IPC.cpp b/Src/IACore/imp/cpp/IPC.cpp index 41a4d4a..21284f3 100644 --- a/Src/IACore/imp/cpp/IPC.cpp +++ b/Src/IACore/imp/cpp/IPC.cpp @@ -20,432 +20,452 @@ #include #include -namespace IACore { -struct IpcConnectionDescriptor { - Mut socket_path; - Mut shared_mem_path; - Mut shared_mem_size; +namespace IACore +{ + struct IpcConnectionDescriptor + { + Mut socket_path; + Mut shared_mem_path; + Mut shared_mem_size; - [[nodiscard]] auto serialize() const -> String { - return std::format("{}|{}|{}|", socket_path, shared_mem_path, - shared_mem_size); - } + [[nodiscard]] auto serialize() const -> String + { + return std::format("{}|{}|{}|", socket_path, shared_mem_path, shared_mem_size); + } - static auto deserialize(const StringView data) - -> Option { - enum class ParseState { SocketPath, SharedMemPath, SharedMemSize }; + static auto deserialize(const StringView data) -> Option + { + enum class ParseState + { + SocketPath, + SharedMemPath, + SharedMemSize + }; - Mut result{}; - Mut t = 0; - Mut state = ParseState::SocketPath; + Mut result{}; + Mut t = 0; + Mut state = ParseState::SocketPath; - for (Mut i = 0; i < data.size(); ++i) { - if (data[i] != '|') { - continue; - } - - switch (state) { - case ParseState::SocketPath: - result.socket_path = String(data.substr(t, i - t)); - state = ParseState::SharedMemPath; - break; - - case ParseState::SharedMemPath: - result.shared_mem_path = String(data.substr(t, i - t)); - state = ParseState::SharedMemSize; - break; - - case ParseState::SharedMemSize: { - const char *start = data.data() + t; - const char *end = data.data() + i; - if (std::from_chars(start, end, result.shared_mem_size).ec != - std::errc{}) { - return std::nullopt; + for (Mut i = 0; i < data.size(); ++i) + { + if (data[i] != '|') + { + continue; } - return result; + + switch (state) + { + case ParseState::SocketPath: + result.socket_path = String(data.substr(t, i - t)); + state = ParseState::SharedMemPath; + break; + + case ParseState::SharedMemPath: + result.shared_mem_path = String(data.substr(t, i - t)); + state = ParseState::SharedMemSize; + break; + + case ParseState::SharedMemSize: { + const char *start = data.data() + t; + const char *end = data.data() + i; + if (std::from_chars(start, end, result.shared_mem_size).ec != std::errc{}) + { + return std::nullopt; + } + return result; + } + } + t = i + 1; } - } - t = i + 1; + return std::nullopt; } - return std::nullopt; - } -}; + }; -IpcNode::~IpcNode() { - if (m_socket != INVALID_SOCKET) { - SocketOps::close(m_socket); - } -} - -auto IpcNode::connect(const char *connection_string) -> Result { - const Option desc_opt = - IpcConnectionDescriptor::deserialize(connection_string); - if (!desc_opt) { - return fail("Failed to parse connection string"); - } - Ref desc = *desc_opt; - m_shm_name = desc.shared_mem_path; - - m_socket = AU_TRY(SocketOps::create_unix_socket()); - AU_TRY_PURE( - SocketOps::connect_unix_socket(m_socket, desc.socket_path.c_str())); - - Mut mapped_ptr = AU_TRY(FileOps::map_shared_memory( - desc.shared_mem_path, desc.shared_mem_size, false)); - m_shared_memory = mapped_ptr; - - Mut layout = - reinterpret_cast(m_shared_memory); - - if (layout->meta.magic != 0x49414950) { - return fail("Invalid shared memory header signature"); - } - - if (layout->meta.version != 1) { - return fail("IPC version mismatch"); - } - - Mut moni_ptr = m_shared_memory + layout->moni_data_offset; - Mut mino_ptr = m_shared_memory + layout->mino_data_offset; - - m_moni = AU_TRY(RingBufferView::create( - &layout->moni_control, - Span(moni_ptr, static_cast(layout->moni_data_size)), false)); - - m_mino = AU_TRY(RingBufferView::create( - &layout->mino_control, - Span(mino_ptr, static_cast(layout->mino_data_size)), false)); - -#if IA_PLATFORM_WINDOWS - Mut mode = 1; - ioctlsocket(m_socket, FIONBIO, &mode); -#else - fcntl(m_socket, F_SETFL, O_NONBLOCK); -#endif - - m_receive_buffer.resize(UINT16_MAX + 1); - - return {}; -} - -void IpcNode::update() { - if (!m_moni.is_valid()) { - return; - } - - Mut header; - - while (m_moni.pop( - header, Span(m_receive_buffer.data(), m_receive_buffer.size()))) { - on_packet(header.id, {m_receive_buffer.data(), header.payload_size}); - } - - Mut signal = 0; - const isize res = recv(m_socket, reinterpret_cast(&signal), 1, 0); - if (res == 1) { - on_signal(signal); - } else if (res == 0 || (res < 0 && !SocketOps::is_would_block())) { - SocketOps::close(m_socket); - FileOps::unlink_shared_memory(m_shm_name); - - std::exit(-1); - } -} - -void IpcNode::send_signal(const u8 signal) { - if (m_socket != INVALID_SOCKET) { - send(m_socket, reinterpret_cast(&signal), sizeof(signal), 0); - } -} - -auto IpcNode::send_packet(const u16 packet_id, const Span payload) - -> Result { - if (!m_mino.is_valid()) - return fail("invalid MINO"); - return m_mino.push(packet_id, payload); -} - -void IpcManager::NodeSession::send_signal(const u8 signal) { - if (data_socket != INVALID_SOCKET) { - send(data_socket, reinterpret_cast(&signal), sizeof(signal), - 0); - } -} - -auto IpcManager::NodeSession::send_packet(const u16 packet_id, - const Span payload) - -> Result { - const std::scoped_lock lock(send_mutex); - if (!moni.is_valid()) - return fail("invalid MONI"); - return moni.push(packet_id, payload); -} - -IpcManager::IpcManager() { - ensure(SocketOps::is_initialized(), - "SocketOps must be initialized before using IpcManager"); - - m_receive_buffer.resize(UINT16_MAX + 1); -} - -IpcManager::~IpcManager() { - for (MutRef> session : m_active_sessions) { - ProcessOps::terminate_process(session->node_process); - FileOps::unmap_file(session->mapped_ptr); - FileOps::unlink_shared_memory(session->shared_mem_name); - SocketOps::close(session->data_socket); - } - m_active_sessions.clear(); - - for (MutRef> session : m_pending_sessions) { - ProcessOps::terminate_process(session->node_process); - FileOps::unmap_file(session->mapped_ptr); - FileOps::unlink_shared_memory(session->shared_mem_name); - SocketOps::close(session->listener_socket); - } - m_pending_sessions.clear(); -} - -void IpcManager::update() { - const std::chrono::system_clock::time_point now = - std::chrono::system_clock::now(); - - for (Mut i = static_cast(m_pending_sessions.size()) - 1; i >= 0; - --i) { - MutRef> session = - m_pending_sessions[static_cast(i)]; - - if (now - session->creation_time > std::chrono::seconds(5)) { - ProcessOps::terminate_process(session->node_process); - - FileOps::unmap_file(session->mapped_ptr); - FileOps::unlink_shared_memory(session->shared_mem_name); - SocketOps::close(session->listener_socket); - - m_pending_sessions.erase(m_pending_sessions.begin() + i); - continue; - } - -#if IA_PLATFORM_WINDOWS - Mut new_sock = accept(session->listener_socket, nullptr, nullptr); -#else - Mut new_sock = accept(session->listener_socket, nullptr, nullptr); -#endif - - if (new_sock != INVALID_SOCKET) { - session->data_socket = new_sock; - session->is_ready = true; - -#if IA_PLATFORM_WINDOWS - Mut mode = 1; - ioctlsocket(session->data_socket, FIONBIO, &mode); -#else - fcntl(session->data_socket, F_SETFL, O_NONBLOCK); -#endif - - SocketOps::close(session->listener_socket); - session->listener_socket = INVALID_SOCKET; - - const NativeProcessID session_id = session->node_process->id.load(); - Mut session_ptr = session.get(); - m_active_sessions.push_back(std::move(session)); - m_pending_sessions.erase(m_pending_sessions.begin() + i); - m_active_session_map[session_id] = session_ptr; + IpcNode::~IpcNode() + { + if (m_socket != INVALID_SOCKET) + { + SocketOps::close(m_socket); } } - for (Mut i = static_cast(m_active_sessions.size()) - 1; i >= 0; - --i) { - MutRef> node = m_active_sessions[static_cast(i)]; + auto IpcNode::connect(const char *connection_string) -> Result + { + const Option desc_opt = IpcConnectionDescriptor::deserialize(connection_string); + if (!desc_opt) + { + return fail("Failed to parse connection string"); + } + Ref desc = *desc_opt; + m_shm_name = desc.shared_mem_path; - Mut node_id = node->node_process->id.load(); + m_socket = AU_TRY(SocketOps::create_unix_socket()); + AU_TRY_PURE(SocketOps::connect_unix_socket(m_socket, desc.socket_path.c_str())); + + Mut mapped_ptr = AU_TRY(FileOps::map_shared_memory(desc.shared_mem_path, desc.shared_mem_size, false)); + m_shared_memory = mapped_ptr; + + Mut layout = reinterpret_cast(m_shared_memory); + + if (layout->meta.magic != 0x49414950) + { + return fail("Invalid shared memory header signature"); + } + + if (layout->meta.version != 1) + { + return fail("IPC version mismatch"); + } + + Mut moni_ptr = m_shared_memory + layout->moni_data_offset; + Mut mino_ptr = m_shared_memory + layout->mino_data_offset; + + m_moni = AU_TRY(RingBufferView::create(&layout->moni_control, + Span(moni_ptr, static_cast(layout->moni_data_size)), false)); + + m_mino = AU_TRY(RingBufferView::create(&layout->mino_control, + Span(mino_ptr, static_cast(layout->mino_data_size)), false)); + +#if IA_PLATFORM_WINDOWS + Mut mode = 1; + ioctlsocket(m_socket, FIONBIO, &mode); +#else + fcntl(m_socket, F_SETFL, O_NONBLOCK); +#endif + + m_receive_buffer.resize(UINT16_MAX + 1); + + return {}; + } + + void IpcNode::update() + { + if (!m_moni.is_valid()) + { + return; + } Mut header; - while (node->mino.pop( - header, Span(m_receive_buffer.data(), m_receive_buffer.size()))) { - on_packet(node_id, header.id, - {m_receive_buffer.data(), header.payload_size}); + while (m_moni.pop(header, Span(m_receive_buffer.data(), m_receive_buffer.size()))) + { + on_packet(header.id, {m_receive_buffer.data(), header.payload_size}); } Mut signal = 0; - const isize res = - recv(node->data_socket, reinterpret_cast(&signal), 1, 0); + const isize res = recv(m_socket, reinterpret_cast(&signal), 1, 0); + if (res == 1) + { + on_signal(signal); + } + else if (res == 0 || (res < 0 && !SocketOps::is_would_block())) + { + SocketOps::close(m_socket); + FileOps::unlink_shared_memory(m_shm_name); - if (res == 1) { - on_signal(node_id, signal); - } else if (res == 0 || (res < 0 && !SocketOps::is_would_block())) { - ProcessOps::terminate_process(node->node_process); - - FileOps::unmap_file(node->mapped_ptr); - FileOps::unlink_shared_memory(node->shared_mem_name); - SocketOps::close(node->data_socket); - - m_active_sessions.erase(m_active_sessions.begin() + i); - m_active_session_map.erase(node_id); + std::exit(-1); } } -} -auto IpcManager::spawn_node(Ref executable_path, - const u32 shared_memory_size) - -> Result { - Mut> session = make_box(); - - static Mut> s_id_gen{0}; - const u32 sid = ++s_id_gen; - - Mut sock_path; -#if IA_PLATFORM_WINDOWS - Mut temp_path; - GetTempPathA(MAX_PATH, temp_path); - sock_path = std::format("{}\\ia_sess_{}.sock", temp_path, sid); -#else - sock_path = std::format("/tmp/ia_sess_{}.sock", sid); -#endif - - session->listener_socket = AU_TRY(SocketOps::create_unix_socket()); - AU_TRY_PURE( - SocketOps::bind_unix_socket(session->listener_socket, sock_path.c_str())); - AU_TRY_PURE(SocketOps::listen(session->listener_socket, 1)); - -#if IA_PLATFORM_WINDOWS - Mut mode = 1; - ioctlsocket(session->listener_socket, FIONBIO, &mode); -#else - fcntl(session->listener_socket, F_SETFL, O_NONBLOCK); -#endif - - const String shm_name = std::format("ia_shm_{}", sid); - session->mapped_ptr = - AU_TRY(FileOps::map_shared_memory(shm_name, shared_memory_size, true)); - - Mut layout = - reinterpret_cast(session->mapped_ptr); - - layout->meta.magic = 0x49414950; - layout->meta.version = 1; - layout->meta.total_size = shared_memory_size; - - const u64 header_size = IpcSharedMemoryLayout::get_header_size(); - const u64 usable_bytes = shared_memory_size - header_size; - - Mut half_size = (usable_bytes / 2); - half_size -= (half_size % 64); - - layout->moni_data_offset = header_size; - layout->moni_data_size = half_size; - - layout->mino_data_offset = header_size + half_size; - layout->mino_data_size = half_size; - - session->moni = AU_TRY(RingBufferView::create( - &layout->moni_control, - Span(session->mapped_ptr + layout->moni_data_offset, - static_cast(layout->moni_data_size)), - true)); - - session->mino = AU_TRY(RingBufferView::create( - &layout->mino_control, - Span(session->mapped_ptr + layout->mino_data_offset, - static_cast(layout->mino_data_size)), - true)); - - Mut desc; - desc.socket_path = sock_path; - desc.shared_mem_path = shm_name; - desc.shared_mem_size = shared_memory_size; - - const String args = std::format("\"{}\"", desc.serialize()); - - session->node_process = AU_TRY(ProcessOps::spawn_process_async( - FileOps::normalize_executable_path(executable_path).string(), args, - [sid](StringView line) { - if (Env::IS_DEBUG) { - std::cout << std::format("{}[Node:{}:STDOUT|STDERR]: {}{}\n", - console::MAGENTA, sid, line, console::RESET); - } - }, - [sid](Result result) { - if (Env::IS_DEBUG) { - if (!result) { - std::cout << std::format( - "{}[Node: {}]: Failed to spawn with error '{}'{}\n", - console::RED, sid, result.error(), console::RESET); - } else { - std::cout << std::format("{}[Node: {}]: Exited with code {}{}\n", - console::RED, sid, *result, - console::RESET); - } - } - })); - - std::this_thread::sleep_for(std::chrono::seconds(1)); - if (!session->node_process->is_active()) { - return fail("Failed to spawn the child process \"{}\"", - executable_path.string()); + void IpcNode::send_signal(const u8 signal) + { + if (m_socket != INVALID_SOCKET) + { + send(m_socket, reinterpret_cast(&signal), sizeof(signal), 0); + } } - const NativeProcessID process_id = session->node_process->id.load(); + auto IpcNode::send_packet(const u16 packet_id, const Span payload) -> Result + { + if (!m_mino.is_valid()) + return fail("invalid MINO"); + return m_mino.push(packet_id, payload); + } - session->shared_mem_name = shm_name; - session->creation_time = std::chrono::system_clock::now(); - m_pending_sessions.push_back(std::move(session)); + void IpcManager::NodeSession::send_signal(const u8 signal) + { + if (data_socket != INVALID_SOCKET) + { + send(data_socket, reinterpret_cast(&signal), sizeof(signal), 0); + } + } - return process_id; -} + auto IpcManager::NodeSession::send_packet(const u16 packet_id, const Span payload) -> Result + { + const std::scoped_lock lock(send_mutex); + if (!moni.is_valid()) + return fail("invalid MONI"); + return moni.push(packet_id, payload); + } -auto IpcManager::wait_till_node_is_online(const NativeProcessID node_id) - -> bool { - Mut is_pending = true; - while (is_pending) { - is_pending = false; - for (const Box &session : m_pending_sessions) { - if (session->node_process->id.load() == node_id) { - is_pending = true; - break; + IpcManager::IpcManager() + { + ensure(SocketOps::is_initialized(), "SocketOps must be initialized before using IpcManager"); + + m_receive_buffer.resize(UINT16_MAX + 1); + } + + IpcManager::~IpcManager() + { + for (MutRef> session : m_active_sessions) + { + ProcessOps::terminate_process(session->node_process); + FileOps::unmap_file(session->mapped_ptr); + FileOps::unlink_shared_memory(session->shared_mem_name); + SocketOps::close(session->data_socket); + } + m_active_sessions.clear(); + + for (MutRef> session : m_pending_sessions) + { + ProcessOps::terminate_process(session->node_process); + FileOps::unmap_file(session->mapped_ptr); + FileOps::unlink_shared_memory(session->shared_mem_name); + SocketOps::close(session->listener_socket); + } + m_pending_sessions.clear(); + } + + void IpcManager::update() + { + const std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); + + for (Mut i = static_cast(m_pending_sessions.size()) - 1; i >= 0; --i) + { + MutRef> session = m_pending_sessions[static_cast(i)]; + + if (now - session->creation_time > std::chrono::seconds(5)) + { + ProcessOps::terminate_process(session->node_process); + + FileOps::unmap_file(session->mapped_ptr); + FileOps::unlink_shared_memory(session->shared_mem_name); + SocketOps::close(session->listener_socket); + + m_pending_sessions.erase(m_pending_sessions.begin() + i); + continue; + } + +#if IA_PLATFORM_WINDOWS + Mut new_sock = accept(session->listener_socket, nullptr, nullptr); +#else + Mut new_sock = accept(session->listener_socket, nullptr, nullptr); +#endif + + if (new_sock != INVALID_SOCKET) + { + session->data_socket = new_sock; + session->is_ready = true; + +#if IA_PLATFORM_WINDOWS + Mut mode = 1; + ioctlsocket(session->data_socket, FIONBIO, &mode); +#else + fcntl(session->data_socket, F_SETFL, O_NONBLOCK); +#endif + + SocketOps::close(session->listener_socket); + session->listener_socket = INVALID_SOCKET; + + const NativeProcessID session_id = session->node_process->id.load(); + Mut session_ptr = session.get(); + m_active_sessions.push_back(std::move(session)); + m_pending_sessions.erase(m_pending_sessions.begin() + i); + m_active_session_map[session_id] = session_ptr; } } - update(); - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - } - return m_active_session_map.contains(node_id); -} -void IpcManager::shutdown_node(const NativeProcessID node_id) { - const HashMap::iterator it_node = - m_active_session_map.find(node_id); - if (it_node == m_active_session_map.end()) { - return; + for (Mut i = static_cast(m_active_sessions.size()) - 1; i >= 0; --i) + { + MutRef> node = m_active_sessions[static_cast(i)]; + + Mut node_id = node->node_process->id.load(); + + Mut header; + + while (node->mino.pop(header, Span(m_receive_buffer.data(), m_receive_buffer.size()))) + { + on_packet(node_id, header.id, {m_receive_buffer.data(), header.payload_size}); + } + + Mut signal = 0; + const isize res = recv(node->data_socket, reinterpret_cast(&signal), 1, 0); + + if (res == 1) + { + on_signal(node_id, signal); + } + else if (res == 0 || (res < 0 && !SocketOps::is_would_block())) + { + ProcessOps::terminate_process(node->node_process); + + FileOps::unmap_file(node->mapped_ptr); + FileOps::unlink_shared_memory(node->shared_mem_name); + SocketOps::close(node->data_socket); + + m_active_sessions.erase(m_active_sessions.begin() + i); + m_active_session_map.erase(node_id); + } + } } - Mut node = it_node->second; + auto IpcManager::spawn_node(Ref executable_path, const u32 shared_memory_size) -> Result + { + Mut> session = make_box(); - ProcessOps::terminate_process(node->node_process); - FileOps::unmap_file(node->mapped_ptr); - FileOps::unlink_shared_memory(node->shared_mem_name); - SocketOps::close(node->data_socket); + static Mut> s_id_gen{0}; + const u32 sid = ++s_id_gen; - std::erase_if(m_active_sessions, - [&](Ref> s) { return s.get() == node; }); - m_active_session_map.erase(it_node); -} + Mut sock_path; +#if IA_PLATFORM_WINDOWS + Mut temp_path; + GetTempPathA(MAX_PATH, temp_path); + sock_path = std::format("{}\\ia_sess_{}.sock", temp_path, sid); +#else + sock_path = std::format("/tmp/ia_sess_{}.sock", sid); +#endif -void IpcManager::send_signal(const NativeProcessID node, const u8 signal) { - const HashMap::iterator it_node = - m_active_session_map.find(node); - if (it_node == m_active_session_map.end()) { - return; + session->listener_socket = AU_TRY(SocketOps::create_unix_socket()); + AU_TRY_PURE(SocketOps::bind_unix_socket(session->listener_socket, sock_path.c_str())); + AU_TRY_PURE(SocketOps::listen(session->listener_socket, 1)); + +#if IA_PLATFORM_WINDOWS + Mut mode = 1; + ioctlsocket(session->listener_socket, FIONBIO, &mode); +#else + fcntl(session->listener_socket, F_SETFL, O_NONBLOCK); +#endif + + const String shm_name = std::format("ia_shm_{}", sid); + session->mapped_ptr = AU_TRY(FileOps::map_shared_memory(shm_name, shared_memory_size, true)); + + Mut layout = reinterpret_cast(session->mapped_ptr); + + layout->meta.magic = 0x49414950; + layout->meta.version = 1; + layout->meta.total_size = shared_memory_size; + + const u64 header_size = IpcSharedMemoryLayout::get_header_size(); + const u64 usable_bytes = shared_memory_size - header_size; + + Mut half_size = (usable_bytes / 2); + half_size -= (half_size % 64); + + layout->moni_data_offset = header_size; + layout->moni_data_size = half_size; + + layout->mino_data_offset = header_size + half_size; + layout->mino_data_size = half_size; + + session->moni = AU_TRY(RingBufferView::create( + &layout->moni_control, + Span(session->mapped_ptr + layout->moni_data_offset, static_cast(layout->moni_data_size)), true)); + + session->mino = AU_TRY(RingBufferView::create( + &layout->mino_control, + Span(session->mapped_ptr + layout->mino_data_offset, static_cast(layout->mino_data_size)), true)); + + Mut desc; + desc.socket_path = sock_path; + desc.shared_mem_path = shm_name; + desc.shared_mem_size = shared_memory_size; + + const String args = std::format("\"{}\"", desc.serialize()); + + session->node_process = AU_TRY(ProcessOps::spawn_process_async( + FileOps::normalize_executable_path(executable_path).string(), args, + [sid](StringView line) { + if (Env::IS_DEBUG) + { + std::cout << std::format("{}[Node:{}:STDOUT|STDERR]: {}{}\n", console::MAGENTA, sid, line, console::RESET); + } + }, + [sid](Result result) { + if (Env::IS_DEBUG) + { + if (!result) + { + std::cout << std::format("{}[Node: {}]: Failed to spawn with error '{}'{}\n", console::RED, sid, + result.error(), console::RESET); + } + else + { + std::cout << std::format("{}[Node: {}]: Exited with code {}{}\n", console::RED, sid, *result, + console::RESET); + } + } + })); + + std::this_thread::sleep_for(std::chrono::seconds(1)); + if (!session->node_process->is_active()) + { + return fail("Failed to spawn the child process \"{}\"", executable_path.string()); + } + + const NativeProcessID process_id = session->node_process->id.load(); + + session->shared_mem_name = shm_name; + session->creation_time = std::chrono::system_clock::now(); + m_pending_sessions.push_back(std::move(session)); + + return process_id; } - it_node->second->send_signal(signal); -} -auto IpcManager::send_packet(const NativeProcessID node, const u16 packet_id, - const Span payload) -> Result { - const HashMap::iterator it_node = - m_active_session_map.find(node); - if (it_node == m_active_session_map.end()) - return fail("no such node"); - return it_node->second->send_packet(packet_id, payload); -} + auto IpcManager::wait_till_node_is_online(const NativeProcessID node_id) -> bool + { + Mut is_pending = true; + while (is_pending) + { + is_pending = false; + for (const Box &session : m_pending_sessions) + { + if (session->node_process->id.load() == node_id) + { + is_pending = true; + break; + } + } + update(); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + return m_active_session_map.contains(node_id); + } + + void IpcManager::shutdown_node(const NativeProcessID node_id) + { + const HashMap::iterator it_node = m_active_session_map.find(node_id); + if (it_node == m_active_session_map.end()) + { + return; + } + + Mut node = it_node->second; + + ProcessOps::terminate_process(node->node_process); + FileOps::unmap_file(node->mapped_ptr); + FileOps::unlink_shared_memory(node->shared_mem_name); + SocketOps::close(node->data_socket); + + std::erase_if(m_active_sessions, [&](Ref> s) { return s.get() == node; }); + m_active_session_map.erase(it_node); + } + + void IpcManager::send_signal(const NativeProcessID node, const u8 signal) + { + const HashMap::iterator it_node = m_active_session_map.find(node); + if (it_node == m_active_session_map.end()) + { + return; + } + it_node->second->send_signal(signal); + } + + auto IpcManager::send_packet(const NativeProcessID node, const u16 packet_id, const Span payload) + -> Result + { + const HashMap::iterator it_node = m_active_session_map.find(node); + if (it_node == m_active_session_map.end()) + return fail("no such node"); + return it_node->second->send_packet(packet_id, payload); + } } // namespace IACore \ No newline at end of file diff --git a/Src/IACore/imp/cpp/JSON.cpp b/Src/IACore/imp/cpp/JSON.cpp index 7fbc6e8..28b3f64 100644 --- a/Src/IACore/imp/cpp/JSON.cpp +++ b/Src/IACore/imp/cpp/JSON.cpp @@ -15,4 +15,6 @@ #include -namespace IACore {} // namespace IACore \ No newline at end of file +namespace IACore +{ +} // namespace IACore \ No newline at end of file diff --git a/Src/IACore/imp/cpp/Logger.cpp b/Src/IACore/imp/cpp/Logger.cpp index 2597a19..0c8ac86 100644 --- a/Src/IACore/imp/cpp/Logger.cpp +++ b/Src/IACore/imp/cpp/Logger.cpp @@ -19,67 +19,76 @@ #include #include -namespace IACore { -Mut Logger::m_log_level = Logger::LogLevel::Info; -Mut Logger::m_log_file; +namespace IACore +{ + Mut Logger::m_log_level = Logger::LogLevel::Info; + Mut Logger::m_log_file; -static auto get_seconds_count() -> f64 { - static const std::chrono::time_point start_time = - std::chrono::steady_clock::now(); - const std::chrono::time_point now = - std::chrono::steady_clock::now(); - const std::chrono::duration duration = now - start_time; - return duration.count(); -} - -auto Logger::initialize() -> void {} - -auto Logger::terminate() -> void { - if (m_log_file.is_open()) { - m_log_file.flush(); - m_log_file.close(); - } -} - -auto Logger::enable_logging_to_disk(const char *file_path) -> Result { - if (m_log_file.is_open()) { - m_log_file.flush(); - m_log_file.close(); + static auto get_seconds_count() -> f64 + { + static const std::chrono::time_point start_time = std::chrono::steady_clock::now(); + const std::chrono::time_point now = std::chrono::steady_clock::now(); + const std::chrono::duration duration = now - start_time; + return duration.count(); } - m_log_file.open(file_path); - - if (!m_log_file.is_open()) { - return fail("Failed to open log file: {}", file_path); + auto Logger::initialize() -> void + { } - return {}; -} - -auto Logger::set_log_level(const LogLevel log_level) -> void { - m_log_level = log_level; -} - -auto Logger::flush_logs() -> void { - std::cout.flush(); - if (m_log_file.is_open()) { - m_log_file.flush(); + auto Logger::terminate() -> void + { + if (m_log_file.is_open()) + { + m_log_file.flush(); + m_log_file.close(); + } } -} -auto Logger::log_internal(const char *prefix, const char *tag, - ForwardRef msg) -> void { - const f64 seconds = get_seconds_count(); - const String out_line = - std::format("[{:>8.3f}]: [{}]: {}", seconds, tag, msg); + auto Logger::enable_logging_to_disk(const char *file_path) -> Result + { + if (m_log_file.is_open()) + { + m_log_file.flush(); + m_log_file.close(); + } - std::cout << prefix << out_line << console::RESET << '\n'; + m_log_file.open(file_path); - if (m_log_file.is_open()) { - m_log_file.write(out_line.data(), - static_cast(out_line.size())); - m_log_file.put('\n'); - m_log_file.flush(); + if (!m_log_file.is_open()) + { + return fail("Failed to open log file: {}", file_path); + } + + return {}; + } + + auto Logger::set_log_level(const LogLevel log_level) -> void + { + m_log_level = log_level; + } + + auto Logger::flush_logs() -> void + { + std::cout.flush(); + if (m_log_file.is_open()) + { + m_log_file.flush(); + } + } + + auto Logger::log_internal(const char *prefix, const char *tag, ForwardRef msg) -> void + { + const f64 seconds = get_seconds_count(); + const String out_line = std::format("[{:>8.3f}]: [{}]: {}", seconds, tag, msg); + + std::cout << prefix << out_line << console::RESET << '\n'; + + if (m_log_file.is_open()) + { + m_log_file.write(out_line.data(), static_cast(out_line.size())); + m_log_file.put('\n'); + m_log_file.flush(); + } } -} } // namespace IACore \ No newline at end of file diff --git a/Src/IACore/imp/cpp/Platform.cpp b/Src/IACore/imp/cpp/Platform.cpp index 718b282..de29121 100644 --- a/Src/IACore/imp/cpp/Platform.cpp +++ b/Src/IACore/imp/cpp/Platform.cpp @@ -16,119 +16,126 @@ #include #if defined(IA_ARCH_X64) -#ifndef _MSC_VER -#include -#endif +# ifndef _MSC_VER +# include +# endif #elif defined(IA_ARCH_ARM64) -#if defined(__linux__) || defined(__ANDROID__) -#include -#include -#endif +# if defined(__linux__) || defined(__ANDROID__) +# include +# include +# endif #endif -namespace IACore { -Mut Platform::s_capabilities{}; +namespace IACore +{ + Mut Platform::s_capabilities{}; #if defined(IA_ARCH_X64) -auto Platform::cpuid(const i32 function, const i32 sub_function, - Mut out[4]) -> void { -#ifdef _MSC_VER - __cpuidex(reinterpret_cast(out), static_cast(function), - static_cast(sub_function)); -#else - Mut a = 0; - Mut b = 0; - Mut c = 0; - Mut d = 0; - __cpuid_count(function, sub_function, a, b, c, d); - out[0] = static_cast(a); - out[1] = static_cast(b); - out[2] = static_cast(c); - out[3] = static_cast(d); -#endif -} + auto Platform::cpuid(const i32 function, const i32 sub_function, Mut out[4]) -> void + { +# ifdef _MSC_VER + __cpuidex(reinterpret_cast(out), static_cast(function), static_cast(sub_function)); +# else + Mut a = 0; + Mut b = 0; + Mut c = 0; + Mut d = 0; + __cpuid_count(function, sub_function, a, b, c, d); + out[0] = static_cast(a); + out[1] = static_cast(b); + out[2] = static_cast(c); + out[3] = static_cast(d); +# endif + } #endif -auto Platform::check_cpu() -> bool { + auto Platform::check_cpu() -> bool + { #if defined(IA_ARCH_X64) - Mut cpu_info[4]; + Mut cpu_info[4]; - cpuid(0, 0, cpu_info); - if (cpu_info[0] < 7) { - return false; - } + cpuid(0, 0, cpu_info); + if (cpu_info[0] < 7) + { + return false; + } - cpuid(1, 0, cpu_info); - const bool osxsave = (cpu_info[2] & (1 << 27)) != 0; - const bool avx = (cpu_info[2] & (1 << 28)) != 0; - const bool fma = (cpu_info[2] & (1 << 12)) != 0; + cpuid(1, 0, cpu_info); + const bool osxsave = (cpu_info[2] & (1 << 27)) != 0; + const bool avx = (cpu_info[2] & (1 << 28)) != 0; + const bool fma = (cpu_info[2] & (1 << 12)) != 0; - if (!osxsave || !avx || !fma) { - return false; - } + if (!osxsave || !avx || !fma) + { + return false; + } - const u64 xcr_feature_mask = _xgetbv(0); - if ((xcr_feature_mask & 0x6) != 0x6) { - return false; - } + const u64 xcr_feature_mask = _xgetbv(0); + if ((xcr_feature_mask & 0x6) != 0x6) + { + return false; + } - cpuid(7, 0, cpu_info); - const bool avx2 = (cpu_info[1] & (1 << 5)) != 0; - if (!avx2) { - return false; - } + cpuid(7, 0, cpu_info); + const bool avx2 = (cpu_info[1] & (1 << 5)) != 0; + if (!avx2) + { + return false; + } - s_capabilities.hardware_crc32 = true; + s_capabilities.hardware_crc32 = true; #elif defined(IA_ARCH_ARM64) -#if defined(__linux__) || defined(__ANDROID__) - const usize hw_caps = getauxval(AT_HWCAP); +# if defined(__linux__) || defined(__ANDROID__) + const usize hw_caps = getauxval(AT_HWCAP); -#ifndef HWCAP_CRC32 -#define HWCAP_CRC32 (1 << 7) -#endif +# ifndef HWCAP_CRC32 +# define HWCAP_CRC32 (1 << 7) +# endif - s_capabilities.hardware_crc32 = (hw_caps & HWCAP_CRC32) != 0; -#elif defined(IA_PLATFORM_APPLE) - s_capabilities.hardware_crc32 = true; + s_capabilities.hardware_crc32 = (hw_caps & HWCAP_CRC32) != 0; +# elif defined(IA_PLATFORM_APPLE) + s_capabilities.hardware_crc32 = true; +# else + s_capabilities.hardware_crc32 = false; +# endif #else - s_capabilities.hardware_crc32 = false; + s_capabilities.hardware_crc32 = false; #endif -#else - s_capabilities.hardware_crc32 = false; -#endif - return true; -} + return true; + } -auto Platform::get_architecture_name() -> const char * { + auto Platform::get_architecture_name() -> const char * + { #if defined(IA_ARCH_X64) - return "x86_64"; + return "x86_64"; #elif defined(IA_ARCH_ARM64) - return "aarch64"; + return "aarch64"; #elif defined(IA_ARCH_WASM) - return "wasm"; + return "wasm"; #else - return "unknown"; + return "unknown"; #endif -} + } -auto Platform::get_operating_system_name() -> const char * { + auto Platform::get_operating_system_name() -> const char * + { #if IA_PLATFORM_WINDOWS - return "Windows"; + return "Windows"; #elif defined(IA_PLATFORM_APPLE) -#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE - return "iOS"; -#else - return "macOS"; -#endif +# if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE + return "iOS"; +# else + return "macOS"; +# endif #elif defined(__ANDROID__) - return "Android"; + return "Android"; #elif IA_PLATFORM_LINUX - return "Linux"; + return "Linux"; #elif IA_PLATFORM_WASM - return "WebAssembly"; + return "WebAssembly"; #else - return "Unknown"; + return "Unknown"; #endif -} + } } // namespace IACore \ No newline at end of file diff --git a/Src/IACore/imp/cpp/ProcessOps.cpp b/Src/IACore/imp/cpp/ProcessOps.cpp index 16bc739..f1cc3c3 100644 --- a/Src/IACore/imp/cpp/ProcessOps.cpp +++ b/Src/IACore/imp/cpp/ProcessOps.cpp @@ -15,295 +15,341 @@ #include -namespace IACore { -struct LineBuffer { - Mut m_accumulator; - const std::function m_callback; +namespace IACore +{ + struct LineBuffer + { + Mut m_accumulator; + const std::function m_callback; - auto append(const char *data, const usize size) -> void; - auto flush() -> void; -}; + auto append(const char *data, const usize size) -> void; + auto flush() -> void; + }; -auto LineBuffer::append(const char *data, const usize size) -> void { - Mut start = 0; - for (Mut i = 0; i < size; ++i) { - if (data[i] == '\n' || data[i] == '\r') { - if (!m_accumulator.empty()) { - m_accumulator.append(data + start, i - start); - if (!m_accumulator.empty()) { - m_callback(m_accumulator); + auto LineBuffer::append(const char *data, const usize size) -> void + { + Mut start = 0; + for (Mut i = 0; i < size; ++i) + { + if (data[i] == '\n' || data[i] == '\r') + { + if (!m_accumulator.empty()) + { + m_accumulator.append(data + start, i - start); + if (!m_accumulator.empty()) + { + m_callback(m_accumulator); + } + m_accumulator.clear(); } - m_accumulator.clear(); - } else { - if (i > start) { - m_callback(StringView(data + start, i - start)); + else + { + if (i > start) + { + m_callback(StringView(data + start, i - start)); + } } - } - if (data[i] == '\r' && i + 1 < size && data[i + 1] == '\n') { - i++; + if (data[i] == '\r' && i + 1 < size && data[i + 1] == '\n') + { + i++; + } + start = i + 1; } - start = i + 1; + } + if (start < size) + { + m_accumulator.append(data + start, size - start); } } - if (start < size) { - m_accumulator.append(data + start, size - start); - } -} -auto LineBuffer::flush() -> void { - if (!m_accumulator.empty()) { - m_callback(m_accumulator); - m_accumulator.clear(); + auto LineBuffer::flush() -> void + { + if (!m_accumulator.empty()) + { + m_callback(m_accumulator); + m_accumulator.clear(); + } } -} -auto ProcessOps::get_current_process_id() -> NativeProcessID { + auto ProcessOps::get_current_process_id() -> NativeProcessID + { #if IA_PLATFORM_WINDOWS - return ::GetCurrentProcessId(); + return ::GetCurrentProcessId(); #else - return getpid(); + return getpid(); #endif -} - -auto ProcessOps::spawn_process_sync( - Ref command, Ref args, - const std::function on_output_line_callback) - -> Result { - Mut> id = 0; - if constexpr (Env::IS_WINDOWS) { - return spawn_process_windows(command, args, on_output_line_callback, id); - } else { - return spawn_process_posix(command, args, on_output_line_callback, id); } -} -auto ProcessOps::spawn_process_async( - Ref command, Ref args, - const std::function on_output_line_callback, - const std::function)> on_finish_callback) - -> Result> { - Mut> handle = make_box(); - handle->is_running = true; + auto ProcessOps::spawn_process_sync(Ref command, Ref args, + const std::function on_output_line_callback) -> Result + { + Mut> id = 0; + if constexpr (Env::IS_WINDOWS) + { + return spawn_process_windows(command, args, on_output_line_callback, id); + } + else + { + return spawn_process_posix(command, args, on_output_line_callback, id); + } + } - Mut h_ptr = handle.get(); + auto ProcessOps::spawn_process_async(Ref command, Ref args, + const std::function on_output_line_callback, + const std::function)> on_finish_callback) + -> Result> + { + Mut> handle = make_box(); + handle->is_running = true; - handle->m_thread_handle = std::jthread([h_ptr, cmd = command, arg = args, - cb = on_output_line_callback, - fin = on_finish_callback]() mutable { - Mut> result = fail("Platform not supported"); + Mut h_ptr = handle.get(); - if constexpr (Env::IS_WINDOWS) { - result = spawn_process_windows(cmd, arg, cb, h_ptr->id); - } else { - result = spawn_process_posix(cmd, arg, cb, h_ptr->id); + handle->m_thread_handle = std::jthread( + [h_ptr, cmd = command, arg = args, cb = on_output_line_callback, fin = on_finish_callback]() mutable { + Mut> result = fail("Platform not supported"); + + if constexpr (Env::IS_WINDOWS) + { + result = spawn_process_windows(cmd, arg, cb, h_ptr->id); + } + else + { + result = spawn_process_posix(cmd, arg, cb, h_ptr->id); + } + + h_ptr->is_running = false; + + if (fin) + { + if (!result) + { + fin(fail(std::move(result.error()))); + } + else + { + fin(*result); + } + } + }); + + return handle; + } + + auto ProcessOps::terminate_process(Ref> handle) -> void + { + if (!handle || !handle->is_active()) + { + return; } - h_ptr->is_running = false; - - if (fin) { - if (!result) { - fin(fail(std::move(result.error()))); - } else { - fin(*result); - } + const NativeProcessID pid = handle->id.load(); + if (pid == 0) + { + return; } - }); - - return handle; -} - -auto ProcessOps::terminate_process(Ref> handle) -> void { - if (!handle || !handle->is_active()) { - return; - } - - const NativeProcessID pid = handle->id.load(); - if (pid == 0) { - return; - } #if IA_PLATFORM_WINDOWS - Mut h_process = OpenProcess(PROCESS_TERMINATE, false, pid); - if (h_process != NULL) { - ::TerminateProcess(h_process, 9); - CloseHandle(h_process); - } + Mut h_process = OpenProcess(PROCESS_TERMINATE, false, pid); + if (h_process != NULL) + { + ::TerminateProcess(h_process, 9); + CloseHandle(h_process); + } #endif #if IA_PLATFORM_UNIX - kill(pid, SIGKILL); + kill(pid, SIGKILL); #endif -} + } -auto ProcessOps::spawn_process_windows( - Ref command, Ref args, - const std::function on_output_line_callback, - MutRef> id) -> Result { + auto ProcessOps::spawn_process_windows(Ref command, Ref args, + const std::function on_output_line_callback, + MutRef> id) -> Result + { #if IA_PLATFORM_WINDOWS - Mut sa_attr = {sizeof(SECURITY_ATTRIBUTES), NULL, true}; - Mut h_read = NULL; - Mut h_write = NULL; + Mut sa_attr = {sizeof(SECURITY_ATTRIBUTES), NULL, true}; + Mut h_read = NULL; + Mut h_write = NULL; - if (!CreatePipe(&h_read, &h_write, &sa_attr, 0)) { - return fail("Failed to create pipe"); - } - - if (!SetHandleInformation(h_read, HANDLE_FLAG_INHERIT, 0)) { - return fail("Failed to secure pipe handles"); - } - - Mut si = {sizeof(STARTUPINFOA)}; - si.dwFlags |= STARTF_USESTDHANDLES; - si.hStdOutput = h_write; - si.hStdError = h_write; - si.hStdInput = NULL; - - Mut pi = {0}; - - Mut command_line = std::format("\"{}\" {}", command, args); - - const BOOL success = CreateProcessA(NULL, command_line.data(), NULL, NULL, - true, 0, NULL, NULL, &si, &pi); - - CloseHandle(h_write); - - if (!success) { - CloseHandle(h_read); - return fail("CreateProcess failed: {}", GetLastError()); - } - - id.store(pi.dwProcessId); - - Mut line_buf{"", on_output_line_callback}; - Mut bytes_read = 0; - Mut> buffer; - - while (ReadFile(h_read, buffer.data(), static_cast(buffer.size()), - &bytes_read, NULL) && - bytes_read != 0) { - line_buf.append(buffer.data(), bytes_read); - } - line_buf.flush(); - - Mut exit_code = 0; - WaitForSingleObject(pi.hProcess, INFINITE); - GetExitCodeProcess(pi.hProcess, &exit_code); - - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); - CloseHandle(h_read); - id.store(0); - - return static_cast(exit_code); -#else - AU_UNUSED(command); - AU_UNUSED(args); - AU_UNUSED(on_output_line_callback); - AU_UNUSED(id); - return fail("Windows implementation not available."); -#endif -} - -auto ProcessOps::spawn_process_posix( - Ref command, Ref args, - const std::function on_output_line_callback, - MutRef> id) -> Result { -#if IA_PLATFORM_UNIX - Mut> pipefd; - if (pipe(pipefd.data()) == -1) { - return fail("Failed to create pipe"); - } - - const pid_t pid = fork(); - - if (pid == -1) { - return fail("Failed to fork process"); - } else if (pid == 0) { - close(pipefd[0]); - - dup2(pipefd[1], STDOUT_FILENO); - dup2(pipefd[1], STDERR_FILENO); - close(pipefd[1]); - - Mut> arg_storage; - Mut> argv; - - Mut cmd_str = command; - argv.push_back(cmd_str.data()); - - Mut current_token; - Mut in_quotes = false; - Mut is_escaped = false; - - for (const char c : args) { - if (is_escaped) { - current_token += c; - is_escaped = false; - continue; - } - - if (c == '\\') { - is_escaped = true; - continue; - } - - if (c == '\"') { - in_quotes = !in_quotes; - continue; - } - - if (c == ' ' && !in_quotes) { - if (!current_token.empty()) { - arg_storage.push_back(current_token); - current_token.clear(); - } - } else { - current_token += c; - } + if (!CreatePipe(&h_read, &h_write, &sa_attr, 0)) + { + return fail("Failed to create pipe"); } - if (!current_token.empty()) { - arg_storage.push_back(current_token); + if (!SetHandleInformation(h_read, HANDLE_FLAG_INHERIT, 0)) + { + return fail("Failed to secure pipe handles"); } - for (MutRef s : arg_storage) { - argv.push_back(s.data()); + Mut si = {sizeof(STARTUPINFOA)}; + si.dwFlags |= STARTF_USESTDHANDLES; + si.hStdOutput = h_write; + si.hStdError = h_write; + si.hStdInput = NULL; + + Mut pi = {0}; + + Mut command_line = std::format("\"{}\" {}", command, args); + + const BOOL success = CreateProcessA(NULL, command_line.data(), NULL, NULL, true, 0, NULL, NULL, &si, &pi); + + CloseHandle(h_write); + + if (!success) + { + CloseHandle(h_read); + return fail("CreateProcess failed: {}", GetLastError()); } - argv.push_back(nullptr); - execvp(argv[0], argv.data()); - _exit(127); - } else { - id.store(pid); - - close(pipefd[1]); + id.store(pi.dwProcessId); Mut line_buf{"", on_output_line_callback}; + Mut bytes_read = 0; Mut> buffer; - Mut count; - while ((count = read(pipefd[0], buffer.data(), buffer.size())) > 0) { - line_buf.append(buffer.data(), static_cast(count)); + while (ReadFile(h_read, buffer.data(), static_cast(buffer.size()), &bytes_read, NULL) && bytes_read != 0) + { + line_buf.append(buffer.data(), bytes_read); } line_buf.flush(); - close(pipefd[0]); - Mut status; - waitpid(pid, &status, 0); + Mut exit_code = 0; + WaitForSingleObject(pi.hProcess, INFINITE); + GetExitCodeProcess(pi.hProcess, &exit_code); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + CloseHandle(h_read); id.store(0); - if (WIFEXITED(status)) { - return WEXITSTATUS(status); - } - return -1; - } + + return static_cast(exit_code); #else - AU_UNUSED(command); - AU_UNUSED(args); - AU_UNUSED(on_output_line_callback); - AU_UNUSED(id); - return fail("Posix implementation not available."); + AU_UNUSED(command); + AU_UNUSED(args); + AU_UNUSED(on_output_line_callback); + AU_UNUSED(id); + return fail("Windows implementation not available."); #endif -} + } + + auto ProcessOps::spawn_process_posix(Ref command, Ref args, + const std::function on_output_line_callback, + MutRef> id) -> Result + { +#if IA_PLATFORM_UNIX + Mut> pipefd; + if (pipe(pipefd.data()) == -1) + { + return fail("Failed to create pipe"); + } + + const pid_t pid = fork(); + + if (pid == -1) + { + return fail("Failed to fork process"); + } + else if (pid == 0) + { + close(pipefd[0]); + + dup2(pipefd[1], STDOUT_FILENO); + dup2(pipefd[1], STDERR_FILENO); + close(pipefd[1]); + + Mut> arg_storage; + Mut> argv; + + Mut cmd_str = command; + argv.push_back(cmd_str.data()); + + Mut current_token; + Mut in_quotes = false; + Mut is_escaped = false; + + for (const char c : args) + { + if (is_escaped) + { + current_token += c; + is_escaped = false; + continue; + } + + if (c == '\\') + { + is_escaped = true; + continue; + } + + if (c == '\"') + { + in_quotes = !in_quotes; + continue; + } + + if (c == ' ' && !in_quotes) + { + if (!current_token.empty()) + { + arg_storage.push_back(current_token); + current_token.clear(); + } + } + else + { + current_token += c; + } + } + + if (!current_token.empty()) + { + arg_storage.push_back(current_token); + } + + for (MutRef s : arg_storage) + { + argv.push_back(s.data()); + } + argv.push_back(nullptr); + + execvp(argv[0], argv.data()); + _exit(127); + } + else + { + id.store(pid); + + close(pipefd[1]); + + Mut line_buf{"", on_output_line_callback}; + Mut> buffer; + Mut count; + + while ((count = read(pipefd[0], buffer.data(), buffer.size())) > 0) + { + line_buf.append(buffer.data(), static_cast(count)); + } + line_buf.flush(); + close(pipefd[0]); + + Mut status; + waitpid(pid, &status, 0); + + id.store(0); + if (WIFEXITED(status)) + { + return WEXITSTATUS(status); + } + return -1; + } +#else + AU_UNUSED(command); + AU_UNUSED(args); + AU_UNUSED(on_output_line_callback); + AU_UNUSED(id); + return fail("Posix implementation not available."); +#endif + } } // namespace IACore \ No newline at end of file diff --git a/Src/IACore/imp/cpp/SIMD.cpp b/Src/IACore/imp/cpp/SIMD.cpp index 687d33a..1fa9def 100644 --- a/Src/IACore/imp/cpp/SIMD.cpp +++ b/Src/IACore/imp/cpp/SIMD.cpp @@ -15,4 +15,6 @@ #include -namespace IACore {} // namespace IACore \ No newline at end of file +namespace IACore +{ +} // namespace IACore \ No newline at end of file diff --git a/Src/IACore/imp/cpp/SocketOps.cpp b/Src/IACore/imp/cpp/SocketOps.cpp index ec8e3b4..a84bb90 100644 --- a/Src/IACore/imp/cpp/SocketOps.cpp +++ b/Src/IACore/imp/cpp/SocketOps.cpp @@ -14,133 +14,143 @@ // limitations under the License. #include -#include -namespace IACore { -Mut SocketOps::s_init_count = 0; +namespace IACore +{ + Mut SocketOps::s_init_count = 0; -auto SocketOps::close(const SocketHandle sock) -> void { - if (sock == INVALID_SOCKET) { - return; - } + auto SocketOps::close(const SocketHandle sock) -> void + { + if (sock == INVALID_SOCKET) + { + return; + } #if IA_PLATFORM_WINDOWS - closesocket(sock); + closesocket(sock); #else - ::close(sock); + ::close(sock); #endif -} + } + + auto SocketOps::listen(const SocketHandle sock, const i32 queue_size) -> Result + { + if (::listen(sock, queue_size) == 0) + { + return {}; + } + +#if IA_PLATFORM_WINDOWS + return fail("listen failed: {}", WSAGetLastError()); +#else + return fail("listen failed: {}", errno); +#endif + } + + auto SocketOps::create_unix_socket() -> Result + { + const SocketHandle sock = socket(AF_UNIX, SOCK_STREAM, 0); + if (sock == INVALID_SOCKET) + { +#if IA_PLATFORM_WINDOWS + return fail("socket(AF_UNIX) failed: {}", WSAGetLastError()); +#else + return fail("socket(AF_UNIX) failed: {}", errno); +#endif + } + return sock; + } + + auto SocketOps::bind_unix_socket(const SocketHandle sock, const char *path) -> Result + { + if (sock == INVALID_SOCKET) + { + return fail("Invalid socket handle"); + } + + unlink_file(path); + + Mut addr{}; + addr.sun_family = AF_UNIX; + + const usize max_len = sizeof(addr.sun_path) - 1; +#if IA_PLATFORM_WINDOWS + strncpy_s(addr.sun_path, sizeof(addr.sun_path), path, max_len); +#else + std::strncpy(addr.sun_path, path, max_len); +#endif + + if (::bind(sock, reinterpret_cast(&addr), sizeof(addr)) == -1) + { +#if IA_PLATFORM_WINDOWS + return fail("bind failed: {}", WSAGetLastError()); +#else + return fail("bind failed: {}", errno); +#endif + } -auto SocketOps::listen(const SocketHandle sock, const i32 queue_size) - -> Result { - if (::listen(sock, queue_size) == 0) { return {}; } + auto SocketOps::connect_unix_socket(const SocketHandle sock, const char *path) -> Result + { + if (sock == INVALID_SOCKET) + { + return fail("Invalid socket handle"); + } + + Mut addr{}; + addr.sun_family = AF_UNIX; + + const usize max_len = sizeof(addr.sun_path) - 1; #if IA_PLATFORM_WINDOWS - return fail("listen failed: {}", WSAGetLastError()); + strncpy_s(addr.sun_path, sizeof(addr.sun_path), path, max_len); #else - return fail("listen failed: {}", errno); -#endif -} - -auto SocketOps::create_unix_socket() -> Result { - const SocketHandle sock = socket(AF_UNIX, SOCK_STREAM, 0); - if (sock == INVALID_SOCKET) { -#if IA_PLATFORM_WINDOWS - return fail("socket(AF_UNIX) failed: {}", WSAGetLastError()); -#else - return fail("socket(AF_UNIX) failed: {}", errno); -#endif - } - return sock; -} - -auto SocketOps::bind_unix_socket(const SocketHandle sock, const char *path) - -> Result { - if (sock == INVALID_SOCKET) { - return fail("Invalid socket handle"); - } - - unlink_file(path); - - Mut addr{}; - addr.sun_family = AF_UNIX; - - const usize max_len = sizeof(addr.sun_path) - 1; -#if IA_PLATFORM_WINDOWS - strncpy_s(addr.sun_path, sizeof(addr.sun_path), path, max_len); -#else - std::strncpy(addr.sun_path, path, max_len); + std::strncpy(addr.sun_path, path, max_len); #endif - if (::bind(sock, reinterpret_cast(&addr), sizeof(addr)) == - -1) { + if (::connect(sock, reinterpret_cast(&addr), sizeof(addr)) == -1) + { #if IA_PLATFORM_WINDOWS - return fail("bind failed: {}", WSAGetLastError()); + return fail("connect failed: {}", WSAGetLastError()); #else - return fail("bind failed: {}", errno); + return fail("connect failed: {}", errno); +#endif + } + + return {}; + } + + auto SocketOps::is_port_available(const u16 port, const i32 type) -> bool + { + const SocketHandle sock = socket(AF_INET, type, 0); + if (sock == INVALID_SOCKET) + { + return false; + } + + Mut addr{}; + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = htonl(INADDR_ANY); + + Mut is_free = false; + if (::bind(sock, reinterpret_cast(&addr), sizeof(addr)) == 0) + { + is_free = true; + } + + close(sock); + + return is_free; + } + + auto SocketOps::is_would_block() -> bool + { +#if IA_PLATFORM_WINDOWS + return WSAGetLastError() == WSAEWOULDBLOCK; +#else + return errno == EWOULDBLOCK || errno == EAGAIN; #endif } - return {}; -} - -auto SocketOps::connect_unix_socket(const SocketHandle sock, const char *path) - -> Result { - if (sock == INVALID_SOCKET) { - return fail("Invalid socket handle"); - } - - Mut addr{}; - addr.sun_family = AF_UNIX; - - const usize max_len = sizeof(addr.sun_path) - 1; -#if IA_PLATFORM_WINDOWS - strncpy_s(addr.sun_path, sizeof(addr.sun_path), path, max_len); -#else - std::strncpy(addr.sun_path, path, max_len); -#endif - - if (::connect(sock, reinterpret_cast(&addr), - sizeof(addr)) == -1) { -#if IA_PLATFORM_WINDOWS - return fail("connect failed: {}", WSAGetLastError()); -#else - return fail("connect failed: {}", errno); -#endif - } - - return {}; -} - -auto SocketOps::is_port_available(const u16 port, const i32 type) -> bool { - const SocketHandle sock = socket(AF_INET, type, 0); - if (sock == INVALID_SOCKET) { - return false; - } - - Mut addr{}; - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr.s_addr = htonl(INADDR_ANY); - - Mut is_free = false; - if (::bind(sock, reinterpret_cast(&addr), sizeof(addr)) == - 0) { - is_free = true; - } - - close(sock); - - return is_free; -} - -auto SocketOps::is_would_block() -> bool { -#if IA_PLATFORM_WINDOWS - return WSAGetLastError() == WSAEWOULDBLOCK; -#else - return errno == EWOULDBLOCK || errno == EAGAIN; -#endif -} - } // namespace IACore \ No newline at end of file diff --git a/Src/IACore/imp/cpp/StreamReader.cpp b/Src/IACore/imp/cpp/StreamReader.cpp index cdce378..fd1c13d 100644 --- a/Src/IACore/imp/cpp/StreamReader.cpp +++ b/Src/IACore/imp/cpp/StreamReader.cpp @@ -16,70 +16,78 @@ #include #include -namespace IACore { -auto StreamReader::create_from_file(Ref path) -> Result { - Mut size = 0; +namespace IACore +{ + auto StreamReader::create_from_file(Ref path) -> Result + { + Mut size = 0; - const u8 *ptr = AU_TRY(FileOps::map_file(path, size)); + const u8 *ptr = AU_TRY(FileOps::map_file(path, size)); - Mut reader(Span(ptr, size)); - reader.m_storage_type = StorageType::OwningMmap; + Mut reader(Span(ptr, size)); + reader.m_storage_type = StorageType::OwningMmap; - return reader; -} - -StreamReader::StreamReader(ForwardRef> data) - : m_owning_vector(std::move(data)), - m_storage_type(StorageType::OwningVector) { - m_data = m_owning_vector.data(); - m_data_size = m_owning_vector.size(); -} - -StreamReader::StreamReader(const Span data) - : m_data(data.data()), m_data_size(data.size()), - m_storage_type(StorageType::NonOwning) {} - -StreamReader::StreamReader(ForwardRef other) - : m_data(other.m_data), m_cursor(other.m_cursor), - m_data_size(other.m_data_size), - m_owning_vector(std::move(other.m_owning_vector)), - m_storage_type(other.m_storage_type) { - other.m_storage_type = StorageType::NonOwning; - other.m_data = {}; - other.m_data_size = 0; - - if (m_storage_type == StorageType::OwningVector) { - m_data = m_owning_vector.data(); + return reader; } -} -auto StreamReader::operator=(ForwardRef other) - -> MutRef { - if (this != &other) { - if (m_storage_type == StorageType::OwningMmap) { - FileOps::unmap_file(m_data); - } + StreamReader::StreamReader(ForwardRef> data) + : m_owning_vector(std::move(data)), m_storage_type(StorageType::OwningVector) + { + m_data = m_owning_vector.data(); + m_data_size = m_owning_vector.size(); + } - m_data = other.m_data; - m_cursor = other.m_cursor; - m_data_size = other.m_data_size; - m_owning_vector = std::move(other.m_owning_vector); - m_storage_type = other.m_storage_type; - - if (m_storage_type == StorageType::OwningVector) { - m_data = m_owning_vector.data(); - } + StreamReader::StreamReader(const Span data) + : m_data(data.data()), m_data_size(data.size()), m_storage_type(StorageType::NonOwning) + { + } + StreamReader::StreamReader(ForwardRef other) + : m_data(other.m_data), m_cursor(other.m_cursor), m_data_size(other.m_data_size), + m_owning_vector(std::move(other.m_owning_vector)), m_storage_type(other.m_storage_type) + { other.m_storage_type = StorageType::NonOwning; other.m_data = {}; other.m_data_size = 0; - } - return *this; -} -StreamReader::~StreamReader() { - if (m_storage_type == StorageType::OwningMmap) { - FileOps::unmap_file(m_data); + if (m_storage_type == StorageType::OwningVector) + { + m_data = m_owning_vector.data(); + } + } + + auto StreamReader::operator=(ForwardRef other) -> MutRef + { + if (this != &other) + { + if (m_storage_type == StorageType::OwningMmap) + { + FileOps::unmap_file(m_data); + } + + m_data = other.m_data; + m_cursor = other.m_cursor; + m_data_size = other.m_data_size; + m_owning_vector = std::move(other.m_owning_vector); + m_storage_type = other.m_storage_type; + + if (m_storage_type == StorageType::OwningVector) + { + m_data = m_owning_vector.data(); + } + + other.m_storage_type = StorageType::NonOwning; + other.m_data = {}; + other.m_data_size = 0; + } + return *this; + } + + StreamReader::~StreamReader() + { + if (m_storage_type == StorageType::OwningMmap) + { + FileOps::unmap_file(m_data); + } } -} } // namespace IACore \ No newline at end of file diff --git a/Src/IACore/imp/cpp/StreamWriter.cpp b/Src/IACore/imp/cpp/StreamWriter.cpp index 9095a99..4606be7 100644 --- a/Src/IACore/imp/cpp/StreamWriter.cpp +++ b/Src/IACore/imp/cpp/StreamWriter.cpp @@ -15,147 +15,168 @@ #include -namespace IACore { +namespace IACore +{ -auto StreamWriter::create_from_file(Ref path) -> Result { - Mut f = std::fopen(path.string().c_str(), "wb"); - if (!f) { - return fail("Failed to open file for writing: {}", path.string()); - } - std::fclose(f); - - Mut writer; - writer.m_file_path = path; - writer.m_storage_type = StorageType::OwningFile; - - return writer; -} - -StreamWriter::StreamWriter() : m_storage_type(StorageType::OwningVector) { - m_capacity = 256; - m_owning_vector.resize(m_capacity); - m_buffer = m_owning_vector.data(); -} - -StreamWriter::StreamWriter(const Span data) - : m_buffer(data.data()), m_cursor(0), m_capacity(data.size()), - m_storage_type(StorageType::NonOwning) {} - -StreamWriter::StreamWriter(ForwardRef other) - : m_buffer(other.m_buffer), m_cursor(other.m_cursor), - m_capacity(other.m_capacity), m_file_path(other.m_file_path), - m_owning_vector(std::move(other.m_owning_vector)), - m_storage_type(other.m_storage_type) { - other.m_capacity = {}; - other.m_buffer = {}; - other.m_storage_type = StorageType::NonOwning; - - if (m_storage_type == StorageType::OwningVector) - m_buffer = m_owning_vector.data(); -} - -auto StreamWriter::operator=(ForwardRef other) - -> MutRef { - if (this != &other) { - if (m_storage_type == StorageType::OwningFile) { - if (const Result res = flush_to_disk(); !res) { - std::fprintf(stderr, "[IACore] Data loss in StreamWriter move: %s\n", - res.error().c_str()); - } + auto StreamWriter::create_from_file(Ref path) -> Result + { + Mut f = std::fopen(path.string().c_str(), "wb"); + if (!f) + { + return fail("Failed to open file for writing: {}", path.string()); } + std::fclose(f); - m_buffer = other.m_buffer; - m_cursor = other.m_cursor; - m_capacity = other.m_capacity; - m_file_path = std::move(other.m_file_path); - m_owning_vector = std::move(other.m_owning_vector); - m_storage_type = other.m_storage_type; + Mut writer; + writer.m_file_path = path; + writer.m_storage_type = StorageType::OwningFile; + + return writer; + } + + StreamWriter::StreamWriter() : m_storage_type(StorageType::OwningVector) + { + m_capacity = 256; + m_owning_vector.resize(m_capacity); + m_buffer = m_owning_vector.data(); + } + + StreamWriter::StreamWriter(const Span data) + : m_buffer(data.data()), m_cursor(0), m_capacity(data.size()), m_storage_type(StorageType::NonOwning) + { + } + + StreamWriter::StreamWriter(ForwardRef other) + : m_buffer(other.m_buffer), m_cursor(other.m_cursor), m_capacity(other.m_capacity), + m_file_path(other.m_file_path), m_owning_vector(std::move(other.m_owning_vector)), + m_storage_type(other.m_storage_type) + { + other.m_capacity = {}; + other.m_buffer = {}; + other.m_storage_type = StorageType::NonOwning; if (m_storage_type == StorageType::OwningVector) m_buffer = m_owning_vector.data(); - - other.m_capacity = 0; - other.m_cursor = 0; - other.m_buffer = nullptr; - other.m_storage_type = StorageType::NonOwning; } - return *this; -} -StreamWriter::~StreamWriter() { - if (m_storage_type == StorageType::OwningFile) { - if (const Result res = flush_to_disk(); !res) { - std::fprintf(stderr, "[IACore] LOST DATA in ~StreamWriter: %s\n", - res.error().c_str()); + auto StreamWriter::operator=(ForwardRef other) -> MutRef + { + if (this != &other) + { + if (m_storage_type == StorageType::OwningFile) + { + if (const Result res = flush_to_disk(); !res) + { + std::fprintf(stderr, "[IACore] Data loss in StreamWriter move: %s\n", res.error().c_str()); + } + } + + m_buffer = other.m_buffer; + m_cursor = other.m_cursor; + m_capacity = other.m_capacity; + m_file_path = std::move(other.m_file_path); + m_owning_vector = std::move(other.m_owning_vector); + m_storage_type = other.m_storage_type; + + if (m_storage_type == StorageType::OwningVector) + m_buffer = m_owning_vector.data(); + + other.m_capacity = 0; + other.m_cursor = 0; + other.m_buffer = nullptr; + other.m_storage_type = StorageType::NonOwning; + } + return *this; + } + + StreamWriter::~StreamWriter() + { + if (m_storage_type == StorageType::OwningFile) + { + if (const Result res = flush_to_disk(); !res) + { + std::fprintf(stderr, "[IACore] LOST DATA in ~StreamWriter: %s\n", res.error().c_str()); + } } } -} -auto StreamWriter::flush() -> Result { - Mut> res = flush_to_disk(); - if (res.has_value()) { - m_storage_type = StorageType::OwningVector; + auto StreamWriter::flush() -> Result + { + Mut> res = flush_to_disk(); + if (res.has_value()) + { + m_storage_type = StorageType::OwningVector; + } + return res; } - return res; -} -auto StreamWriter::flush_to_disk() -> Result { - if (m_storage_type != StorageType::OwningFile || m_file_path.empty()) { + auto StreamWriter::flush_to_disk() -> Result + { + if (m_storage_type != StorageType::OwningFile || m_file_path.empty()) + { + return {}; + } + + Mut f = std::fopen(m_file_path.string().c_str(), "wb"); + if (!f) + { + return fail("Failed to open file for writing: {}", m_file_path.string()); + } + + const usize written = std::fwrite(m_buffer, 1, m_cursor, f); + std::fclose(f); + + if (written != m_cursor) + { + return fail("Incomplete write: {} of {} bytes written", written, m_cursor); + } return {}; } - Mut f = std::fopen(m_file_path.string().c_str(), "wb"); - if (!f) { - return fail("Failed to open file for writing: {}", m_file_path.string()); - } + auto StreamWriter::write(const u8 byte, const usize count) -> Result + { + if (m_cursor + count > m_capacity) + { + if (m_storage_type == StorageType::NonOwning) + { + return fail("StreamWriter buffer overflow (NonOwning)"); + } - const usize written = std::fwrite(m_buffer, 1, m_cursor, f); - std::fclose(f); + const usize required = m_cursor + count; + const usize double_cap = m_capacity * 2; + const usize new_capacity = (double_cap > required) ? double_cap : required; - if (written != m_cursor) { - return fail("Incomplete write: {} of {} bytes written", written, m_cursor); - } - return {}; -} - -auto StreamWriter::write(const u8 byte, const usize count) -> Result { - if (m_cursor + count > m_capacity) { - if (m_storage_type == StorageType::NonOwning) { - return fail("StreamWriter buffer overflow (NonOwning)"); + m_owning_vector.resize(new_capacity); + m_capacity = m_owning_vector.size(); + m_buffer = m_owning_vector.data(); } - const usize required = m_cursor + count; - const usize double_cap = m_capacity * 2; - const usize new_capacity = (double_cap > required) ? double_cap : required; - - m_owning_vector.resize(new_capacity); - m_capacity = m_owning_vector.size(); - m_buffer = m_owning_vector.data(); + std::memset(m_buffer + m_cursor, byte, count); + m_cursor += count; + return {}; } - std::memset(m_buffer + m_cursor, byte, count); - m_cursor += count; - return {}; -} + auto StreamWriter::write(const void *buffer, const usize size) -> Result + { + if (m_cursor + size > m_capacity) + { + if (m_storage_type == StorageType::NonOwning) + { + return fail("StreamWriter buffer overflow (NonOwning)"); + } -auto StreamWriter::write(const void *buffer, const usize size) -> Result { - if (m_cursor + size > m_capacity) { - if (m_storage_type == StorageType::NonOwning) { - return fail("StreamWriter buffer overflow (NonOwning)"); + const usize required = m_cursor + size; + const usize double_cap = m_capacity * 2; + const usize new_capacity = (double_cap > required) ? double_cap : required; + + m_owning_vector.resize(new_capacity); + m_capacity = m_owning_vector.size(); + m_buffer = m_owning_vector.data(); } - const usize required = m_cursor + size; - const usize double_cap = m_capacity * 2; - const usize new_capacity = (double_cap > required) ? double_cap : required; - - m_owning_vector.resize(new_capacity); - m_capacity = m_owning_vector.size(); - m_buffer = m_owning_vector.data(); + std::memcpy(m_buffer + m_cursor, buffer, size); + m_cursor += size; + return {}; } - std::memcpy(m_buffer + m_cursor, buffer, size); - m_cursor += size; - return {}; -} - } // namespace IACore \ No newline at end of file diff --git a/Src/IACore/imp/cpp/StringOps.cpp b/Src/IACore/imp/cpp/StringOps.cpp index a1bfe0a..7b55923 100644 --- a/Src/IACore/imp/cpp/StringOps.cpp +++ b/Src/IACore/imp/cpp/StringOps.cpp @@ -15,108 +15,126 @@ #include -namespace IACore { +namespace IACore +{ -static const String BASE64_CHAR_TABLE = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + static const String BASE64_CHAR_TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -static auto is_base64(const u8 c) -> bool { - return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || - (c >= '0' && c <= '9') || (c == '+') || (c == '/'); -} - -static auto get_base64_index(const u8 c) -> u8 { - if (c >= 'A' && c <= 'Z') - return c - 'A'; - if (c >= 'a' && c <= 'z') - return c - 'a' + 26; - if (c >= '0' && c <= '9') - return c - '0' + 52; - if (c == '+') - return 62; - if (c == '/') - return 63; - return 0; -} - -auto StringOps::encode_base64(const Span data) -> String { - Mut result; - result.reserve(((data.size() + 2) / 3) * 4); - - for (Mut i = 0; i < data.size(); i += 3) { - const u32 b0 = data[i]; - const u32 b1 = (i + 1 < data.size()) ? data[i + 1] : 0; - const u32 b2 = (i + 2 < data.size()) ? data[i + 2] : 0; - - const u32 triple = (b0 << 16) | (b1 << 8) | b2; - - result += BASE64_CHAR_TABLE[(triple >> 18) & 0x3F]; - result += BASE64_CHAR_TABLE[(triple >> 12) & 0x3F]; - - if (i + 1 < data.size()) { - result += BASE64_CHAR_TABLE[(triple >> 6) & 0x3F]; - } else { - result += '='; - } - - if (i + 2 < data.size()) { - result += BASE64_CHAR_TABLE[triple & 0x3F]; - } else { - result += '='; - } + static auto is_base64(const u8 c) -> bool + { + return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || (c == '+') || (c == '/'); } - return result; -} -auto StringOps::decode_base64(Ref data) -> Vec { - Mut> result; - result.reserve(data.size() * 3 / 4); + static auto get_base64_index(const u8 c) -> u8 + { + if (c >= 'A' && c <= 'Z') + return c - 'A'; + if (c >= 'a' && c <= 'z') + return c - 'a' + 26; + if (c >= '0' && c <= '9') + return c - '0' + 52; + if (c == '+') + return 62; + if (c == '/') + return 63; + return 0; + } - Mut i = 0; - Mut> tmp_buf = {}; + auto StringOps::encode_base64(const Span data) -> String + { + Mut result; + result.reserve(((data.size() + 2) / 3) * 4); - for (const char c_char : data) { - const u8 c = static_cast(c_char); - if (c == '=') { - break; + for (Mut i = 0; i < data.size(); i += 3) + { + const u32 b0 = data[i]; + const u32 b1 = (i + 1 < data.size()) ? data[i + 1] : 0; + const u32 b2 = (i + 2 < data.size()) ? data[i + 2] : 0; + + const u32 triple = (b0 << 16) | (b1 << 8) | b2; + + result += BASE64_CHAR_TABLE[(triple >> 18) & 0x3F]; + result += BASE64_CHAR_TABLE[(triple >> 12) & 0x3F]; + + if (i + 1 < data.size()) + { + result += BASE64_CHAR_TABLE[(triple >> 6) & 0x3F]; + } + else + { + result += '='; + } + + if (i + 2 < data.size()) + { + result += BASE64_CHAR_TABLE[triple & 0x3F]; + } + else + { + result += '='; + } } - if (!is_base64(c)) { - break; + return result; + } + + auto StringOps::decode_base64(Ref data) -> Vec + { + Mut> result; + result.reserve(data.size() * 3 / 4); + + Mut i = 0; + Mut> tmp_buf = {}; + + for (const char c_char : data) + { + const u8 c = static_cast(c_char); + if (c == '=') + { + break; + } + if (!is_base64(c)) + { + break; + } + + tmp_buf[i++] = c; + if (i == 4) + { + const u8 n0 = get_base64_index(tmp_buf[0]); + const u8 n1 = get_base64_index(tmp_buf[1]); + const u8 n2 = get_base64_index(tmp_buf[2]); + const u8 n3 = get_base64_index(tmp_buf[3]); + + result.push_back((n0 << 2) | ((n1 & 0x30) >> 4)); + result.push_back(((n1 & 0x0F) << 4) | ((n2 & 0x3C) >> 2)); + result.push_back(((n2 & 0x03) << 6) | n3); + + i = 0; + } } - tmp_buf[i++] = c; - if (i == 4) { + if (i > 0) + { + for (Mut j = i; j < 4; ++j) + { + tmp_buf[j] = 'A'; + } + const u8 n0 = get_base64_index(tmp_buf[0]); const u8 n1 = get_base64_index(tmp_buf[1]); const u8 n2 = get_base64_index(tmp_buf[2]); - const u8 n3 = get_base64_index(tmp_buf[3]); - result.push_back((n0 << 2) | ((n1 & 0x30) >> 4)); - result.push_back(((n1 & 0x0F) << 4) | ((n2 & 0x3C) >> 2)); - result.push_back(((n2 & 0x03) << 6) | n3); - - i = 0; + if (i > 1) + { + result.push_back((n0 << 2) | ((n1 & 0x30) >> 4)); + } + if (i > 2) + { + result.push_back(((n1 & 0x0F) << 4) | ((n2 & 0x3C) >> 2)); + } } + + return result; } - if (i > 0) { - for (Mut j = i; j < 4; ++j) { - tmp_buf[j] = 'A'; - } - - const u8 n0 = get_base64_index(tmp_buf[0]); - const u8 n1 = get_base64_index(tmp_buf[1]); - const u8 n2 = get_base64_index(tmp_buf[2]); - - if (i > 1) { - result.push_back((n0 << 2) | ((n1 & 0x30) >> 4)); - } - if (i > 2) { - result.push_back(((n1 & 0x0F) << 4) | ((n2 & 0x3C) >> 2)); - } - } - - return result; -} - } // namespace IACore \ No newline at end of file diff --git a/Src/IACore/imp/cpp/Utils.cpp b/Src/IACore/imp/cpp/Utils.cpp index 401f2b7..3bb9ab9 100644 --- a/Src/IACore/imp/cpp/Utils.cpp +++ b/Src/IACore/imp/cpp/Utils.cpp @@ -17,96 +17,110 @@ #include #include -namespace IACore { -namespace { -auto from_hex_char(const char c) -> i32 { - if (c >= '0' && c <= '9') { - return c - '0'; - } - if (c >= 'A' && c <= 'F') { - return c - 'A' + 10; - } - if (c >= 'a' && c <= 'f') { - return c - 'a' + 10; - } - return -1; -} -} // namespace +namespace IACore +{ + namespace + { + auto from_hex_char(const char c) -> i32 + { + if (c >= '0' && c <= '9') + { + return c - '0'; + } + if (c >= 'A' && c <= 'F') + { + return c - 'A' + 10; + } + if (c >= 'a' && c <= 'f') + { + return c - 'a' + 10; + } + return -1; + } + } // namespace -extern Mut g_start_time; + extern Mut g_start_time; -auto Utils::get_unix_time() -> u64 { - const std::chrono::system_clock::time_point now = - std::chrono::system_clock::now(); - return std::chrono::duration_cast( - now.time_since_epoch()) - .count(); -} - -auto Utils::get_ticks_count() -> u64 { - const std::chrono::high_resolution_clock::duration duration = - std::chrono::high_resolution_clock::now() - g_start_time; - return std::chrono::duration_cast(duration) - .count(); -} - -auto Utils::get_seconds_count() -> f64 { - const std::chrono::high_resolution_clock::duration duration = - std::chrono::high_resolution_clock::now() - g_start_time; - return static_cast( - std::chrono::duration_cast(duration).count()); -} - -auto Utils::get_random() -> f32 { - return static_cast(std::rand()) / static_cast(RAND_MAX); -} - -auto Utils::get_random(const u64 max) -> u64 { - return static_cast(static_cast(max) * get_random()); -} - -auto Utils::get_random(const i64 min, const i64 max) -> i64 { - return min + static_cast(static_cast(max - min) * get_random()); -} - -auto Utils::sleep(const u64 milliseconds) -> void { - std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds)); -} - -auto Utils::binary_to_hex_string(const Span data) -> String { - static constexpr const char LUT[17] = "0123456789ABCDEF"; - Mut res = String(); - res.reserve(data.size() * 2); - - for (u8 b : data) { - res.push_back(LUT[(b >> 4) & 0x0F]); - res.push_back(LUT[b & 0x0F]); - } - return res; -} - -auto Utils::hex_string_to_binary(const StringView hex) -> Result> { - if (hex.size() % 2 != 0) { - return fail("Hex string must have even length"); + auto Utils::get_unix_time() -> u64 + { + const std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); + return std::chrono::duration_cast(now.time_since_epoch()).count(); } - Mut> out = Vec(); - out.reserve(hex.size() / 2); + auto Utils::get_ticks_count() -> u64 + { + const std::chrono::high_resolution_clock::duration duration = + std::chrono::high_resolution_clock::now() - g_start_time; + return std::chrono::duration_cast(duration).count(); + } - for (Mut i = 0; i < hex.size(); i += 2) { - const char high = hex[i]; - const char low = hex[i + 1]; + auto Utils::get_seconds_count() -> f64 + { + const std::chrono::high_resolution_clock::duration duration = + std::chrono::high_resolution_clock::now() - g_start_time; + return static_cast(std::chrono::duration_cast(duration).count()); + } - const i32 h = from_hex_char(high); - const i32 l = from_hex_char(low); + auto Utils::get_random() -> f32 + { + return static_cast(std::rand()) / static_cast(RAND_MAX); + } - if (h == -1 || l == -1) { - return fail("Invalid hex character found"); + auto Utils::get_random(const u64 max) -> u64 + { + return static_cast(static_cast(max) * get_random()); + } + + auto Utils::get_random(const i64 min, const i64 max) -> i64 + { + return min + static_cast(static_cast(max - min) * get_random()); + } + + auto Utils::sleep(const u64 milliseconds) -> void + { + std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds)); + } + + auto Utils::binary_to_hex_string(const Span data) -> String + { + static constexpr const char LUT[17] = "0123456789ABCDEF"; + Mut res = String(); + res.reserve(data.size() * 2); + + for (u8 b : data) + { + res.push_back(LUT[(b >> 4) & 0x0F]); + res.push_back(LUT[b & 0x0F]); + } + return res; + } + + auto Utils::hex_string_to_binary(const StringView hex) -> Result> + { + if (hex.size() % 2 != 0) + { + return fail("Hex string must have even length"); } - out.push_back(static_cast((h << 4) | l)); - } + Mut> out = Vec(); + out.reserve(hex.size() / 2); - return out; -} + for (Mut i = 0; i < hex.size(); i += 2) + { + const char high = hex[i]; + const char low = hex[i + 1]; + + const i32 h = from_hex_char(high); + const i32 l = from_hex_char(low); + + if (h == -1 || l == -1) + { + return fail("Invalid hex character found"); + } + + out.push_back(static_cast((h << 4) | l)); + } + + return out; + } } // namespace IACore \ No newline at end of file diff --git a/Src/IACore/imp/cpp/XML.cpp b/Src/IACore/imp/cpp/XML.cpp index 6a1e1c9..6caf32f 100644 --- a/Src/IACore/imp/cpp/XML.cpp +++ b/Src/IACore/imp/cpp/XML.cpp @@ -16,67 +16,76 @@ #include #include -namespace IACore { +namespace IACore +{ -auto XML::parse_from_string(Ref data) -> Result { - Mut doc; - const pugi::xml_parse_result parse_result = doc.load_string(data.c_str()); - if (!parse_result) { - return fail("Failed to parse XML {}", parse_result.description()); - } - return std::move(doc); -} - -auto XML::parse_from_file(Ref path) -> Result { - Mut doc; - const pugi::xml_parse_result parse_result = - doc.load_file(path.string().c_str()); - if (!parse_result) { - return fail("Failed to parse XML {}", parse_result.description()); - } - return std::move(doc); -} - -auto XML::serialize_to_string(Ref node, const bool escape) -> String { - Mut oss; - node.print(oss); - return escape ? escape_xml_string(oss.str()) : oss.str(); -} - -auto XML::serialize_to_string(Ref doc, const bool escape) -> String { - Mut oss; - doc.save(oss); - return escape ? escape_xml_string(oss.str()) : oss.str(); -} - -auto XML::escape_xml_string(Ref xml) -> String { - Mut buffer; - buffer.reserve(xml.size() + (xml.size() / 10)); - - for (const char c : xml) { - switch (c) { - case '&': - buffer.append("&"); - break; - case '\"': - buffer.append("""); - break; - case '\'': - buffer.append("'"); - break; - case '<': - buffer.append("<"); - break; - case '>': - buffer.append(">"); - break; - default: - buffer.push_back(c); - break; + auto XML::parse_from_string(Ref data) -> Result + { + Mut doc; + const pugi::xml_parse_result parse_result = doc.load_string(data.c_str()); + if (!parse_result) + { + return fail("Failed to parse XML {}", parse_result.description()); } + return std::move(doc); } - return buffer; -} + auto XML::parse_from_file(Ref path) -> Result + { + Mut doc; + const pugi::xml_parse_result parse_result = doc.load_file(path.string().c_str()); + if (!parse_result) + { + return fail("Failed to parse XML {}", parse_result.description()); + } + return std::move(doc); + } + + auto XML::serialize_to_string(Ref node, const bool escape) -> String + { + Mut oss; + node.print(oss); + return escape ? escape_xml_string(oss.str()) : oss.str(); + } + + auto XML::serialize_to_string(Ref doc, const bool escape) -> String + { + Mut oss; + doc.save(oss); + return escape ? escape_xml_string(oss.str()) : oss.str(); + } + + auto XML::escape_xml_string(Ref xml) -> String + { + Mut buffer; + buffer.reserve(xml.size() + (xml.size() / 10)); + + for (const char c : xml) + { + switch (c) + { + case '&': + buffer.append("&"); + break; + case '\"': + buffer.append("""); + break; + case '\'': + buffer.append("'"); + break; + case '<': + buffer.append("<"); + break; + case '>': + buffer.append(">"); + break; + default: + buffer.push_back(c); + break; + } + } + + return buffer; + } } // namespace IACore \ No newline at end of file diff --git a/Src/IACore/inc/IACore/ADT/RingBuffer.hpp b/Src/IACore/inc/IACore/ADT/RingBuffer.hpp index e624d84..f88c8e4 100644 --- a/Src/IACore/inc/IACore/ADT/RingBuffer.hpp +++ b/Src/IACore/inc/IACore/ADT/RingBuffer.hpp @@ -17,244 +17,260 @@ #include -namespace IACore { -class RingBufferView { +namespace IACore +{ + class RingBufferView + { public: - static constexpr const u16 PACKET_ID_SKIP = 0; + static constexpr const u16 PACKET_ID_SKIP = 0; - struct ControlBlock { - struct alignas(64) { - Mut> write_offset{0}; - } producer; + struct ControlBlock + { + struct alignas(64) + { + Mut> write_offset{0}; + } producer; - struct alignas(64) { - Mut> read_offset{0}; - Mut capacity{0}; - } consumer; - }; + struct alignas(64) + { + Mut> read_offset{0}; + Mut capacity{0}; + } consumer; + }; - static_assert(offsetof(ControlBlock, consumer) == 64, - "False sharing detected in ControlBlock"); + static_assert(offsetof(ControlBlock, consumer) == 64, "False sharing detected in ControlBlock"); - struct PacketHeader { - PacketHeader() : id(0), payload_size(0) {} + struct PacketHeader + { + PacketHeader() : id(0), payload_size(0) + { + } - PacketHeader(const u16 id) : id(id), payload_size(0) {} + PacketHeader(const u16 id) : id(id), payload_size(0) + { + } - PacketHeader(const u16 id, const u16 payload_size) - : id(id), payload_size(payload_size) {} + PacketHeader(const u16 id, const u16 payload_size) : id(id), payload_size(payload_size) + { + } - Mut id{}; - Mut payload_size{}; - }; + Mut id{}; + Mut payload_size{}; + }; public: - static auto default_instance() -> RingBufferView; + static auto default_instance() -> RingBufferView; - static auto create(Ref> buffer, const bool is_owner) - -> Result; - static auto create(ControlBlock *control_block, Ref> buffer, - const bool is_owner) -> Result; + static auto create(Ref> buffer, const bool is_owner) -> Result; + static auto create(ControlBlock *control_block, Ref> buffer, const bool is_owner) + -> Result; - // Returns: - // - nullopt if empty - // - bytes_read if success - // - Error if buffer too small - auto pop(MutRef out_header, Ref> out_buffer) - -> Result>; + // Returns: + // - nullopt if empty + // - bytes_read if success + // - Error if buffer too small + auto pop(MutRef out_header, Ref> out_buffer) -> Result>; - auto push(const u16 packet_id, Ref> data) -> Result; + auto push(const u16 packet_id, Ref> data) -> Result; - auto get_control_block() -> ControlBlock *; + auto get_control_block() -> ControlBlock *; - [[nodiscard]] auto is_valid() const -> bool; + [[nodiscard]] auto is_valid() const -> bool; protected: - RingBufferView(Ref> buffer, const bool is_owner); - RingBufferView(ControlBlock *control_block, Ref> buffer, - const bool is_owner); + RingBufferView(Ref> buffer, const bool is_owner); + RingBufferView(ControlBlock *control_block, Ref> buffer, const bool is_owner); private: - Mut m_data_ptr{}; - Mut m_capacity{}; - Mut m_control_block{}; + Mut m_data_ptr{}; + Mut m_capacity{}; + Mut m_control_block{}; private: - auto write_wrapped(const u32 offset, const void *data, const u32 size) - -> void; - auto read_wrapped(const u32 offset, void *out_data, const u32 size) -> void; -}; + auto write_wrapped(const u32 offset, const void *data, const u32 size) -> void; + auto read_wrapped(const u32 offset, void *out_data, const u32 size) -> void; + }; -inline auto RingBufferView::default_instance() -> RingBufferView { - return RingBufferView(nullptr, {}, false); -} - -inline auto RingBufferView::create(Ref> buffer, const bool is_owner) - -> Result { - if (buffer.size() <= sizeof(ControlBlock)) { - return fail("Buffer too small for ControlBlock"); + inline auto RingBufferView::default_instance() -> RingBufferView + { + return RingBufferView(nullptr, {}, false); } - if (!is_owner) { - const ControlBlock *cb = reinterpret_cast(buffer.data()); - const u32 capacity = static_cast(buffer.size()) - sizeof(ControlBlock); - if (cb->consumer.capacity != capacity) { - return fail("Capacity mismatch"); + inline auto RingBufferView::create(Ref> buffer, const bool is_owner) -> Result + { + if (buffer.size() <= sizeof(ControlBlock)) + { + return fail("Buffer too small for ControlBlock"); + } + + if (!is_owner) + { + const ControlBlock *cb = reinterpret_cast(buffer.data()); + const u32 capacity = static_cast(buffer.size()) - sizeof(ControlBlock); + if (cb->consumer.capacity != capacity) + { + return fail("Capacity mismatch"); + } + } + + return RingBufferView(buffer, is_owner); + } + + inline auto RingBufferView::create(ControlBlock *control_block, Ref> buffer, const bool is_owner) + -> Result + { + if (control_block == nullptr) + { + return fail("ControlBlock is null"); + } + if (buffer.empty()) + { + return fail("Buffer is empty"); + } + + return RingBufferView(control_block, buffer, is_owner); + } + + inline RingBufferView::RingBufferView(Ref> buffer, const bool is_owner) + { + m_control_block = reinterpret_cast(buffer.data()); + m_data_ptr = buffer.data() + sizeof(ControlBlock); + + m_capacity = static_cast(buffer.size()) - sizeof(ControlBlock); + + if (is_owner) + { + m_control_block->consumer.capacity = m_capacity; + m_control_block->producer.write_offset.store(0, std::memory_order_release); + m_control_block->consumer.read_offset.store(0, std::memory_order_release); } } - return RingBufferView(buffer, is_owner); -} + inline RingBufferView::RingBufferView(ControlBlock *control_block, Ref> buffer, const bool is_owner) + { + m_control_block = control_block; + m_data_ptr = buffer.data(); + m_capacity = static_cast(buffer.size()); -inline auto RingBufferView::create(ControlBlock *control_block, - Ref> buffer, const bool is_owner) - -> Result { - if (control_block == nullptr) { - return fail("ControlBlock is null"); - } - if (buffer.empty()) { - return fail("Buffer is empty"); + if (is_owner) + { + m_control_block->consumer.capacity = m_capacity; + m_control_block->producer.write_offset.store(0, std::memory_order_release); + m_control_block->consumer.read_offset.store(0, std::memory_order_release); + } } - return RingBufferView(control_block, buffer, is_owner); -} + inline auto RingBufferView::pop(MutRef out_header, Ref> out_buffer) -> Result> + { + const u32 write = m_control_block->producer.write_offset.load(std::memory_order_acquire); + const u32 read = m_control_block->consumer.read_offset.load(std::memory_order_relaxed); + const u32 cap = m_capacity; -inline RingBufferView::RingBufferView(Ref> buffer, - const bool is_owner) { - m_control_block = reinterpret_cast(buffer.data()); - m_data_ptr = buffer.data() + sizeof(ControlBlock); + if (read == write) + { + return std::nullopt; + } - m_capacity = static_cast(buffer.size()) - sizeof(ControlBlock); + read_wrapped(read, &out_header, sizeof(PacketHeader)); - if (is_owner) { - m_control_block->consumer.capacity = m_capacity; - m_control_block->producer.write_offset.store(0, std::memory_order_release); - m_control_block->consumer.read_offset.store(0, std::memory_order_release); - } -} + if (out_header.payload_size > out_buffer.size()) + { + return fail("Buffer too small: needed {}, provided {}", out_header.payload_size, out_buffer.size()); + } -inline RingBufferView::RingBufferView(ControlBlock *control_block, - Ref> buffer, - const bool is_owner) { - m_control_block = control_block; - m_data_ptr = buffer.data(); - m_capacity = static_cast(buffer.size()); + if (out_header.payload_size > 0) + { + const u32 data_read_offset = (read + sizeof(PacketHeader)) % cap; + read_wrapped(data_read_offset, out_buffer.data(), out_header.payload_size); + } - if (is_owner) { - m_control_block->consumer.capacity = m_capacity; - m_control_block->producer.write_offset.store(0, std::memory_order_release); - m_control_block->consumer.read_offset.store(0, std::memory_order_release); - } -} + const u32 new_read_offset = (read + sizeof(PacketHeader) + out_header.payload_size) % cap; + m_control_block->consumer.read_offset.store(new_read_offset, std::memory_order_release); -inline auto RingBufferView::pop(MutRef out_header, - Ref> out_buffer) - -> Result> { - const u32 write = - m_control_block->producer.write_offset.load(std::memory_order_acquire); - const u32 read = - m_control_block->consumer.read_offset.load(std::memory_order_relaxed); - const u32 cap = m_capacity; - - if (read == write) { - return std::nullopt; + return std::make_optional(static_cast(out_header.payload_size)); } - read_wrapped(read, &out_header, sizeof(PacketHeader)); + inline auto RingBufferView::push(const u16 packet_id, Ref> data) -> Result + { + if (data.size() > std::numeric_limits::max()) + { + return fail("Data size exceeds u16 limit"); + } - if (out_header.payload_size > out_buffer.size()) { - return fail("Buffer too small: needed {}, provided {}", - out_header.payload_size, out_buffer.size()); + const u32 total_size = sizeof(PacketHeader) + static_cast(data.size()); + + const u32 read = m_control_block->consumer.read_offset.load(std::memory_order_acquire); + const u32 write = m_control_block->producer.write_offset.load(std::memory_order_relaxed); + const u32 cap = m_capacity; + + const u32 free_space = (read <= write) ? (m_capacity - write) + read : (read - write); + + // Leave 1 byte empty (prevent ambiguities) + if (free_space <= total_size) + { + return fail("RingBuffer full"); + } + + const PacketHeader header{packet_id, static_cast(data.size())}; + write_wrapped(write, &header, sizeof(PacketHeader)); + + const u32 data_write_offset = (write + sizeof(PacketHeader)) % cap; + + if (!data.empty()) + { + write_wrapped(data_write_offset, data.data(), static_cast(data.size())); + } + + const u32 new_write_offset = (data_write_offset + data.size()) % cap; + m_control_block->producer.write_offset.store(new_write_offset, std::memory_order_release); + + return {}; } - if (out_header.payload_size > 0) { - const u32 data_read_offset = (read + sizeof(PacketHeader)) % cap; - read_wrapped(data_read_offset, out_buffer.data(), out_header.payload_size); + inline auto RingBufferView::get_control_block() -> ControlBlock * + { + return m_control_block; } - const u32 new_read_offset = - (read + sizeof(PacketHeader) + out_header.payload_size) % cap; - m_control_block->consumer.read_offset.store(new_read_offset, - std::memory_order_release); + inline auto RingBufferView::write_wrapped(const u32 offset, const void *data, const u32 size) -> void + { + if (offset + size <= m_capacity) + { + std::memcpy(m_data_ptr + offset, data, size); + } + else + { + const u32 first_chunk = m_capacity - offset; + const u32 second_chunk = size - first_chunk; - return std::make_optional(static_cast(out_header.payload_size)); -} + const u8 *src = static_cast(data); -inline auto RingBufferView::push(const u16 packet_id, Ref> data) - -> Result { - if (data.size() > std::numeric_limits::max()) { - return fail("Data size exceeds u16 limit"); + std::memcpy(m_data_ptr + offset, src, first_chunk); + std::memcpy(m_data_ptr, src + first_chunk, second_chunk); + } } - const u32 total_size = sizeof(PacketHeader) + static_cast(data.size()); + inline auto RingBufferView::read_wrapped(const u32 offset, void *out_data, const u32 size) -> void + { + if (offset + size <= m_capacity) + { + std::memcpy(out_data, m_data_ptr + offset, size); + } + else + { + const u32 first_chunk = m_capacity - offset; + const u32 second_chunk = size - first_chunk; - const u32 read = - m_control_block->consumer.read_offset.load(std::memory_order_acquire); - const u32 write = - m_control_block->producer.write_offset.load(std::memory_order_relaxed); - const u32 cap = m_capacity; + u8 *dst = static_cast(out_data); - const u32 free_space = - (read <= write) ? (m_capacity - write) + read : (read - write); - - // Leave 1 byte empty (prevent ambiguities) - if (free_space <= total_size) { - return fail("RingBuffer full"); + std::memcpy(dst, m_data_ptr + offset, first_chunk); + std::memcpy(dst + first_chunk, m_data_ptr, second_chunk); + } } - const PacketHeader header{packet_id, static_cast(data.size())}; - write_wrapped(write, &header, sizeof(PacketHeader)); - - const u32 data_write_offset = (write + sizeof(PacketHeader)) % cap; - - if (!data.empty()) { - write_wrapped(data_write_offset, data.data(), - static_cast(data.size())); + [[nodiscard]] inline auto RingBufferView::is_valid() const -> bool + { + return m_control_block && m_data_ptr && m_capacity; } - const u32 new_write_offset = (data_write_offset + data.size()) % cap; - m_control_block->producer.write_offset.store(new_write_offset, - std::memory_order_release); - - return {}; -} - -inline auto RingBufferView::get_control_block() -> ControlBlock * { - return m_control_block; -} - -inline auto RingBufferView::write_wrapped(const u32 offset, const void *data, - const u32 size) -> void { - if (offset + size <= m_capacity) { - std::memcpy(m_data_ptr + offset, data, size); - } else { - const u32 first_chunk = m_capacity - offset; - const u32 second_chunk = size - first_chunk; - - const u8 *src = static_cast(data); - - std::memcpy(m_data_ptr + offset, src, first_chunk); - std::memcpy(m_data_ptr, src + first_chunk, second_chunk); - } -} - -inline auto RingBufferView::read_wrapped(const u32 offset, void *out_data, - const u32 size) -> void { - if (offset + size <= m_capacity) { - std::memcpy(out_data, m_data_ptr + offset, size); - } else { - const u32 first_chunk = m_capacity - offset; - const u32 second_chunk = size - first_chunk; - - u8 *dst = static_cast(out_data); - - std::memcpy(dst, m_data_ptr + offset, first_chunk); - std::memcpy(dst + first_chunk, m_data_ptr, second_chunk); - } -} - -[[nodiscard]] inline auto RingBufferView::is_valid() const -> bool { - return m_control_block && m_data_ptr && m_capacity; -} - } // namespace IACore \ No newline at end of file diff --git a/Src/IACore/inc/IACore/AsyncOps.hpp b/Src/IACore/inc/IACore/AsyncOps.hpp index 3006c0d..f2408b2 100644 --- a/Src/IACore/inc/IACore/AsyncOps.hpp +++ b/Src/IACore/inc/IACore/AsyncOps.hpp @@ -20,51 +20,57 @@ #include #include -namespace IACore { -class AsyncOps { +namespace IACore +{ + class AsyncOps + { public: - using TaskTag = u64; - using WorkerId = u16; + using TaskTag = u64; + using WorkerId = u16; - static constexpr const WorkerId MAIN_THREAD_WORKER_ID = 0; + static constexpr const WorkerId MAIN_THREAD_WORKER_ID = 0; - enum class Priority : u8 { High, Normal }; + enum class Priority : u8 + { + High, + Normal + }; - struct Schedule { - Mut> counter{0}; - }; + struct Schedule + { + Mut> counter{0}; + }; public: - static auto initialize_scheduler(const u8 worker_count = 0) -> Result; - static auto terminate_scheduler() -> void; + static auto initialize_scheduler(const u8 worker_count = 0) -> Result; + static auto terminate_scheduler() -> void; - static auto schedule_task(Mut> task, - const TaskTag tag, Mut schedule, - const Priority priority = Priority::Normal) -> void; + static auto schedule_task(Mut> task, const TaskTag tag, + Mut schedule, const Priority priority = Priority::Normal) -> void; - static auto cancel_tasks_of_tag(const TaskTag tag) -> void; + static auto cancel_tasks_of_tag(const TaskTag tag) -> void; - static auto wait_for_schedule_completion(Mut schedule) -> void; + static auto wait_for_schedule_completion(Mut schedule) -> void; - static auto run_task(Mut> task) -> void; + static auto run_task(Mut> task) -> void; - IA_NODISCARD static auto get_worker_count() -> WorkerId; + IA_NODISCARD static auto get_worker_count() -> WorkerId; private: - struct ScheduledTask { - Mut tag{}; - Mut schedule_handle{}; - Mut> task{}; + struct ScheduledTask + { + Mut tag{}; + Mut schedule_handle{}; + Mut> task{}; + }; + + static auto schedule_worker_loop(Mut stop_token, const WorkerId worker_id) -> void; + +private: + static Mut s_queue_mutex; + static Mut s_wake_condition; + static Mut> s_schedule_workers; + static Mut> s_high_priority_queue; + static Mut> s_normal_priority_queue; }; - - static auto schedule_worker_loop(Mut stop_token, - const WorkerId worker_id) -> void; - -private: - static Mut s_queue_mutex; - static Mut s_wake_condition; - static Mut> s_schedule_workers; - static Mut> s_high_priority_queue; - static Mut> s_normal_priority_queue; -}; } // namespace IACore \ No newline at end of file diff --git a/Src/IACore/inc/IACore/CLI.hpp b/Src/IACore/inc/IACore/CLI.hpp index 0c158f4..b635e86 100644 --- a/Src/IACore/inc/IACore/CLI.hpp +++ b/Src/IACore/inc/IACore/CLI.hpp @@ -17,47 +17,54 @@ #include -namespace IACore { -class CLIParser { - /* - * PLEASE READ - * - * CLIParser is still very much in it's baby stages. - * Subject to heavy and frequent changes, use with - * caution! - */ +namespace IACore +{ + class CLIParser + { + /* + * PLEASE READ + * + * CLIParser is still very much in it's baby stages. + * Subject to heavy and frequent changes, use with + * caution! + */ public: - CLIParser(const Span args); - ~CLIParser() = default; + CLIParser(const Span args); + ~CLIParser() = default; public: - IA_NODISCARD auto remaining() const -> bool { - return m_current_arg < m_arg_list.end(); - } - - IA_NODISCARD auto peek() const -> StringView { - if (!remaining()) - return ""; - return *m_current_arg; - } - - auto next() -> StringView { - if (!remaining()) - return ""; - return *m_current_arg++; - } - - auto consume(Ref expected) -> bool { - if (peek() == expected) { - next(); - return true; + IA_NODISCARD auto remaining() const -> bool + { + return m_current_arg < m_arg_list.end(); + } + + IA_NODISCARD auto peek() const -> StringView + { + if (!remaining()) + return ""; + return *m_current_arg; + } + + auto next() -> StringView + { + if (!remaining()) + return ""; + return *m_current_arg++; + } + + auto consume(Ref expected) -> bool + { + if (peek() == expected) + { + next(); + return true; + } + return false; } - return false; - } private: - const Span m_arg_list; - Mut::const_iterator> m_current_arg; -}; + const Span m_arg_list; + Mut::const_iterator> m_current_arg; + }; } // namespace IACore \ No newline at end of file diff --git a/Src/IACore/inc/IACore/DataOps.hpp b/Src/IACore/inc/IACore/DataOps.hpp index d025499..dc36cdb 100644 --- a/Src/IACore/inc/IACore/DataOps.hpp +++ b/Src/IACore/inc/IACore/DataOps.hpp @@ -17,29 +17,36 @@ #include -namespace IACore { -class DataOps { +namespace IACore +{ + class DataOps + { public: - enum class CompressionType { None, Gzip, Zlib }; + enum class CompressionType + { + None, + Gzip, + Zlib + }; public: - static auto hash_fnv1a(Ref string) -> u32; - static auto hash_fnv1a(Ref> data) -> u32; + static auto hash_fnv1a(Ref string) -> u32; + static auto hash_fnv1a(Ref> data) -> u32; - static auto hash_xxhash(Ref string, const u32 seed = 0) -> u32; - static auto hash_xxhash(Ref> data, const u32 seed = 0) -> u32; + static auto hash_xxhash(Ref string, const u32 seed = 0) -> u32; + static auto hash_xxhash(Ref> data, const u32 seed = 0) -> u32; - static auto crc32(Ref> data) -> u32; + static auto crc32(Ref> data) -> u32; - static auto detect_compression(const Span data) -> CompressionType; + static auto detect_compression(const Span data) -> CompressionType; - static auto gzip_inflate(Ref> data) -> Result>; - static auto gzip_deflate(Ref> data) -> Result>; + static auto gzip_inflate(Ref> data) -> Result>; + static auto gzip_deflate(Ref> data) -> Result>; - static auto zlib_inflate(Ref> data) -> Result>; - static auto zlib_deflate(Ref> data) -> Result>; + static auto zlib_inflate(Ref> data) -> Result>; + static auto zlib_deflate(Ref> data) -> Result>; - static auto zstd_inflate(Ref> data) -> Result>; - static auto zstd_deflate(Ref> data) -> Result>; -}; + static auto zstd_inflate(Ref> data) -> Result>; + static auto zstd_deflate(Ref> data) -> Result>; + }; } // namespace IACore \ No newline at end of file diff --git a/Src/IACore/inc/IACore/DynamicLib.hpp b/Src/IACore/inc/IACore/DynamicLib.hpp index 9942e23..cc07a18 100644 --- a/Src/IACore/inc/IACore/DynamicLib.hpp +++ b/Src/IACore/inc/IACore/DynamicLib.hpp @@ -18,134 +18,153 @@ #include #if !IA_PLATFORM_WINDOWS -#include +# include #endif -namespace IACore { +namespace IACore +{ -class DynamicLib { + class DynamicLib + { public: - IA_NODISCARD static auto load(Ref search_path, Ref name) - -> Result { - namespace fs = std::filesystem; - Mut full_path = fs::path(search_path) / name; + IA_NODISCARD static auto load(Ref search_path, Ref name) -> Result + { + namespace fs = std::filesystem; + Mut full_path = fs::path(search_path) / name; - if (!full_path.has_extension()) { + if (!full_path.has_extension()) + { #if IA_PLATFORM_WINDOWS - full_path += ".dll"; + full_path += ".dll"; #elif IA_PLATFORM_APPLE - full_path += ".dylib"; + full_path += ".dylib"; #else - full_path += ".so"; + full_path += ".so"; #endif - } + } - Mut lib; + Mut lib; #if IA_PLATFORM_WINDOWS - const HMODULE h = LoadLibraryA(full_path.string().c_str()); - if (!h) { - return fail(get_windows_error()); - } - lib.m_handle = static_cast(h); + const HMODULE h = LoadLibraryA(full_path.string().c_str()); + if (!h) + { + return fail(get_windows_error()); + } + lib.m_handle = static_cast(h); #else - Mut h = dlopen(full_path.c_str(), RTLD_LAZY | RTLD_LOCAL); - if (!h) { - const char *err = dlerror(); - return fail(err ? err : "Unknown dlopen error"); - } - lib.m_handle = h; + Mut h = dlopen(full_path.c_str(), RTLD_LAZY | RTLD_LOCAL); + if (!h) + { + const char *err = dlerror(); + return fail(err ? err : "Unknown dlopen error"); + } + lib.m_handle = h; #endif - return lib; - } + return lib; + } - DynamicLib() = default; + DynamicLib() = default; - DynamicLib(ForwardRef other) noexcept : m_handle(other.m_handle) { - other.m_handle = nullptr; - } - - auto operator=(ForwardRef other) noexcept -> MutRef { - if (this != &other) { - unload(); - m_handle = other.m_handle; + DynamicLib(ForwardRef other) noexcept : m_handle(other.m_handle) + { other.m_handle = nullptr; } - return *this; - } - DynamicLib(Ref) = delete; - auto operator=(Ref) -> MutRef = delete; - - ~DynamicLib() { unload(); } - - IA_NODISCARD auto get_symbol(Ref name) const -> Result { - if (!m_handle) { - return fail("Library not loaded"); + auto operator=(ForwardRef other) noexcept -> MutRef + { + if (this != &other) + { + unload(); + m_handle = other.m_handle; + other.m_handle = nullptr; + } + return *this; } - Mut sym = nullptr; + DynamicLib(Ref) = delete; + auto operator=(Ref) -> MutRef = delete; + + ~DynamicLib() + { + unload(); + } + + IA_NODISCARD auto get_symbol(Ref name) const -> Result + { + if (!m_handle) + { + return fail("Library not loaded"); + } + + Mut sym = nullptr; #if IA_PLATFORM_WINDOWS - sym = static_cast( - GetProcAddress(static_cast(m_handle), name.c_str())); - if (!sym) { - return fail(get_windows_error()); - } + sym = static_cast(GetProcAddress(static_cast(m_handle), name.c_str())); + if (!sym) + { + return fail(get_windows_error()); + } #else - dlerror(); // Clear prev errors - sym = dlsym(m_handle, name.c_str()); - if (const char *err = dlerror()) { - return fail(err); - } + dlerror(); // Clear prev errors + sym = dlsym(m_handle, name.c_str()); + if (const char *err = dlerror()) + { + return fail(err); + } #endif - return sym; - } + return sym; + } - template - IA_NODISCARD auto get_function(Ref name) const -> Result { - Mut sym = nullptr; - sym = AU_TRY(get_symbol(name)); - return reinterpret_cast(sym); - } + template IA_NODISCARD auto get_function(Ref name) const -> Result + { + Mut sym = nullptr; + sym = AU_TRY(get_symbol(name)); + return reinterpret_cast(sym); + } - void unload() { - if (m_handle) { + void unload() + { + if (m_handle) + { #if IA_PLATFORM_WINDOWS - FreeLibrary(static_cast(m_handle)); + FreeLibrary(static_cast(m_handle)); #else - dlclose(m_handle); + dlclose(m_handle); #endif - m_handle = nullptr; + m_handle = nullptr; + } } - } - IA_NODISCARD auto is_loaded() const -> bool { return m_handle != nullptr; } + IA_NODISCARD auto is_loaded() const -> bool + { + return m_handle != nullptr; + } private: - Mut m_handle = nullptr; + Mut m_handle = nullptr; #if IA_PLATFORM_WINDOWS - static auto get_windows_error() -> String { - const DWORD error_id = ::GetLastError(); - if (error_id == 0) { - return String(); + static auto get_windows_error() -> String + { + const DWORD error_id = ::GetLastError(); + if (error_id == 0) + { + return String(); + } + + Mut message_buffer = nullptr; + const usize size = FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, + error_id, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast(&message_buffer), 0, nullptr); + + const String message(message_buffer, size); + LocalFree(message_buffer); + return "Win32 Error: " + message; } - - Mut message_buffer = nullptr; - const usize size = FormatMessageA( - FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - nullptr, error_id, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - reinterpret_cast(&message_buffer), 0, nullptr); - - const String message(message_buffer, size); - LocalFree(message_buffer); - return "Win32 Error: " + message; - } #endif -}; + }; } // namespace IACore \ No newline at end of file diff --git a/Src/IACore/inc/IACore/Environment.hpp b/Src/IACore/inc/IACore/Environment.hpp index c004120..9f6777a 100644 --- a/Src/IACore/inc/IACore/Environment.hpp +++ b/Src/IACore/inc/IACore/Environment.hpp @@ -18,82 +18,96 @@ #include #include -namespace IACore { +namespace IACore +{ -class Environment { + class Environment + { public: - static auto find(Ref name) -> Option { + static auto find(Ref name) -> Option + { #if IA_PLATFORM_WINDOWS - const u32 buffer_size = - static_cast(GetEnvironmentVariableA(name.c_str(), nullptr, 0)); + const u32 buffer_size = static_cast(GetEnvironmentVariableA(name.c_str(), nullptr, 0)); - if (buffer_size == 0) { - return std::nullopt; - } + if (buffer_size == 0) + { + return std::nullopt; + } - Mut result; - result.resize(buffer_size); + Mut result; + result.resize(buffer_size); - const u32 actual_size = static_cast( - GetEnvironmentVariableA(name.c_str(), result.data(), buffer_size)); + const u32 actual_size = static_cast(GetEnvironmentVariableA(name.c_str(), result.data(), buffer_size)); - if (actual_size == 0 || actual_size > buffer_size) { - return std::nullopt; - } + if (actual_size == 0 || actual_size > buffer_size) + { + return std::nullopt; + } - result.resize(actual_size); - return result; + result.resize(actual_size); + return result; #else - const char *val = std::getenv(name.c_str()); - if (val == nullptr) { - return std::nullopt; - } - return String(val); + const char *val = std::getenv(name.c_str()); + if (val == nullptr) + { + return std::nullopt; + } + return String(val); #endif - } - - static auto get(Ref name, Ref default_value = "") -> String { - return find(name).value_or(default_value); - } - - static auto set(Ref name, Ref value) -> Result { - if (name.empty()) { - return fail("Environment variable name cannot be empty"); } + static auto get(Ref name, Ref default_value = "") -> String + { + return find(name).value_or(default_value); + } + + static auto set(Ref name, Ref value) -> Result + { + if (name.empty()) + { + return fail("Environment variable name cannot be empty"); + } + #if IA_PLATFORM_WINDOWS - if (SetEnvironmentVariableA(name.c_str(), value.c_str()) == 0) { - return fail("Failed to set environment variable: {}", name); - } + if (SetEnvironmentVariableA(name.c_str(), value.c_str()) == 0) + { + return fail("Failed to set environment variable: {}", name); + } #else - if (setenv(name.c_str(), value.c_str(), 1) != 0) { - return fail("Failed to set environment variable: {}", name); - } + if (setenv(name.c_str(), value.c_str(), 1) != 0) + { + return fail("Failed to set environment variable: {}", name); + } #endif - return {}; - } - - static auto unset(Ref name) -> Result { - if (name.empty()) { - return fail("Environment variable name cannot be empty"); + return {}; } + static auto unset(Ref name) -> Result + { + if (name.empty()) + { + return fail("Environment variable name cannot be empty"); + } + #if IA_PLATFORM_WINDOWS - if (SetEnvironmentVariableA(name.c_str(), nullptr) == 0) { - return fail("Failed to unset environment variable: {}", name); - } + if (SetEnvironmentVariableA(name.c_str(), nullptr) == 0) + { + return fail("Failed to unset environment variable: {}", name); + } #else - if (unsetenv(name.c_str()) != 0) { - return fail("Failed to unset environment variable: {}", name); - } + if (unsetenv(name.c_str()) != 0) + { + return fail("Failed to unset environment variable: {}", name); + } #endif - return {}; - } + return {}; + } - static auto exists(Ref name) -> bool { - return find(name).has_value(); - } -}; + static auto exists(Ref name) -> bool + { + return find(name).has_value(); + } + }; } // namespace IACore \ No newline at end of file diff --git a/Src/IACore/inc/IACore/FileOps.hpp b/Src/IACore/inc/IACore/FileOps.hpp index bcf0a3b..1a54bcc 100644 --- a/Src/IACore/inc/IACore/FileOps.hpp +++ b/Src/IACore/inc/IACore/FileOps.hpp @@ -22,105 +22,110 @@ #if IA_PLATFORM_WINDOWS using NativeFileHandle = HANDLE; -static constexpr NativeFileHandle INVALID_FILE_HANDLE = INVALID_HANDLE_VALUE; +static const NativeFileHandle INVALID_FILE_HANDLE = INVALID_HANDLE_VALUE; #else using NativeFileHandle = int; -static constexpr NativeFileHandle INVALID_FILE_HANDLE = -1; +static const NativeFileHandle INVALID_FILE_HANDLE = -1; #endif -namespace IACore { +namespace IACore +{ -class FileOps { + class FileOps + { public: - class MemoryMappedRegion; + class MemoryMappedRegion; - enum class FileAccess : u8 { - Read, // Read-only - Write, // Write-only - ReadWrite // Read and Write - }; + enum class FileAccess : u8 + { + Read, // Read-only + Write, // Write-only + ReadWrite // Read and Write + }; - enum class FileMode : u8 { - OpenExisting, // Fails if file doesn't exist - OpenAlways, // Opens if exists, creates if not - CreateNew, // Fails if file exists - CreateAlways, // Overwrites existing - TruncateExisting // Opens existing and clears it - }; + enum class FileMode : u8 + { + OpenExisting, // Fails if file doesn't exist + OpenAlways, // Opens if exists, creates if not + CreateNew, // Fails if file exists + CreateAlways, // Overwrites existing + TruncateExisting // Opens existing and clears it + }; - static auto native_open_file(Ref path, const FileAccess access, - const FileMode mode, - const u32 permissions = 0644) - -> Result; + static auto native_open_file(Ref path, const FileAccess access, const FileMode mode, + const u32 permissions = 0644) -> Result; - static auto native_close_file(const NativeFileHandle handle) -> void; + static auto native_close_file(const NativeFileHandle handle) -> void; public: - static auto normalize_executable_path(Ref path) -> Path; + static auto normalize_executable_path(Ref path) -> Path; public: - static auto unmap_file(const u8 *mapped_ptr) -> void; + static auto unmap_file(const u8 *mapped_ptr) -> void; - static auto map_file(Ref path, MutRef size) - -> Result; + static auto map_file(Ref path, MutRef size) -> Result; - // @param `is_owner` true to allocate/truncate. false to just open. - static auto map_shared_memory(Ref name, const usize size, - const bool is_owner) -> Result; + // @param `is_owner` true to allocate/truncate. false to just open. + static auto map_shared_memory(Ref name, const usize size, const bool is_owner) -> Result; - static auto unlink_shared_memory(Ref name) -> void; + static auto unlink_shared_memory(Ref name) -> void; - static auto stream_from_file(Ref path) -> Result; + static auto stream_from_file(Ref path) -> Result; - static auto stream_to_file(Ref path, const bool overwrite = false) - -> Result; + static auto stream_to_file(Ref path, const bool overwrite = false) -> Result; - static auto read_text_file(Ref path) -> Result; + static auto read_text_file(Ref path) -> Result; - static auto read_binary_file(Ref path) -> Result>; + static auto read_binary_file(Ref path) -> Result>; - static auto write_text_file(Ref path, Ref contents, - const bool overwrite = false) -> Result; + static auto write_text_file(Ref path, Ref contents, const bool overwrite = false) -> Result; - static auto write_binary_file(Ref path, const Span contents, - const bool overwrite = false) -> Result; + static auto write_binary_file(Ref path, const Span contents, const bool overwrite = false) + -> Result; private: - static Mut>> - s_mapped_files; -}; + static Mut>> s_mapped_files; + }; -class FileOps::MemoryMappedRegion { + class FileOps::MemoryMappedRegion + { public: - MemoryMappedRegion() = default; - ~MemoryMappedRegion(); + MemoryMappedRegion() = default; + ~MemoryMappedRegion(); - MemoryMappedRegion(Ref) = delete; - auto operator=(Ref) -> MemoryMappedRegion & = delete; + MemoryMappedRegion(Ref) = delete; + auto operator=(Ref) -> MemoryMappedRegion & = delete; - MemoryMappedRegion(ForwardRef other) noexcept; - auto operator=(ForwardRef other) noexcept - -> MemoryMappedRegion &; + MemoryMappedRegion(ForwardRef other) noexcept; + auto operator=(ForwardRef other) noexcept -> MemoryMappedRegion &; - auto map(const NativeFileHandle handle, const u64 offset, const usize size) - -> Result; + auto map(const NativeFileHandle handle, const u64 offset, const usize size) -> Result; - auto unmap() -> void; - auto flush() -> void; + auto unmap() -> void; + auto flush() -> void; - [[nodiscard]] auto get_ptr() const -> u8 * { return m_ptr; } + [[nodiscard]] auto get_ptr() const -> u8 * + { + return m_ptr; + } - [[nodiscard]] auto get_size() const -> usize { return m_size; } + [[nodiscard]] auto get_size() const -> usize + { + return m_size; + } - [[nodiscard]] auto is_valid() const -> bool { return m_ptr != nullptr; } + [[nodiscard]] auto is_valid() const -> bool + { + return m_ptr != nullptr; + } private: - Mut m_ptr = nullptr; - Mut m_size = 0; + Mut m_ptr = nullptr; + Mut m_size = 0; #if IA_PLATFORM_WINDOWS - Mut m_map_handle = NULL; + Mut m_map_handle = NULL; #endif -}; + }; } // namespace IACore \ No newline at end of file diff --git a/Src/IACore/inc/IACore/Http/Client.hpp b/Src/IACore/inc/IACore/Http/Client.hpp index a5c4d54..74fd998 100644 --- a/Src/IACore/inc/IACore/Http/Client.hpp +++ b/Src/IACore/inc/IACore/Http/Client.hpp @@ -18,78 +18,77 @@ #include #include -namespace IACore { -class HttpClient : public HttpCommon { +namespace IACore +{ + class HttpClient : public HttpCommon + { public: - static auto create(Ref host) -> Result>; + static auto create(Ref host) -> Result>; - ~HttpClient(); + ~HttpClient(); - HttpClient(ForwardRef) = default; - HttpClient(Ref) = delete; - auto operator=(ForwardRef) -> MutRef = default; - auto operator=(Ref) -> MutRef = delete; + HttpClient(ForwardRef) = default; + HttpClient(Ref) = delete; + auto operator=(ForwardRef) -> MutRef = default; + auto operator=(Ref) -> MutRef = delete; public: - auto raw_get(Ref path, Span headers, - const char *default_content_type = - "application/x-www-form-urlencoded") -> Result; + auto raw_get(Ref path, Span headers, + const char *default_content_type = "application/x-www-form-urlencoded") -> Result; - auto raw_post(Ref path, Span headers, Ref body, - const char *default_content_type = - "application/x-www-form-urlencoded") -> Result; + auto raw_post(Ref path, Span headers, Ref body, + const char *default_content_type = "application/x-www-form-urlencoded") -> Result; - template - auto json_get(Ref path, Span headers) - -> Result; + template auto json_get(Ref path, Span headers) -> Result; - template - auto json_post(Ref path, Span headers, - Ref body) -> Result; + template + auto json_post(Ref path, Span headers, Ref body) -> Result; - // Certificate verification is enabled by default - auto enable_certificate_verification() -> void; - auto disable_certificate_verification() -> void; + // Certificate verification is enabled by default + auto enable_certificate_verification() -> void; + auto disable_certificate_verification() -> void; public: - auto last_response_code() -> EResponseCode { return m_last_response_code; } + auto last_response_code() -> EResponseCode + { + return m_last_response_code; + } private: - Mut m_client; - Mut m_last_response_code; + Mut m_client; + Mut m_last_response_code; private: - auto preprocess_response(Ref response) -> String; + auto preprocess_response(Ref response) -> String; protected: - explicit HttpClient(ForwardRef client); -}; + explicit HttpClient(ForwardRef client); + }; -template -auto HttpClient::json_get(Ref path, Span headers) - -> Result { - const String raw_response = - AU_TRY(raw_get(path, headers, "application/json")); + template + auto HttpClient::json_get(Ref path, Span headers) -> Result + { + const String raw_response = AU_TRY(raw_get(path, headers, "application/json")); - if (last_response_code() != EResponseCode::OK) { - return fail("Server responded with code {}", - static_cast(last_response_code())); + if (last_response_code() != EResponseCode::OK) + { + return fail("Server responded with code {}", static_cast(last_response_code())); + } + return Json::parse_to_struct(raw_response); } - return Json::parse_to_struct(raw_response); -} -template -auto HttpClient::json_post(Ref path, Span headers, - Ref body) -> Result { - const String encoded_body = AU_TRY(Json::encode_struct(body)); + template + auto HttpClient::json_post(Ref path, Span headers, Ref body) + -> Result + { + const String encoded_body = AU_TRY(Json::encode_struct(body)); - const String raw_response = - AU_TRY(raw_post(path, headers, encoded_body, "application/json")); + const String raw_response = AU_TRY(raw_post(path, headers, encoded_body, "application/json")); - if (last_response_code() != EResponseCode::OK) { - return fail("Server responded with code {}", - static_cast(last_response_code())); + if (last_response_code() != EResponseCode::OK) + { + return fail("Server responded with code {}", static_cast(last_response_code())); + } + return Json::parse_to_struct(raw_response); } - return Json::parse_to_struct(raw_response); -} } // namespace IACore \ No newline at end of file diff --git a/Src/IACore/inc/IACore/Http/Common.hpp b/Src/IACore/inc/IACore/Http/Common.hpp index 12d12c9..3133a26 100644 --- a/Src/IACore/inc/IACore/Http/Common.hpp +++ b/Src/IACore/inc/IACore/Http/Common.hpp @@ -19,137 +19,139 @@ #include -namespace IACore { -class HttpCommon { +namespace IACore +{ + class HttpCommon + { public: - enum class EHeaderType { - ACCEPT, - ACCEPT_CHARSET, - ACCEPT_ENCODING, - ACCEPT_LANGUAGE, - AUTHORIZATION, - CACHE_CONTROL, - CONNECTION, - CONTENT_LENGTH, - CONTENT_TYPE, - COOKIE, - DATE, - EXPECT, - HOST, - IF_MATCH, - IF_MODIFIED_SINCE, - IF_NONE_MATCH, - ORIGIN, - PRAGMA, - PROXY_AUTHORIZATION, - RANGE, - REFERER, - TE, - UPGRADE, - USER_AGENT, - VIA, - WARNING - }; + enum class EHeaderType + { + ACCEPT, + ACCEPT_CHARSET, + ACCEPT_ENCODING, + ACCEPT_LANGUAGE, + AUTHORIZATION, + CACHE_CONTROL, + CONNECTION, + CONTENT_LENGTH, + CONTENT_TYPE, + COOKIE, + DATE, + EXPECT, + HOST, + IF_MATCH, + IF_MODIFIED_SINCE, + IF_NONE_MATCH, + ORIGIN, + PRAGMA, + PROXY_AUTHORIZATION, + RANGE, + REFERER, + TE, + UPGRADE, + USER_AGENT, + VIA, + WARNING + }; - enum class EResponseCode : i32 { - // 1xx Informational - CONTINUE = 100, - SWITCHING_PROTOCOLS = 101, - PROCESSING = 102, - EARLY_HINTS = 103, + enum class EResponseCode : i32 + { + // 1xx Informational + CONTINUE = 100, + SWITCHING_PROTOCOLS = 101, + PROCESSING = 102, + EARLY_HINTS = 103, - // 2xx Success - OK = 200, - CREATED = 201, - ACCEPTED = 202, - NON_AUTHORITATIVE_INFORMATION = 203, - NO_CONTENT = 204, - RESET_CONTENT = 205, - PARTIAL_CONTENT = 206, - MULTI_STATUS = 207, - ALREADY_REPORTED = 208, - IM_USED = 226, + // 2xx Success + OK = 200, + CREATED = 201, + ACCEPTED = 202, + NON_AUTHORITATIVE_INFORMATION = 203, + NO_CONTENT = 204, + RESET_CONTENT = 205, + PARTIAL_CONTENT = 206, + MULTI_STATUS = 207, + ALREADY_REPORTED = 208, + IM_USED = 226, - // 3xx Redirection - MULTIPLE_CHOICES = 300, - MOVED_PERMANENTLY = 301, - FOUND = 302, - SEE_OTHER = 303, - NOT_MODIFIED = 304, - USE_PROXY = 305, - TEMPORARY_REDIRECT = 307, - PERMANENT_REDIRECT = 308, + // 3xx Redirection + MULTIPLE_CHOICES = 300, + MOVED_PERMANENTLY = 301, + FOUND = 302, + SEE_OTHER = 303, + NOT_MODIFIED = 304, + USE_PROXY = 305, + TEMPORARY_REDIRECT = 307, + PERMANENT_REDIRECT = 308, - // 4xx Client Error - BAD_REQUEST = 400, - UNAUTHORIZED = 401, - PAYMENT_REQUIRED = 402, - FORBIDDEN = 403, - NOT_FOUND = 404, - METHOD_NOT_ALLOWED = 405, - NOT_ACCEPTABLE = 406, - PROXY_AUTHENTICATION_REQUIRED = 407, - REQUEST_TIMEOUT = 408, - CONFLICT = 409, - GONE = 410, - LENGTH_REQUIRED = 411, - PRECONDITION_FAILED = 412, - PAYLOAD_TOO_LARGE = 413, - URI_TOO_LONG = 414, - UNSUPPORTED_MEDIA_TYPE = 415, - RANGE_NOT_SATISFIABLE = 416, - EXPECTATION_FAILED = 417, - IM_A_TEAPOT = 418, - MISDIRECTED_REQUEST = 421, - UNPROCESSABLE_ENTITY = 422, - LOCKED = 423, - FAILED_DEPENDENCY = 424, - TOO_EARLY = 425, - UPGRADE_REQUIRED = 426, - PRECONDITION_REQUIRED = 428, - TOO_MANY_REQUESTS = 429, - REQUEST_HEADER_FIELDS_TOO_LARGE = 431, - UNAVAILABLE_FOR_LEGAL_REASONS = 451, + // 4xx Client Error + BAD_REQUEST = 400, + UNAUTHORIZED = 401, + PAYMENT_REQUIRED = 402, + FORBIDDEN = 403, + NOT_FOUND = 404, + METHOD_NOT_ALLOWED = 405, + NOT_ACCEPTABLE = 406, + PROXY_AUTHENTICATION_REQUIRED = 407, + REQUEST_TIMEOUT = 408, + CONFLICT = 409, + GONE = 410, + LENGTH_REQUIRED = 411, + PRECONDITION_FAILED = 412, + PAYLOAD_TOO_LARGE = 413, + URI_TOO_LONG = 414, + UNSUPPORTED_MEDIA_TYPE = 415, + RANGE_NOT_SATISFIABLE = 416, + EXPECTATION_FAILED = 417, + IM_A_TEAPOT = 418, + MISDIRECTED_REQUEST = 421, + UNPROCESSABLE_ENTITY = 422, + LOCKED = 423, + FAILED_DEPENDENCY = 424, + TOO_EARLY = 425, + UPGRADE_REQUIRED = 426, + PRECONDITION_REQUIRED = 428, + TOO_MANY_REQUESTS = 429, + REQUEST_HEADER_FIELDS_TOO_LARGE = 431, + UNAVAILABLE_FOR_LEGAL_REASONS = 451, - // 5xx Server Error - INTERNAL_SERVER_ERROR = 500, - NOT_IMPLEMENTED = 501, - BAD_GATEWAY = 502, - SERVICE_UNAVAILABLE = 503, - GATEWAY_TIMEOUT = 504, - HTTP_VERSION_NOT_SUPPORTED = 505, - VARIANT_ALSO_NEGOTIATES = 506, - INSUFFICIENT_STORAGE = 507, - LOOP_DETECTED = 508, - NOT_EXTENDED = 510, - NETWORK_AUTHENTICATION_REQUIRED = 511 - }; + // 5xx Server Error + INTERNAL_SERVER_ERROR = 500, + NOT_IMPLEMENTED = 501, + BAD_GATEWAY = 502, + SERVICE_UNAVAILABLE = 503, + GATEWAY_TIMEOUT = 504, + HTTP_VERSION_NOT_SUPPORTED = 505, + VARIANT_ALSO_NEGOTIATES = 506, + INSUFFICIENT_STORAGE = 507, + LOOP_DETECTED = 508, + NOT_EXTENDED = 510, + NETWORK_AUTHENTICATION_REQUIRED = 511 + }; - using Header = Pair; + using Header = Pair; - static auto url_encode(Ref value) -> String; - static auto url_decode(Ref value) -> String; + static auto url_encode(Ref value) -> String; + static auto url_decode(Ref value) -> String; - static auto header_type_to_string(const EHeaderType type) -> String; + static auto header_type_to_string(const EHeaderType type) -> String; - static inline auto create_header(const EHeaderType key, Ref value) - -> Header; - static inline auto create_header(Ref key, Ref value) - -> Header; + static inline auto create_header(const EHeaderType key, Ref value) -> Header; + static inline auto create_header(Ref key, Ref value) -> Header; - static auto is_success_response_code(const EResponseCode code) -> bool; + static auto is_success_response_code(const EResponseCode code) -> bool; protected: - HttpCommon() = default; -}; + HttpCommon() = default; + }; -auto HttpCommon::create_header(const EHeaderType key, Ref value) - -> HttpCommon::Header { - return Header{header_type_to_string(key), value}; -} + auto HttpCommon::create_header(const EHeaderType key, Ref value) -> HttpCommon::Header + { + return Header{header_type_to_string(key), value}; + } -auto HttpCommon::create_header(Ref key, Ref value) - -> HttpCommon::Header { - return Header{key, value}; -} + auto HttpCommon::create_header(Ref key, Ref value) -> HttpCommon::Header + { + return Header{key, value}; + } } // namespace IACore \ No newline at end of file diff --git a/Src/IACore/inc/IACore/Http/Server.hpp b/Src/IACore/inc/IACore/Http/Server.hpp index 024de1b..927a4df 100644 --- a/Src/IACore/inc/IACore/Http/Server.hpp +++ b/Src/IACore/inc/IACore/Http/Server.hpp @@ -19,133 +19,134 @@ #include #include -namespace IACore { -class HttpServer : public HttpCommon { +namespace IACore +{ + class HttpServer : public HttpCommon + { public: - struct Request { - Mut path; - Mut method; - Mut body; - Mut> headers; - Mut> params; // Query params - Mut> path_params; // Path params (like /object/:id) + struct Request + { + Mut path; + Mut method; + Mut body; + Mut> headers; + Mut> params; // Query params + Mut> path_params; // Path params (like /object/:id) - [[nodiscard]] auto get_header(Ref key) const -> String; - [[nodiscard]] auto get_param(Ref key) const -> String; - [[nodiscard]] auto get_path_param(Ref key) const -> String; + [[nodiscard]] auto get_header(Ref key) const -> String; + [[nodiscard]] auto get_param(Ref key) const -> String; + [[nodiscard]] auto get_path_param(Ref key) const -> String; - [[nodiscard]] auto has_header(Ref key) const -> bool; - [[nodiscard]] auto has_param(Ref key) const -> bool; - [[nodiscard]] auto has_path_param(Ref key) const -> bool; - }; + [[nodiscard]] auto has_header(Ref key) const -> bool; + [[nodiscard]] auto has_param(Ref key) const -> bool; + [[nodiscard]] auto has_path_param(Ref key) const -> bool; + }; - struct Response { - Mut code = EResponseCode::OK; - Mut body; - Mut> headers; - Mut content_type = "text/plain"; + struct Response + { + Mut code = EResponseCode::OK; + Mut body; + Mut> headers; + Mut content_type = "text/plain"; - void set_content(Ref content, Ref type); - void set_status(const EResponseCode status_code); - void add_header(Ref key, Ref value); - }; + void set_content(Ref content, Ref type); + void set_status(const EResponseCode status_code); + void add_header(Ref key, Ref value); + }; - using Handler = std::function, MutRef)>; + using Handler = std::function, MutRef)>; public: - static auto create() -> Result>; + static auto create() -> Result>; - ~HttpServer(); + ~HttpServer(); - HttpServer(HttpServer &&) = delete; - HttpServer(const HttpServer &) = delete; - auto operator=(HttpServer &&) -> HttpServer & = delete; - auto operator=(const HttpServer &) -> HttpServer & = delete; + HttpServer(HttpServer &&) = delete; + HttpServer(const HttpServer &) = delete; + auto operator=(HttpServer &&) -> HttpServer & = delete; + auto operator=(const HttpServer &) -> HttpServer & = delete; - auto listen(Ref host, const u32 port) -> Result; - void stop(); - auto is_running() const -> bool; + auto listen(Ref host, const u32 port) -> Result; + void stop(); + auto is_running() const -> bool; - void get(Ref pattern, const Handler handler); - void post(Ref pattern, const Handler handler); - void put(Ref pattern, const Handler handler); - void del(Ref pattern, const Handler handler); - void options(Ref pattern, const Handler handler); + void get(Ref pattern, const Handler handler); + void post(Ref pattern, const Handler handler); + void put(Ref pattern, const Handler handler); + void del(Ref pattern, const Handler handler); + void options(Ref pattern, const Handler handler); - template - void - json_get(Ref pattern, - const std::function)>> handler); + template + void json_get(Ref pattern, const std::function)>> handler); - template - void json_post( - Ref pattern, - const std::function)>> handler); + template + void json_post(Ref pattern, const std::function)>> handler); protected: - HttpServer(); + HttpServer(); private: - Mut m_server; + Mut m_server; - void register_handler(Ref method, Ref pattern, - const Handler handler); -}; + void register_handler(Ref method, Ref pattern, const Handler handler); + }; -template -void HttpServer::json_get( - Ref pattern, - const std::function)>> handler) { - get(pattern, [handler](Ref req, MutRef res) { - const Result result = handler(req); - if (!result) { - res.set_status(EResponseCode::INTERNAL_SERVER_ERROR); - res.set_content(result.error(), "text/plain"); - return; - } + template + void HttpServer::json_get(Ref pattern, const std::function)>> handler) + { + get(pattern, [handler](Ref req, MutRef res) { + const Result result = handler(req); + if (!result) + { + res.set_status(EResponseCode::INTERNAL_SERVER_ERROR); + res.set_content(result.error(), "text/plain"); + return; + } - const Result json_res = Json::encode_struct(*result); - if (!json_res) { - res.set_status(EResponseCode::INTERNAL_SERVER_ERROR); - res.set_content("Failed to encode JSON response", "text/plain"); - return; - } + const Result json_res = Json::encode_struct(*result); + if (!json_res) + { + res.set_status(EResponseCode::INTERNAL_SERVER_ERROR); + res.set_content("Failed to encode JSON response", "text/plain"); + return; + } - res.set_status(EResponseCode::OK); - res.set_content(*json_res, "application/json"); - }); -} + res.set_status(EResponseCode::OK); + res.set_content(*json_res, "application/json"); + }); + } -template -void HttpServer::json_post( - Ref pattern, - const std::function)>> handler) { - post(pattern, [handler](Ref req, MutRef res) { - const Result payload = - Json::parse_to_struct(req.body); - if (!payload) { - res.set_status(EResponseCode::BAD_REQUEST); - res.set_content("Invalid JSON Payload", "text/plain"); - return; - } + template + void HttpServer::json_post(Ref pattern, const std::function)>> handler) + { + post(pattern, [handler](Ref req, MutRef res) { + const Result payload = Json::parse_to_struct(req.body); + if (!payload) + { + res.set_status(EResponseCode::BAD_REQUEST); + res.set_content("Invalid JSON Payload", "text/plain"); + return; + } - const Result result = handler(*payload); - if (!result) { - res.set_status(EResponseCode::INTERNAL_SERVER_ERROR); - res.set_content(result.error(), "text/plain"); - return; - } + const Result result = handler(*payload); + if (!result) + { + res.set_status(EResponseCode::INTERNAL_SERVER_ERROR); + res.set_content(result.error(), "text/plain"); + return; + } - const Result json_res = Json::encode_struct(*result); - if (!json_res) { - res.set_status(EResponseCode::INTERNAL_SERVER_ERROR); - res.set_content("Failed to encode JSON response", "text/plain"); - return; - } + const Result json_res = Json::encode_struct(*result); + if (!json_res) + { + res.set_status(EResponseCode::INTERNAL_SERVER_ERROR); + res.set_content("Failed to encode JSON response", "text/plain"); + return; + } - res.set_status(EResponseCode::OK); - res.set_content(*json_res, "application/json"); - }); -} + res.set_status(EResponseCode::OK); + res.set_content(*json_res, "application/json"); + }); + } } // namespace IACore \ No newline at end of file diff --git a/Src/IACore/inc/IACore/IACore.hpp b/Src/IACore/inc/IACore/IACore.hpp index 4bcf3d2..7bd506e 100644 --- a/Src/IACore/inc/IACore/IACore.hpp +++ b/Src/IACore/inc/IACore/IACore.hpp @@ -18,49 +18,54 @@ #include #include -#define IACORE_MAIN() \ - auto _app_entry(IACore::Ref> args) \ - -> IACore::Result; \ - auto main(int argc, Mut argv[]) -> int { \ - IACore::Mut exit_code = 0; \ - IACore::initialize(); \ - IACore::Mut> args; \ - args.reserve(static_cast(argc)); \ - for (IACore::Mut i = 0; i < argc; ++i) { \ - args.push_back(argv[i]); \ - } \ - IACore::Result result = _app_entry(args); \ - if (!result) { \ - IACore::Logger::error("Application exited with an error: '{}'.", \ - result.error()); \ - exit_code = -20; \ - } else { \ - exit_code = *result; \ - if (exit_code == 0) { \ - IACore::Logger::info("Application exited successfully."); \ - } else { \ - IACore::Logger::error("Application exited with error code: {}.", \ - exit_code); \ - } \ - } \ - IACore::terminate(); \ - return exit_code; \ - } \ - auto _app_entry(IACore::Ref> args) \ - -> IACore::Result +#define IACORE_MAIN() \ + auto _app_entry(IACore::Ref> args) -> IACore::Result; \ + auto main(int argc, Mut argv[]) -> int \ + { \ + IACore::Mut exit_code = 0; \ + IACore::initialize(); \ + IACore::Mut> args; \ + args.reserve(static_cast(argc)); \ + for (IACore::Mut i = 0; i < argc; ++i) \ + { \ + args.push_back(argv[i]); \ + } \ + IACore::Result result = _app_entry(args); \ + if (!result) \ + { \ + IACore::Logger::error("Application exited with an error: '{}'.", result.error()); \ + exit_code = -20; \ + } \ + else \ + { \ + exit_code = *result; \ + if (exit_code == 0) \ + { \ + IACore::Logger::info("Application exited successfully."); \ + } \ + else \ + { \ + IACore::Logger::error("Application exited with error code: {}.", exit_code); \ + } \ + } \ + IACore::terminate(); \ + return exit_code; \ + } \ + auto _app_entry(IACore::Ref> args) -> IACore::Result -namespace IACore { -// Must be called from main thread -// Safe to call multiple times but, given every initialize call is paired with a -// corresponding terminate call -auto initialize() -> void; +namespace IACore +{ + // Must be called from main thread + // Safe to call multiple times but, given every initialize call is paired with a + // corresponding terminate call + auto initialize() -> void; -// Must be called from same thread as initialize -// Safe to call multiple times but, given every initialize call is paired with a -// corresponding terminate call -auto terminate() -> void; + // Must be called from same thread as initialize + // Safe to call multiple times but, given every initialize call is paired with a + // corresponding terminate call + auto terminate() -> void; -auto is_initialized() -> bool; + auto is_initialized() -> bool; -auto is_main_thread() -> bool; + auto is_main_thread() -> bool; } // namespace IACore \ No newline at end of file diff --git a/Src/IACore/inc/IACore/IATest.hpp b/Src/IACore/inc/IACore/IATest.hpp index 2769ff4..d78542c 100644 --- a/Src/IACore/inc/IACore/IATest.hpp +++ b/Src/IACore/inc/IACore/IATest.hpp @@ -21,269 +21,292 @@ // Macros // ----------------------------------------------------------------------------- -#define __iat_micro_test(call) \ - if (!(call)) \ +#define __iat_micro_test(call) \ + if (!(call)) \ return false #define IAT_CHECK(v) __iat_micro_test(_test((v), #v)) #define IAT_CHECK_NOT(v) __iat_micro_test(_test_not((v), "NOT " #v)) -#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)) +#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)) -#define IAT_CHECK_APPROX(lhs, rhs) \ - __iat_micro_test(_test_approx((lhs), (rhs), #lhs " ~= " #rhs)) +#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) #define IAT_NAMED_UNIT(n, func) _test_unit([this]() { return this->func(); }, n) #define IAT_BLOCK(name) class name : public IACore::Test::Block -#define IAT_BEGIN_BLOCK(_group, _name) \ - class _group##_##_name : public IACore::Test::Block { \ - public: \ - [[nodiscard]] auto get_name() const -> const char * override { \ - return #_group "::" #_name; \ - } \ - \ - private: +#define IAT_BEGIN_BLOCK(_group, _name) \ + class _group##_##_name : public IACore::Test::Block \ + { \ +public: \ + [[nodiscard]] auto get_name() const -> const char * override \ + { \ + return #_group "::" #_name; \ + } \ + \ +private: -#define IAT_END_BLOCK() \ - } \ +#define IAT_END_BLOCK() \ + } \ ; -#define IAT_BEGIN_TEST_LIST() \ -public: \ - auto declare_tests() -> void override { +#define IAT_BEGIN_TEST_LIST() \ + public: \ + auto declare_tests() -> void override \ + { #define IAT_ADD_TEST(name) IAT_UNIT(name) -#define IAT_END_TEST_LIST() \ - } \ - \ -private: +#define IAT_END_TEST_LIST() \ + } \ + \ + private: -namespace IACore::Test { -// ------------------------------------------------------------------------- -// String Conversion Helpers -// ------------------------------------------------------------------------- -template auto to_string(Ref value) -> String { - if constexpr (std::is_arithmetic_v) { - return std::to_string(value); - } else if constexpr (std::is_same_v || - std::is_same_v || - std::is_same_v) { - return String("\"") + String(value) + "\""; - } else { - return "{Object}"; +namespace IACore::Test +{ + // ------------------------------------------------------------------------- + // String Conversion Helpers + // ------------------------------------------------------------------------- + template auto to_string(Ref value) -> String + { + if constexpr (std::is_arithmetic_v) + { + return std::to_string(value); + } + else if constexpr (std::is_same_v || std::is_same_v || std::is_same_v) + { + return String("\"") + String(value) + "\""; + } + else + { + return "{Object}"; + } } -} -template auto to_string(T *value) -> String { - if (value == nullptr) { - return "nullptr"; + template auto to_string(T *value) -> String + { + if (value == nullptr) + { + return "nullptr"; + } + return std::format("ptr({})", static_cast(value)); } - return std::format("ptr({})", static_cast(value)); -} -// ------------------------------------------------------------------------- -// Types -// ------------------------------------------------------------------------- -using TestFunctor = std::function; + // ------------------------------------------------------------------------- + // Types + // ------------------------------------------------------------------------- + using TestFunctor = std::function; -struct TestUnit { - Mut name; - Mut functor; -}; + struct TestUnit + { + Mut name; + Mut functor; + }; -class Block { + class Block + { public: - virtual ~Block() = default; - [[nodiscard]] virtual auto get_name() const -> const char * = 0; - virtual auto declare_tests() -> void = 0; + virtual ~Block() = default; + [[nodiscard]] virtual auto get_name() const -> const char * = 0; + virtual auto declare_tests() -> void = 0; - auto units() -> MutRef> { return m_units; } + auto units() -> MutRef> + { + return m_units; + } protected: - template - auto _test_eq(Ref lhs, Ref rhs, const char *description) -> bool { - if (lhs != rhs) { - print_fail(description, to_string(lhs), to_string(rhs)); - return false; + template auto _test_eq(Ref lhs, Ref rhs, const char *description) -> bool + { + if (lhs != rhs) + { + print_fail(description, to_string(lhs), to_string(rhs)); + return false; + } + return true; } - return true; - } - template - auto _test_neq(Ref lhs, Ref rhs, const char *description) -> bool { - if (lhs == rhs) { - print_fail(description, to_string(lhs), "NOT " + to_string(rhs)); - return false; + template auto _test_neq(Ref lhs, Ref rhs, const char *description) -> bool + { + if (lhs == rhs) + { + print_fail(description, to_string(lhs), "NOT " + to_string(rhs)); + return false; + } + return true; } - return true; - } - template - auto _test_approx(const T lhs, const T rhs, const char *description) -> bool { - static_assert(std::is_floating_point_v, - "Approx only works for floats/doubles"); - const T diff = std::abs(lhs - rhs); - if (diff > static_cast(0.0001)) { - print_fail(description, to_string(lhs), to_string(rhs)); - return false; + template auto _test_approx(const T lhs, const T rhs, const char *description) -> bool + { + static_assert(std::is_floating_point_v, "Approx only works for floats/doubles"); + const T diff = std::abs(lhs - rhs); + if (diff > static_cast(0.0001)) + { + print_fail(description, to_string(lhs), to_string(rhs)); + return false; + } + return true; } - return true; - } - auto _test(const bool value, const char *description) -> bool { - if (!value) { - std::cout << console::BLUE << " " << description << "... " - << console::RED << "FAILED" << console::RESET << "\n"; - return false; + auto _test(const bool value, const char *description) -> bool + { + if (!value) + { + std::cout << console::BLUE << " " << description << "... " << console::RED << "FAILED" << console::RESET + << "\n"; + return false; + } + return true; } - return true; - } - auto _test_not(const bool value, const char *description) -> bool { - if (value) { - std::cout << console::BLUE << " " << description << "... " - << console::RED << "FAILED" << console::RESET << "\n"; - return false; + auto _test_not(const bool value, const char *description) -> bool + { + if (value) + { + std::cout << console::BLUE << " " << description << "... " << console::RED << "FAILED" << console::RESET + << "\n"; + return false; + } + return true; } - return true; - } - auto _test_unit(Mut functor, const char *name) -> void { - m_units.push_back({name, std::move(functor)}); - } + auto _test_unit(Mut functor, const char *name) -> void + { + m_units.push_back({name, std::move(functor)}); + } private: - auto print_fail(const char *desc, Ref v1, Ref v2) -> void { - std::cout << console::BLUE << " " << desc << "... " << console::RED - << "FAILED" << console::RESET << "\n"; - std::cout << console::RED << " Expected: " << v2 << console::RESET - << "\n"; - std::cout << console::RED << " Actual: " << v1 << console::RESET - << "\n"; - } + auto print_fail(const char *desc, Ref v1, Ref v2) -> void + { + std::cout << console::BLUE << " " << desc << "... " << console::RED << "FAILED" << console::RESET << "\n"; + std::cout << console::RED << " Expected: " << v2 << console::RESET << "\n"; + std::cout << console::RED << " Actual: " << v1 << console::RESET << "\n"; + } - Mut> m_units; -}; + Mut> m_units; + }; -template -concept ValidBlockClass = std::derived_from; + template + concept ValidBlockClass = std::derived_from; -// ------------------------------------------------------------------------- -// Runner -// ------------------------------------------------------------------------- -template class Runner { + // ------------------------------------------------------------------------- + // Runner + // ------------------------------------------------------------------------- + template class Runner + { public: - Runner() = default; + Runner() = default; - ~Runner() { summarize(); } - - template - requires ValidBlockClass - auto test_block() -> void; - -private: - auto summarize() -> void; - - Mut m_test_count{0}; - Mut m_fail_count{0}; - Mut m_block_count{0}; -}; - -template -template - requires ValidBlockClass -auto Runner::test_block() -> void { - m_block_count++; - Mut b; - b.declare_tests(); - - std::cout << console::MAGENTA << "Testing [" << b.get_name() << "]..." - << console::RESET << "\n"; - - for (MutRef v : b.units()) { - m_test_count++; - if constexpr (IsVerbose) { - std::cout << console::YELLOW << " Testing " << v.name << "...\n" - << console::RESET; + ~Runner() + { + summarize(); } - const bool result = v.functor(); + template + requires ValidBlockClass + auto test_block() -> void; - if (!result) { - m_fail_count++; - if constexpr (StopOnFail) { - summarize(); - std::exit(-1); +private: + auto summarize() -> void; + + Mut m_test_count{0}; + Mut m_fail_count{0}; + Mut m_block_count{0}; + }; + + template + template + requires ValidBlockClass + auto Runner::test_block() -> void + { + m_block_count++; + Mut b; + b.declare_tests(); + + std::cout << console::MAGENTA << "Testing [" << b.get_name() << "]..." << console::RESET << "\n"; + + for (MutRef v : b.units()) + { + m_test_count++; + if constexpr (IsVerbose) + { + std::cout << console::YELLOW << " Testing " << v.name << "...\n" << console::RESET; + } + + const bool result = v.functor(); + + if (!result) + { + m_fail_count++; + if constexpr (StopOnFail) + { + summarize(); + std::exit(-1); + } } } - } - std::cout << "\n"; -} - -template -auto Runner::summarize() -> void { - std::cout << console::GREEN - << "\n-----------------------------------\n\t " - "SUMMARY\n-----------------------------------\n"; - - if (m_fail_count == 0) { - std::cout << "\n\tALL TESTS PASSED!\n\n"; - } else { - const f64 success_rate = - (100.0 * static_cast(m_test_count - m_fail_count) / - static_cast(m_test_count)); - std::cout << console::RED << m_fail_count << " OF " << m_test_count - << " TESTS FAILED\n" - << console::YELLOW - << std::format("Success Rate: {:.2f}%\n", success_rate); + std::cout << "\n"; } - std::cout << console::MAGENTA << "Ran " << m_test_count << " test(s) across " - << m_block_count << " block(s)\n" - << console::GREEN << "-----------------------------------" - << console::RESET << "\n"; -} + template auto Runner::summarize() -> void + { + std::cout << console::GREEN + << "\n-----------------------------------\n\t " + "SUMMARY\n-----------------------------------\n"; -using DefaultRunner = Runner; - -// ------------------------------------------------------------------------- -// Registry -// ------------------------------------------------------------------------- -class TestRegistry { -public: - using TestEntry = std::function)>; - - static auto get_entries() -> MutRef> { - static Mut> entries; - return entries; - } - - static auto run_all() -> i32 { - Mut r; - MutRef> entries = get_entries(); - std::cout << console::CYAN << "[IATest] Discovered " << entries.size() - << " Test Blocks\n\n" - << console::RESET; - - for (MutRef entry : entries) { - entry(r); + if (m_fail_count == 0) + { + std::cout << "\n\tALL TESTS PASSED!\n\n"; + } + else + { + const f64 success_rate = (100.0 * static_cast(m_test_count - m_fail_count) / static_cast(m_test_count)); + std::cout << console::RED << m_fail_count << " OF " << m_test_count << " TESTS FAILED\n" + << console::YELLOW << std::format("Success Rate: {:.2f}%\n", success_rate); } - return 0; + std::cout << console::MAGENTA << "Ran " << m_test_count << " test(s) across " << m_block_count << " block(s)\n" + << console::GREEN << "-----------------------------------" << console::RESET << "\n"; } -}; -template struct AutoRegister { - AutoRegister() { - TestRegistry::get_entries().push_back( - [](MutRef r) { r.test_block(); }); - } -}; + using DefaultRunner = Runner; + + // ------------------------------------------------------------------------- + // Registry + // ------------------------------------------------------------------------- + class TestRegistry + { +public: + using TestEntry = std::function)>; + + static auto get_entries() -> MutRef> + { + static Mut> entries; + return entries; + } + + static auto run_all() -> i32 + { + Mut r; + MutRef> entries = get_entries(); + std::cout << console::CYAN << "[IATest] Discovered " << entries.size() << " Test Blocks\n\n" << console::RESET; + + for (MutRef entry : entries) + { + entry(r); + } + + return 0; + } + }; + + template struct AutoRegister + { + AutoRegister() + { + TestRegistry::get_entries().push_back([](MutRef r) { r.test_block(); }); + } + }; } // namespace IACore::Test -#define IAT_REGISTER_ENTRY(Group, Name) \ - static IACore::Test::AutoRegister _iat_reg_##Group##_##Name; \ No newline at end of file +#define IAT_REGISTER_ENTRY(Group, Name) static IACore::Test::AutoRegister _iat_reg_##Group##_##Name; \ No newline at end of file diff --git a/Src/IACore/inc/IACore/IPC.hpp b/Src/IACore/inc/IACore/IPC.hpp index 2743cd2..77ed443 100644 --- a/Src/IACore/inc/IACore/IPC.hpp +++ b/Src/IACore/inc/IACore/IPC.hpp @@ -19,142 +19,138 @@ #include #include -namespace IACore { -using IpcPacketHeader = RingBufferView::PacketHeader; +namespace IACore +{ + using IpcPacketHeader = RingBufferView::PacketHeader; -struct alignas(64) IpcSharedMemoryLayout { - // ========================================================= - // METADATA & HANDSHAKE - // ========================================================= - struct Header { - Mut magic; // 0x49414950 ("IAIP") - Mut version; // 1 - Mut total_size; // Total size of SHM block + struct alignas(64) IpcSharedMemoryLayout + { + // ========================================================= + // METADATA & HANDSHAKE + // ========================================================= + struct Header + { + Mut magic; // 0x49414950 ("IAIP") + Mut version; // 1 + Mut total_size; // Total size of SHM block + }; + + Mut
meta; + + // Pad to ensure MONI starts on a fresh cache line (64 bytes) + const Array _pad0; + + // ========================================================= + // RING BUFFER CONTROL BLOCKS + // ========================================================= + + // RingBufferView ControlBlock is already 64-byte aligned internally. + Mut moni_control; + Mut mino_control; + + // ========================================================= + // DATA BUFFER OFFSETS + // ========================================================= + + Mut moni_data_offset; + Mut moni_data_size; + + Mut mino_data_offset; + Mut mino_data_size; + + // Pad to ensure the actual Data Buffer starts on a fresh cache line + const Array _pad1; + + static constexpr auto get_header_size() -> usize + { + return sizeof(IpcSharedMemoryLayout); + } }; - Mut
meta; + // Check padding logic is gucci + static_assert(sizeof(IpcSharedMemoryLayout) % 64 == 0, "IPC Layout is not cache-line aligned!"); - // Pad to ensure MONI starts on a fresh cache line (64 bytes) - const Array _pad0; - - // ========================================================= - // RING BUFFER CONTROL BLOCKS - // ========================================================= - - // RingBufferView ControlBlock is already 64-byte aligned internally. - Mut moni_control; - Mut mino_control; - - // ========================================================= - // DATA BUFFER OFFSETS - // ========================================================= - - Mut moni_data_offset; - Mut moni_data_size; - - Mut mino_data_offset; - Mut mino_data_size; - - // Pad to ensure the actual Data Buffer starts on a fresh cache line - const Array _pad1; - - static constexpr auto get_header_size() -> usize { - return sizeof(IpcSharedMemoryLayout); - } -}; - -// Check padding logic is gucci -static_assert(sizeof(IpcSharedMemoryLayout) % 64 == 0, - "IPC Layout is not cache-line aligned!"); - -class IpcNode { + class IpcNode + { public: - virtual ~IpcNode(); + virtual ~IpcNode(); - // When Manager spawns a node, `connection_string` is passed - // as the first command line argument - auto connect(const char *connection_string) -> Result; + // When Manager spawns a node, `connection_string` is passed + // as the first command line argument + auto connect(const char *connection_string) -> Result; - auto update() -> void; - - auto send_signal(const u8 signal) -> void; - auto send_packet(const u16 packet_id, const Span payload) - -> Result; - -protected: - virtual auto on_signal(const u8 signal) -> void = 0; - virtual auto on_packet(const u16 packet_id, const Span payload) - -> void = 0; - -private: - Mut m_shm_name; - Mut m_shared_memory{}; - Mut> m_receive_buffer; - Mut m_socket{INVALID_SOCKET}; - - Mut m_moni; // Manager Out, Node In - Mut m_mino; // Manager In, Node Out -}; - -class IpcManager { - struct NodeSession { - Mut creation_time{}; - Mut> node_process; - - Mut send_mutex; - - Mut shared_mem_name; - Mut mapped_ptr{}; - - Mut listener_socket{INVALID_SOCKET}; - Mut data_socket{INVALID_SOCKET}; - - Mut moni = - RingBufferView::default_instance(); // Manager Out, Node In - Mut mino = - RingBufferView::default_instance(); // Manager In, Node Out - - Mut is_ready{false}; + auto update() -> void; auto send_signal(const u8 signal) -> void; - auto send_packet(const u16 packet_id, const Span payload) - -> Result; - }; - -public: - static constexpr const u32 DEFAULT_NODE_SHARED_MEMORY_SIZE = 4 * 1024 * 1024; - -public: - virtual ~IpcManager(); - - auto update() -> void; - - auto - spawn_node(Ref executable_path, - const u32 shared_memory_size = DEFAULT_NODE_SHARED_MEMORY_SIZE) - -> Result; - - auto wait_till_node_is_online(const NativeProcessID node) -> bool; - - auto shutdown_node(const NativeProcessID node) -> void; - - auto send_signal(const NativeProcessID node, const u8 signal) -> void; - auto send_packet(const NativeProcessID node, const u16 packet_id, - const Span payload) -> Result; + auto send_packet(const u16 packet_id, const Span payload) -> Result; protected: - virtual auto on_signal(const NativeProcessID node, const u8 signal) - -> void = 0; - virtual auto on_packet(const NativeProcessID node, const u16 packet_id, - const Span payload) -> void = 0; + virtual auto on_signal(const u8 signal) -> void = 0; + virtual auto on_packet(const u16 packet_id, const Span payload) -> void = 0; private: - Mut> m_receive_buffer; - Mut>> m_active_sessions; - Mut>> m_pending_sessions; - Mut> m_active_session_map; + Mut m_shm_name; + Mut m_shared_memory{}; + Mut> m_receive_buffer; + Mut m_socket{INVALID_SOCKET}; + + Mut m_moni; // Manager Out, Node In + Mut m_mino; // Manager In, Node Out + }; + + class IpcManager + { + struct NodeSession + { + Mut creation_time{}; + Mut> node_process; + + Mut send_mutex; + + Mut shared_mem_name; + Mut mapped_ptr{}; + + Mut listener_socket{INVALID_SOCKET}; + Mut data_socket{INVALID_SOCKET}; + + Mut moni = RingBufferView::default_instance(); // Manager Out, Node In + Mut mino = RingBufferView::default_instance(); // Manager In, Node Out + + Mut is_ready{false}; + + auto send_signal(const u8 signal) -> void; + auto send_packet(const u16 packet_id, const Span payload) -> Result; + }; + +public: + static constexpr const u32 DEFAULT_NODE_SHARED_MEMORY_SIZE = 4 * 1024 * 1024; + +public: + virtual ~IpcManager(); + + auto update() -> void; + + auto spawn_node(Ref executable_path, const u32 shared_memory_size = DEFAULT_NODE_SHARED_MEMORY_SIZE) + -> Result; + + auto wait_till_node_is_online(const NativeProcessID node) -> bool; + + auto shutdown_node(const NativeProcessID node) -> void; + + auto send_signal(const NativeProcessID node, const u8 signal) -> void; + auto send_packet(const NativeProcessID node, const u16 packet_id, const Span payload) -> Result; protected: - IpcManager(); -}; + virtual auto on_signal(const NativeProcessID node, const u8 signal) -> void = 0; + virtual auto on_packet(const NativeProcessID node, const u16 packet_id, const Span payload) -> void = 0; + +private: + Mut> m_receive_buffer; + Mut>> m_active_sessions; + Mut>> m_pending_sessions; + Mut> m_active_session_map; + +protected: + IpcManager(); + }; } // namespace IACore \ No newline at end of file diff --git a/Src/IACore/inc/IACore/JSON.hpp b/Src/IACore/inc/IACore/JSON.hpp index 00cc593..f95b302 100644 --- a/Src/IACore/inc/IACore/JSON.hpp +++ b/Src/IACore/inc/IACore/JSON.hpp @@ -21,99 +21,104 @@ #include #include -namespace IACore { -class JsonDocument { +namespace IACore +{ + class JsonDocument + { public: - JsonDocument(ForwardRef) noexcept = default; - auto operator=(ForwardRef) noexcept - -> MutRef = default; + JsonDocument(ForwardRef) noexcept = default; + auto operator=(ForwardRef) noexcept -> MutRef = default; - JsonDocument(Ref) = delete; - auto operator=(Ref) -> MutRef = delete; + JsonDocument(Ref) = delete; + auto operator=(Ref) -> MutRef = delete; - [[nodiscard]] - auto root() const noexcept -> simdjson::dom::element { - return m_root; - } + [[nodiscard]] + auto root() const noexcept -> simdjson::dom::element + { + return m_root; + } private: - friend class Json; + friend class Json; - JsonDocument(Mut> p, Mut r) - : m_parser(std::move(p)), m_root(r) {} + JsonDocument(Mut> p, Mut r) : m_parser(std::move(p)), m_root(r) + { + } - Mut> m_parser; - Mut m_root; -}; + Mut> m_parser; + Mut m_root; + }; -class Json { + class Json + { private: - static constexpr const glz::opts GLAZE_OPTS = - glz::opts{.error_on_unknown_keys = false}; + static constexpr const glz::opts GLAZE_OPTS = glz::opts{.error_on_unknown_keys = false}; public: - static auto parse(Ref json_str) -> Result; - static auto encode(Ref data) -> String; + static auto parse(Ref json_str) -> Result; + static auto encode(Ref data) -> String; - static auto parse_read_only(Ref json_str) -> Result; + static auto parse_read_only(Ref json_str) -> Result; - template - static auto parse_to_struct(Ref json_str) -> Result; + template static auto parse_to_struct(Ref json_str) -> Result; - template - static auto encode_struct(Ref data) -> Result; -}; + template static auto encode_struct(Ref data) -> Result; + }; -inline auto Json::parse(Ref json_str) -> Result { - const nlohmann::json res = - nlohmann::json::parse(json_str, nullptr, false, true); + inline auto Json::parse(Ref json_str) -> Result + { + const nlohmann::json res = nlohmann::json::parse(json_str, nullptr, false, true); - if (res.is_discarded()) { - return fail("Failed to parse JSON (Invalid Syntax)"); - } - return res; -} - -inline auto Json::parse_read_only(Ref json_str) - -> Result { - Mut> parser = make_box(); - - Mut root; - - const simdjson::error_code error = parser->parse(json_str).get(root); - - if (error) { - return fail("JSON Error: {}", simdjson::error_message(error)); + if (res.is_discarded()) + { + return fail("Failed to parse JSON (Invalid Syntax)"); + } + return res; } - return JsonDocument(std::move(parser), root); -} + inline auto Json::parse_read_only(Ref json_str) -> Result + { + Mut> parser = make_box(); -inline auto Json::encode(Ref data) -> String { - return data.dump(); -} + Mut root; -template -inline auto Json::parse_to_struct(Ref json_str) -> Result { - Mut result{}; + const simdjson::error_code error = parser->parse(json_str).get(root); - const glz::error_ctx err = glz::read(result, json_str); + if (error) + { + return fail("JSON Error: {}", simdjson::error_message(error)); + } - if (err) { - return fail("JSON Struct Parse Error: {}", - glz::format_error(err, json_str)); + return JsonDocument(std::move(parser), root); } - return result; -} -template -inline auto Json::encode_struct(Ref data) -> Result { - Mut result; - const glz::error_ctx err = glz::write_json(data, result); - - if (err) { - return fail("JSON Struct Encode Error"); + inline auto Json::encode(Ref data) -> String + { + return data.dump(); + } + + template inline auto Json::parse_to_struct(Ref json_str) -> Result + { + Mut result{}; + + const glz::error_ctx err = glz::read(result, json_str); + + if (err) + { + return fail("JSON Struct Parse Error: {}", glz::format_error(err, json_str)); + } + return result; + } + + template inline auto Json::encode_struct(Ref data) -> Result + { + Mut result; + const glz::error_ctx err = glz::write_json(data, result); + + if (err) + { + return fail("JSON Struct Encode Error"); + } + return result; } - return result; -} } // namespace IACore \ No newline at end of file diff --git a/Src/IACore/inc/IACore/Logger.hpp b/Src/IACore/inc/IACore/Logger.hpp index b22346d..e9ed91c 100644 --- a/Src/IACore/inc/IACore/Logger.hpp +++ b/Src/IACore/inc/IACore/Logger.hpp @@ -18,8 +18,7 @@ #include #define IA_LOG_SET_FILE(path) IACore::Logger::enable_logging_to_disk(path) -#define IA_LOG_SET_LEVEL(level) \ - IACore::Logger::set_log_level(IACore::Logger::LogLevel::level) +#define IA_LOG_SET_LEVEL(level) IACore::Logger::set_log_level(IACore::Logger::LogLevel::level) #define IA_LOG_TRACE(...) IACore::Logger::trace(__VA_ARGS__) #define IA_LOG_DEBUG(...) IACore::Logger::debug(__VA_ARGS__) @@ -27,96 +26,122 @@ #define IA_LOG_WARN(...) IACore::Logger::warn(__VA_ARGS__) #define IA_LOG_ERROR(...) IACore::Logger::error(__VA_ARGS__) -namespace IACore { -class Logger { +namespace IACore +{ + class Logger + { public: - enum class LogLevel { Trace, Debug, Info, Warn, Error }; + enum class LogLevel + { + Trace, + Debug, + Info, + Warn, + Error + }; public: - static auto enable_logging_to_disk(const char *file_path) -> Result; - static auto set_log_level(const LogLevel log_level) -> void; + static auto enable_logging_to_disk(const char *file_path) -> Result; + static auto set_log_level(const LogLevel log_level) -> void; - template - static auto trace(const std::format_string fmt, - ForwardRef... args) -> void { - log_trace(std::vformat(fmt.get(), std::make_format_args(args...))); - } + template + static auto trace(const std::format_string fmt, ForwardRef... args) -> void + { + log_trace(std::vformat(fmt.get(), std::make_format_args(args...))); + } - template - static auto debug(const std::format_string fmt, - ForwardRef... args) -> void { - log_debug(std::vformat(fmt.get(), std::make_format_args(args...))); - } + template + static auto debug(const std::format_string fmt, ForwardRef... args) -> void + { + log_debug(std::vformat(fmt.get(), std::make_format_args(args...))); + } - template - static auto info(const std::format_string fmt, - ForwardRef... args) -> void { - log_info(std::vformat(fmt.get(), std::make_format_args(args...))); - } + template static auto info(const std::format_string fmt, ForwardRef... args) -> void + { + log_info(std::vformat(fmt.get(), std::make_format_args(args...))); + } - template - static auto warn(const std::format_string fmt, - ForwardRef... args) -> void { - log_warn(std::vformat(fmt.get(), std::make_format_args(args...))); - } + template static auto warn(const std::format_string fmt, ForwardRef... args) -> void + { + log_warn(std::vformat(fmt.get(), std::make_format_args(args...))); + } - template - static auto error(const std::format_string fmt, - ForwardRef... args) -> void { - log_error(std::vformat(fmt.get(), std::make_format_args(args...))); - } + template + static auto error(const std::format_string fmt, ForwardRef... args) -> void + { + log_error(std::vformat(fmt.get(), std::make_format_args(args...))); + } - static auto flush_logs() -> void; + static auto flush_logs() -> void; private: #if IA_DISABLE_LOGGING > 0 - static auto log_trace(ForwardRef msg) -> void { IA_UNUSED(msg); } + static auto log_trace(ForwardRef msg) -> void + { + IA_UNUSED(msg); + } - static auto log_debug(ForwardRef msg) -> void { IA_UNUSED(msg); } + static auto log_debug(ForwardRef msg) -> void + { + IA_UNUSED(msg); + } - static auto log_info(ForwardRef msg) -> void { IA_UNUSED(msg); } + static auto log_info(ForwardRef msg) -> void + { + IA_UNUSED(msg); + } - static auto log_warn(ForwardRef msg) -> void { IA_UNUSED(msg); } + static auto log_warn(ForwardRef msg) -> void + { + IA_UNUSED(msg); + } - static auto log_error(ForwardRef msg) -> void { IA_UNUSED(msg); } + static auto log_error(ForwardRef msg) -> void + { + IA_UNUSED(msg); + } #else - static auto log_trace(ForwardRef msg) -> void { - if (m_log_level <= LogLevel::Trace) - log_internal(console::RESET, "TRACE", std::move(msg)); - } + static auto log_trace(ForwardRef msg) -> void + { + if (m_log_level <= LogLevel::Trace) + log_internal(console::RESET, "TRACE", std::move(msg)); + } - static auto log_debug(ForwardRef msg) -> void { - if (m_log_level <= LogLevel::Debug) - log_internal(console::CYAN, "DEBUG", std::move(msg)); - } + static auto log_debug(ForwardRef msg) -> void + { + if (m_log_level <= LogLevel::Debug) + log_internal(console::CYAN, "DEBUG", std::move(msg)); + } - static auto log_info(ForwardRef msg) -> void { - if (m_log_level <= LogLevel::Info) - log_internal(console::GREEN, "INFO", std::move(msg)); - } + static auto log_info(ForwardRef msg) -> void + { + if (m_log_level <= LogLevel::Info) + log_internal(console::GREEN, "INFO", std::move(msg)); + } - static auto log_warn(ForwardRef msg) -> void { - if (m_log_level <= LogLevel::Warn) - log_internal(console::YELLOW, "WARN", std::move(msg)); - } + static auto log_warn(ForwardRef msg) -> void + { + if (m_log_level <= LogLevel::Warn) + log_internal(console::YELLOW, "WARN", std::move(msg)); + } - static auto log_error(ForwardRef msg) -> void { - if (m_log_level <= LogLevel::Error) - log_internal(console::RED, "ERROR", std::move(msg)); - } + static auto log_error(ForwardRef msg) -> void + { + if (m_log_level <= LogLevel::Error) + log_internal(console::RED, "ERROR", std::move(msg)); + } #endif - static auto log_internal(const char *prefix, const char *tag, - ForwardRef msg) -> void; + static auto log_internal(const char *prefix, const char *tag, ForwardRef msg) -> void; private: - static Mut m_log_level; - static Mut m_log_file; + static Mut m_log_level; + static Mut m_log_file; - static auto initialize() -> void; - static auto terminate() -> void; + static auto initialize() -> void; + static auto terminate() -> void; - friend void initialize(); - friend void terminate(); -}; + friend void initialize(); + friend void terminate(); + }; } // namespace IACore \ No newline at end of file diff --git a/Src/IACore/inc/IACore/PCH.hpp b/Src/IACore/inc/IACore/PCH.hpp index a58aab8..621c842 100644 --- a/Src/IACore/inc/IACore/PCH.hpp +++ b/Src/IACore/inc/IACore/PCH.hpp @@ -16,42 +16,42 @@ #pragma once #if defined(__x86_64__) || defined(_M_X64) || defined(_M_AMD64) -#define IA_ARCH_X64 1 +# define IA_ARCH_X64 1 #elif defined(__aarch64__) || defined(_M_ARM64) -#define IA_ARCH_ARM64 1 +# define IA_ARCH_ARM64 1 #elif defined(__wasm__) || defined(__wasm32__) || defined(__wasm64__) -#define IA_ARCH_WASM 1 +# define IA_ARCH_WASM 1 #else -#error "IACore: Unsupported Architecture." +# error "IACore: Unsupported Architecture." #endif #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) -#define IA_PLATFORM_WINDOWS 1 +# define IA_PLATFORM_WINDOWS 1 #elif __APPLE__ -#include -#define IA_PLATFORM_APPLE 1 -#define IA_PLATFORM_UNIX 1 +# include +# define IA_PLATFORM_APPLE 1 +# define IA_PLATFORM_UNIX 1 #elif __linux__ -#define IA_PLATFORM_LINUX 1 -#define IA_PLATFORM_UNIX 1 +# define IA_PLATFORM_LINUX 1 +# define IA_PLATFORM_UNIX 1 #elif __wasm__ -#define IA_PLATFORM_WASM 1 +# define IA_PLATFORM_WASM 1 #else -#error "IACore: Unsupported Platform." +# error "IACore: Unsupported Platform." #endif #if IA_PLATFORM_WINDOWS -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#ifndef NOMINMAX -#define NOMINMAX -#endif -#include +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# ifndef NOMINMAX +# define NOMINMAX +# endif +# include #elif IA_PLATFORM_UNIX -#include -#include -#include +# include +# include +# include #endif #include @@ -70,66 +70,69 @@ #include -namespace IACore { +namespace IACore +{ -using namespace Auxid; + using namespace Auxid; -// ============================================================================= -// Build Environment & Constants -// ============================================================================= -namespace Env { + // ============================================================================= + // Build Environment & Constants + // ============================================================================= + namespace Env + { -using namespace Auxid::Env; + using namespace Auxid::Env; #if IA_PLATFORM_WINDOWS -constexpr const bool IS_WINDOWS = true; -constexpr const bool IS_UNIX = false; + constexpr const bool IS_WINDOWS = true; + constexpr const bool IS_UNIX = false; #else -constexpr const bool IS_WINDOWS = false; -constexpr const bool IS_UNIX = true; + constexpr const bool IS_WINDOWS = false; + constexpr const bool IS_UNIX = true; #endif -constexpr const usize MAX_PATH_LEN = 4096; + constexpr const usize MAX_PATH_LEN = 4096; -} // namespace Env + } // namespace Env -// ============================================================================= -// Data Structures & Aliases -// ============================================================================= -template -using HashMap = ankerl::unordered_dense::map; -template using HashSet = ankerl::unordered_dense::set; + // ============================================================================= + // Data Structures & Aliases + // ============================================================================= + template using HashMap = ankerl::unordered_dense::map; + template using HashSet = ankerl::unordered_dense::set; -using Path = std::filesystem::path; + using Path = std::filesystem::path; -// ============================================================================= -// Versioning -// ============================================================================= -struct Version { - u32 major = 0; - u32 minor = 0; - u32 patch = 0; + // ============================================================================= + // Versioning + // ============================================================================= + struct Version + { + u32 major = 0; + u32 minor = 0; + u32 patch = 0; - [[nodiscard]] constexpr auto to_u64() const -> u64 { - return (static_cast(major) << 40) | (static_cast(minor) << 16) | - (static_cast(patch)); - } -}; + [[nodiscard]] constexpr auto to_u64() const -> u64 + { + return (static_cast(major) << 40) | (static_cast(minor) << 16) | (static_cast(patch)); + } + }; -// ============================================================================= -// Console Colors -// ============================================================================= -namespace console { -constexpr const char *RESET = "\033[0m"; -constexpr const char *RED = "\033[31m"; -constexpr const char *GREEN = "\033[32m"; -constexpr const char *YELLOW = "\033[33m"; -constexpr const char *BLUE = "\033[34m"; -constexpr const char *MAGENTA = "\033[35m"; -constexpr const char *CYAN = "\033[36m"; -} // namespace console + // ============================================================================= + // Console Colors + // ============================================================================= + namespace console + { + constexpr const char *RESET = "\033[0m"; + constexpr const char *RED = "\033[31m"; + constexpr const char *GREEN = "\033[32m"; + constexpr const char *YELLOW = "\033[33m"; + constexpr const char *BLUE = "\033[34m"; + constexpr const char *MAGENTA = "\033[35m"; + constexpr const char *CYAN = "\033[36m"; + } // namespace console } // namespace IACore #define IA_NODISCARD [[nodiscard]] -#define IA_UNUSED(v) (void)(v) +#define IA_UNUSED(v) (void) (v) diff --git a/Src/IACore/inc/IACore/Platform.hpp b/Src/IACore/inc/IACore/Platform.hpp index 49bf133..40147b5 100644 --- a/Src/IACore/inc/IACore/Platform.hpp +++ b/Src/IACore/inc/IACore/Platform.hpp @@ -18,35 +18,40 @@ #include #if IA_ARCH_X64 -#ifdef _MSC_VER -#include -#else -#include -#endif +# ifdef _MSC_VER +# include +# else +# include +# endif #elif IA_ARCH_ARM64 -#include +# include #endif -namespace IACore { -class Platform { +namespace IACore +{ + class Platform + { public: - struct Capabilities { - Mut hardware_crc32 = false; - }; + struct Capabilities + { + Mut hardware_crc32 = false; + }; - static auto check_cpu() -> bool; + static auto check_cpu() -> bool; #if IA_ARCH_X64 - static auto cpuid(const i32 function, const i32 sub_function, Mut out) - -> void; + static auto cpuid(const i32 function, const i32 sub_function, Mut out) -> void; #endif - static auto get_architecture_name() -> const char *; - static auto get_operating_system_name() -> const char *; + static auto get_architecture_name() -> const char *; + static auto get_operating_system_name() -> const char *; - static auto get_capabilities() -> Ref { return s_capabilities; } + static auto get_capabilities() -> Ref + { + return s_capabilities; + } private: - static Mut s_capabilities; -}; + static Mut s_capabilities; + }; } // namespace IACore \ No newline at end of file diff --git a/Src/IACore/inc/IACore/ProcessOps.hpp b/Src/IACore/inc/IACore/ProcessOps.hpp index 7f7ba04..783c107 100644 --- a/Src/IACore/inc/IACore/ProcessOps.hpp +++ b/Src/IACore/inc/IACore/ProcessOps.hpp @@ -22,48 +22,49 @@ using NativeProcessID = DWORD; #elif IA_PLATFORM_UNIX using NativeProcessID = pid_t; #else -#error "This platform does not support IACore ProcessOps" +# error "This platform does not support IACore ProcessOps" #endif -namespace IACore { -struct ProcessHandle { - Mut> id{0}; - Mut> is_running{false}; +namespace IACore +{ + struct ProcessHandle + { + Mut> id{0}; + Mut> is_running{false}; - [[nodiscard]] auto is_active() const -> bool { return is_running && id != 0; } + [[nodiscard]] auto is_active() const -> bool + { + return is_running && id != 0; + } private: - Mut m_thread_handle; + Mut m_thread_handle; - friend class ProcessOps; -}; + friend class ProcessOps; + }; -class ProcessOps { + class ProcessOps + { public: - static auto get_current_process_id() -> NativeProcessID; + static auto get_current_process_id() -> NativeProcessID; - static auto spawn_process_sync( - Ref command, Ref args, - const std::function on_output_line_callback) - -> Result; + static auto spawn_process_sync(Ref command, Ref args, + const std::function on_output_line_callback) -> Result; - static auto spawn_process_async( - Ref command, Ref args, - const std::function on_output_line_callback, - const std::function)> on_finish_callback) - -> Result>; + static auto spawn_process_async(Ref command, Ref args, + const std::function on_output_line_callback, + const std::function)> on_finish_callback) + -> Result>; - static auto terminate_process(Ref> handle) -> void; + static auto terminate_process(Ref> handle) -> void; private: - static auto spawn_process_windows( - Ref command, Ref args, - const std::function on_output_line_callback, - MutRef> id) -> Result; + static auto spawn_process_windows(Ref command, Ref args, + const std::function on_output_line_callback, + MutRef> id) -> Result; - static auto spawn_process_posix( - Ref command, Ref args, - const std::function on_output_line_callback, - MutRef> id) -> Result; -}; + static auto spawn_process_posix(Ref command, Ref args, + const std::function on_output_line_callback, + MutRef> id) -> Result; + }; } // namespace IACore \ No newline at end of file diff --git a/Src/IACore/inc/IACore/SIMD.hpp b/Src/IACore/inc/IACore/SIMD.hpp index 872bf32..d05b8b0 100644 --- a/Src/IACore/inc/IACore/SIMD.hpp +++ b/Src/IACore/inc/IACore/SIMD.hpp @@ -18,261 +18,301 @@ #include #if defined(__clang__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-parameter" -#pragma GCC diagnostic ignored "-Wgnu-zero-variadic-macro-arguments" +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wunused-parameter" +# pragma GCC diagnostic ignored "-Wgnu-zero-variadic-macro-arguments" #endif #include #if defined(__clang__) -#pragma GCC diagnostic pop +# pragma GCC diagnostic pop #endif -namespace IACore { -namespace hn = hwy::HWY_NAMESPACE; +namespace IACore +{ + namespace hn = hwy::HWY_NAMESPACE; #if HWY_TARGET == HWY_SCALAR -#pragma message( \ - "Warning: Configuration mismatch. IACore is being compiled for SCALAR SIMD (Slow)") +# pragma message("Warning: Configuration mismatch. IACore is being compiled for SCALAR SIMD (Slow)") #endif -class alignas(16) IntVec4 { + class alignas(16) IntVec4 + { public: - IntVec4() = default; + IntVec4() = default; - inline explicit IntVec4(const u32 s); - inline explicit IntVec4(const u32 *values); - inline explicit IntVec4(const u32 a, const u32 b, const u32 c, const u32 d); + inline explicit IntVec4(const u32 s); + inline explicit IntVec4(const u32 *values); + inline explicit IntVec4(const u32 a, const u32 b, const u32 c, const u32 d); - inline auto operator+(Ref other) const -> IntVec4; - inline auto operator-(Ref other) const -> IntVec4; - inline auto operator*(Ref other) const -> IntVec4; + inline auto operator+(Ref other) const -> IntVec4; + inline auto operator-(Ref other) const -> IntVec4; + inline auto operator*(Ref other) const -> IntVec4; - inline auto operator&(Ref other) const -> IntVec4; - inline auto operator|(Ref other) const -> IntVec4; - inline auto operator^(Ref other) const -> IntVec4; - inline auto operator~() const -> IntVec4; + inline auto operator&(Ref other) const -> IntVec4; + inline auto operator|(Ref other) const -> IntVec4; + inline auto operator^(Ref other) const -> IntVec4; + inline auto operator~() const -> IntVec4; - inline auto operator<<(const u32 amount) const -> IntVec4; - inline auto operator>>(const u32 amount) const -> IntVec4; + inline auto operator<<(const u32 amount) const -> IntVec4; + inline auto operator>>(const u32 amount) const -> IntVec4; - [[nodiscard]] inline auto sat_add(Ref other) const -> IntVec4; - [[nodiscard]] inline auto sat_sub(Ref other) const -> IntVec4; + [[nodiscard]] inline auto sat_add(Ref other) const -> IntVec4; + [[nodiscard]] inline auto sat_sub(Ref other) const -> IntVec4; - [[nodiscard]] inline auto clamp(const u32 min, const u32 max) const - -> IntVec4; + [[nodiscard]] inline auto clamp(const u32 min, const u32 max) const -> IntVec4; - [[nodiscard]] inline auto mult_add(Ref multiplier, - Ref addend) const -> IntVec4; + [[nodiscard]] inline auto mult_add(Ref multiplier, Ref addend) const -> IntVec4; - inline auto store(Mut values) -> void; - static inline auto load(const u32 *values) -> IntVec4; + inline auto store(Mut values) -> void; + static inline auto load(const u32 *values) -> IntVec4; private: - using Tag = hn::FixedTag; + using Tag = hn::FixedTag; - Mut> m_data; + Mut> m_data; - inline explicit IntVec4(const hn::Vec v) : m_data(v) {} -}; + inline explicit IntVec4(const hn::Vec v) : m_data(v) + { + } + }; -class alignas(16) FloatVec4 { + class alignas(16) FloatVec4 + { public: - FloatVec4() = default; + FloatVec4() = default; - inline explicit FloatVec4(const f32 s); - inline explicit FloatVec4(const f32 *values); - inline explicit FloatVec4(const f32 a, const f32 b, const f32 c, const f32 d); + inline explicit FloatVec4(const f32 s); + inline explicit FloatVec4(const f32 *values); + inline explicit FloatVec4(const f32 a, const f32 b, const f32 c, const f32 d); - inline auto operator+(Ref other) const -> FloatVec4; - inline auto operator-(Ref other) const -> FloatVec4; - inline auto operator*(Ref other) const -> FloatVec4; - inline auto operator/(Ref other) const -> FloatVec4; + inline auto operator+(Ref other) const -> FloatVec4; + inline auto operator-(Ref other) const -> FloatVec4; + inline auto operator*(Ref other) const -> FloatVec4; + inline auto operator/(Ref other) const -> FloatVec4; - [[nodiscard]] inline auto clamp(const f32 min, const f32 max) const - -> FloatVec4; + [[nodiscard]] inline auto clamp(const f32 min, const f32 max) const -> FloatVec4; - [[nodiscard]] inline auto abs() const -> FloatVec4; - [[nodiscard]] inline auto sqrt() const -> FloatVec4; - [[nodiscard]] inline auto rsqrt() const -> FloatVec4; - [[nodiscard]] inline auto normalize() const -> FloatVec4; + [[nodiscard]] inline auto abs() const -> FloatVec4; + [[nodiscard]] inline auto sqrt() const -> FloatVec4; + [[nodiscard]] inline auto rsqrt() const -> FloatVec4; + [[nodiscard]] inline auto normalize() const -> FloatVec4; - [[nodiscard]] inline auto dot(Ref other) const -> f32; + [[nodiscard]] inline auto dot(Ref other) const -> f32; - [[nodiscard]] inline auto mult_add(Ref multiplier, - Ref addend) const -> FloatVec4; + [[nodiscard]] inline auto mult_add(Ref multiplier, Ref addend) const -> FloatVec4; - inline auto store(Mut values) -> void; - static inline auto load(const f32 *values) -> FloatVec4; + inline auto store(Mut values) -> void; + static inline auto load(const f32 *values) -> FloatVec4; private: - using Tag = hn::FixedTag; + using Tag = hn::FixedTag; - Mut> m_data; + Mut> m_data; - inline explicit FloatVec4(const hn::Vec v) : m_data(v) {} -}; + inline explicit FloatVec4(const hn::Vec v) : m_data(v) + { + } + }; } // namespace IACore -namespace IACore { -IntVec4::IntVec4(const u32 s) { - const Tag d; - m_data = hn::Set(d, s); -} +namespace IACore +{ + IntVec4::IntVec4(const u32 s) + { + const Tag d; + m_data = hn::Set(d, s); + } -IntVec4::IntVec4(const u32 *values) { - const Tag data; - m_data = hn::Load(data, values); -} + IntVec4::IntVec4(const u32 *values) + { + const Tag data; + m_data = hn::Load(data, values); + } -IntVec4::IntVec4(const u32 a, const u32 b, const u32 c, const u32 d) { - const Tag data; - alignas(16) Mut> values = {a, b, c, d}; - m_data = hn::Load(data, values.data()); -} + IntVec4::IntVec4(const u32 a, const u32 b, const u32 c, const u32 d) + { + const Tag data; + alignas(16) Mut> values = {a, b, c, d}; + m_data = hn::Load(data, values.data()); + } -auto IntVec4::operator+(Ref other) const -> IntVec4 { - return IntVec4(hn::Add(m_data, other.m_data)); -} + auto IntVec4::operator+(Ref other) const -> IntVec4 + { + return IntVec4(hn::Add(m_data, other.m_data)); + } -auto IntVec4::operator-(Ref other) const -> IntVec4 { - return IntVec4(hn::Sub(m_data, other.m_data)); -} + auto IntVec4::operator-(Ref other) const -> IntVec4 + { + return IntVec4(hn::Sub(m_data, other.m_data)); + } -auto IntVec4::operator*(Ref other) const -> IntVec4 { - return IntVec4(hn::Mul(m_data, other.m_data)); -} + auto IntVec4::operator*(Ref other) const -> IntVec4 + { + return IntVec4(hn::Mul(m_data, other.m_data)); + } -auto IntVec4::operator&(Ref other) const -> IntVec4 { - return IntVec4(hn::And(m_data, other.m_data)); -} + auto IntVec4::operator&(Ref other) const -> IntVec4 + { + return IntVec4(hn::And(m_data, other.m_data)); + } -auto IntVec4::operator|(Ref other) const -> IntVec4 { - return IntVec4(hn::Or(m_data, other.m_data)); -} + auto IntVec4::operator|(Ref other) const -> IntVec4 + { + return IntVec4(hn::Or(m_data, other.m_data)); + } -auto IntVec4::operator^(Ref other) const -> IntVec4 { - return IntVec4(hn::Xor(m_data, other.m_data)); -} + auto IntVec4::operator^(Ref other) const -> IntVec4 + { + return IntVec4(hn::Xor(m_data, other.m_data)); + } -auto IntVec4::operator~() const -> IntVec4 { return IntVec4(hn::Not(m_data)); } + auto IntVec4::operator~() const -> IntVec4 + { + return IntVec4(hn::Not(m_data)); + } -auto IntVec4::operator<<(const u32 amount) const -> IntVec4 { - return IntVec4(hn::ShiftLeftSame(m_data, amount)); -} + auto IntVec4::operator<<(const u32 amount) const -> IntVec4 + { + return IntVec4(hn::ShiftLeftSame(m_data, amount)); + } -auto IntVec4::operator>>(const u32 amount) const -> IntVec4 { - return IntVec4(hn::ShiftRightSame(m_data, amount)); -} + auto IntVec4::operator>>(const u32 amount) const -> IntVec4 + { + return IntVec4(hn::ShiftRightSame(m_data, amount)); + } -auto IntVec4::mult_add(Ref multiplier, Ref addend) const - -> IntVec4 { - return IntVec4(hn::MulAdd(m_data, multiplier.m_data, addend.m_data)); -} + auto IntVec4::mult_add(Ref multiplier, Ref addend) const -> IntVec4 + { + return IntVec4(hn::MulAdd(m_data, multiplier.m_data, addend.m_data)); + } -auto IntVec4::sat_add(Ref other) const -> IntVec4 { - return IntVec4(hn::SaturatedAdd(m_data, other.m_data)); -} + auto IntVec4::sat_add(Ref other) const -> IntVec4 + { + return IntVec4(hn::SaturatedAdd(m_data, other.m_data)); + } -auto IntVec4::sat_sub(Ref other) const -> IntVec4 { - return IntVec4(hn::SaturatedSub(m_data, other.m_data)); -} + auto IntVec4::sat_sub(Ref other) const -> IntVec4 + { + return IntVec4(hn::SaturatedSub(m_data, other.m_data)); + } -auto IntVec4::clamp(const u32 min, const u32 max) const -> IntVec4 { - const Tag d; - const hn::Vec v_min = hn::Set(d, min); - const hn::Vec v_max = hn::Set(d, max); - return IntVec4(hn::Min(hn::Max(m_data, v_min), v_max)); -} + auto IntVec4::clamp(const u32 min, const u32 max) const -> IntVec4 + { + const Tag d; + const hn::Vec v_min = hn::Set(d, min); + const hn::Vec v_max = hn::Set(d, max); + return IntVec4(hn::Min(hn::Max(m_data, v_min), v_max)); + } -auto IntVec4::store(Mut values) -> void { - const Tag d; - hn::Store(m_data, d, values); -} + auto IntVec4::store(Mut values) -> void + { + const Tag d; + hn::Store(m_data, d, values); + } -auto IntVec4::load(const u32 *values) -> IntVec4 { - const Tag d; - return IntVec4(hn::Load(d, values)); -} + auto IntVec4::load(const u32 *values) -> IntVec4 + { + const Tag d; + return IntVec4(hn::Load(d, values)); + } } // namespace IACore -namespace IACore { -FloatVec4::FloatVec4(const f32 s) { - const Tag d; - m_data = hn::Set(d, s); -} +namespace IACore +{ + FloatVec4::FloatVec4(const f32 s) + { + const Tag d; + m_data = hn::Set(d, s); + } -FloatVec4::FloatVec4(const f32 *values) { - const Tag d; - m_data = hn::Load(d, values); -} + FloatVec4::FloatVec4(const f32 *values) + { + const Tag d; + m_data = hn::Load(d, values); + } -FloatVec4::FloatVec4(const f32 a, const f32 b, const f32 c, const f32 d) { - const Tag data; - alignas(16) Mut> temp = {a, b, c, d}; - m_data = hn::Load(data, temp.data()); -} + FloatVec4::FloatVec4(const f32 a, const f32 b, const f32 c, const f32 d) + { + const Tag data; + alignas(16) Mut> temp = {a, b, c, d}; + m_data = hn::Load(data, temp.data()); + } -auto FloatVec4::operator+(Ref other) const -> FloatVec4 { - return FloatVec4(hn::Add(m_data, other.m_data)); -} + auto FloatVec4::operator+(Ref other) const -> FloatVec4 + { + return FloatVec4(hn::Add(m_data, other.m_data)); + } -auto FloatVec4::operator-(Ref other) const -> FloatVec4 { - return FloatVec4(hn::Sub(m_data, other.m_data)); -} + auto FloatVec4::operator-(Ref other) const -> FloatVec4 + { + return FloatVec4(hn::Sub(m_data, other.m_data)); + } -auto FloatVec4::operator*(Ref other) const -> FloatVec4 { - return FloatVec4(hn::Mul(m_data, other.m_data)); -} + auto FloatVec4::operator*(Ref other) const -> FloatVec4 + { + return FloatVec4(hn::Mul(m_data, other.m_data)); + } -auto FloatVec4::operator/(Ref other) const -> FloatVec4 { - return FloatVec4(hn::Div(m_data, other.m_data)); -} + auto FloatVec4::operator/(Ref other) const -> FloatVec4 + { + return FloatVec4(hn::Div(m_data, other.m_data)); + } -auto FloatVec4::mult_add(Ref multiplier, Ref addend) const - -> FloatVec4 { - return FloatVec4(hn::MulAdd(m_data, multiplier.m_data, addend.m_data)); -} + auto FloatVec4::mult_add(Ref multiplier, Ref addend) const -> FloatVec4 + { + return FloatVec4(hn::MulAdd(m_data, multiplier.m_data, addend.m_data)); + } -auto FloatVec4::clamp(const f32 min, const f32 max) const -> FloatVec4 { - const Tag d; - const hn::Vec v_min = hn::Set(d, min); - const hn::Vec v_max = hn::Set(d, max); - return FloatVec4(hn::Min(hn::Max(m_data, v_min), v_max)); -} + auto FloatVec4::clamp(const f32 min, const f32 max) const -> FloatVec4 + { + const Tag d; + const hn::Vec v_min = hn::Set(d, min); + const hn::Vec v_max = hn::Set(d, max); + return FloatVec4(hn::Min(hn::Max(m_data, v_min), v_max)); + } -auto FloatVec4::sqrt() const -> FloatVec4 { - return FloatVec4(hn::Sqrt(m_data)); -} + auto FloatVec4::sqrt() const -> FloatVec4 + { + return FloatVec4(hn::Sqrt(m_data)); + } -auto FloatVec4::rsqrt() const -> FloatVec4 { - return FloatVec4(hn::ApproximateReciprocalSqrt(m_data)); -} + auto FloatVec4::rsqrt() const -> FloatVec4 + { + return FloatVec4(hn::ApproximateReciprocalSqrt(m_data)); + } -auto FloatVec4::abs() const -> FloatVec4 { return FloatVec4(hn::Abs(m_data)); } + auto FloatVec4::abs() const -> FloatVec4 + { + return FloatVec4(hn::Abs(m_data)); + } -auto FloatVec4::dot(Ref other) const -> f32 { - const Tag d; - const hn::Vec v_mul = hn::Mul(m_data, other.m_data); - return hn::ReduceSum(d, v_mul); -} + auto FloatVec4::dot(Ref other) const -> f32 + { + const Tag d; + const hn::Vec v_mul = hn::Mul(m_data, other.m_data); + return hn::ReduceSum(d, v_mul); + } -auto FloatVec4::normalize() const -> FloatVec4 { - const Tag d; - const hn::Vec v_mul = hn::Mul(m_data, m_data); - const hn::Vec v_len_sq = hn::SumOfLanes(d, v_mul); - const hn::Vec v_inv_len = hn::ApproximateReciprocalSqrt(v_len_sq); - return FloatVec4(hn::Mul(m_data, v_inv_len)); -} + auto FloatVec4::normalize() const -> FloatVec4 + { + const Tag d; + const hn::Vec v_mul = hn::Mul(m_data, m_data); + const hn::Vec v_len_sq = hn::SumOfLanes(d, v_mul); + const hn::Vec v_inv_len = hn::ApproximateReciprocalSqrt(v_len_sq); + return FloatVec4(hn::Mul(m_data, v_inv_len)); + } -auto FloatVec4::store(Mut values) -> void { - const Tag d; - hn::Store(m_data, d, values); -} + auto FloatVec4::store(Mut values) -> void + { + const Tag d; + hn::Store(m_data, d, values); + } -auto FloatVec4::load(const f32 *values) -> FloatVec4 { - const Tag d; - return FloatVec4(hn::Load(d, values)); -} + auto FloatVec4::load(const f32 *values) -> FloatVec4 + { + const Tag d; + return FloatVec4(hn::Load(d, values)); + } } // namespace IACore \ No newline at end of file diff --git a/Src/IACore/inc/IACore/SocketOps.hpp b/Src/IACore/inc/IACore/SocketOps.hpp index b636a54..4d35b9c 100644 --- a/Src/IACore/inc/IACore/SocketOps.hpp +++ b/Src/IACore/inc/IACore/SocketOps.hpp @@ -18,99 +18,109 @@ #include #if IA_PLATFORM_WINDOWS -#include -#include -#include -#pragma comment(lib, "ws2_32.lib") +# include +# include +# include +# pragma comment(lib, "ws2_32.lib") #elif IA_PLATFORM_UNIX -#include -#include -#include -#include -#ifndef INVALID_SOCKET -#define INVALID_SOCKET -1 -#endif +# include +# include +# include +# include +# ifndef INVALID_SOCKET +# define INVALID_SOCKET -1 +# endif #else -#error "IACore SocketOps is not supported on this platform." +# error "IACore SocketOps is not supported on this platform." #endif -namespace IACore { +namespace IACore +{ #if IA_PLATFORM_WINDOWS -using SocketHandle = SOCKET; + using SocketHandle = SOCKET; #elif IA_PLATFORM_UNIX -using SocketHandle = i32; + using SocketHandle = i32; #endif -class SocketOps { + class SocketOps + { public: - // SocketOps correctly handles multiple calls to initialize and terminate. - // Make sure every initialize call is paired with a corresponding terminate - // call. - static auto initialize() -> Result { - s_init_count++; - if (s_init_count > 1) { + // SocketOps correctly handles multiple calls to initialize and terminate. + // Make sure every initialize call is paired with a corresponding terminate + // call. + static auto initialize() -> Result + { + s_init_count++; + if (s_init_count > 1) + { + return {}; + } +#if IA_PLATFORM_WINDOWS + Mut wsa_data; + const i32 res = WSAStartup(MAKEWORD(2, 2), &wsa_data); + if (res != 0) + { + s_init_count--; + return fail("WSAStartup failed with error: {}", res); + } +#endif return {}; } -#if IA_PLATFORM_WINDOWS - Mut wsa_data; - const i32 res = WSAStartup(MAKEWORD(2, 2), &wsa_data); - if (res != 0) { + + // SocketOps correctly handles multiple calls to initialize and terminate. + // Make sure every initialize call is paired with a corresponding terminate + // call. + static auto terminate() -> void + { s_init_count--; - return fail("WSAStartup failed with error: {}", res); - } -#endif - return {}; - } - - // SocketOps correctly handles multiple calls to initialize and terminate. - // Make sure every initialize call is paired with a corresponding terminate - // call. - static auto terminate() -> void { - s_init_count--; - if (s_init_count > 0) { - return; - } + if (s_init_count > 0) + { + return; + } #if IA_PLATFORM_WINDOWS - WSACleanup(); + WSACleanup(); #endif - } + } - static auto is_initialized() -> bool { return s_init_count > 0; } + static auto is_initialized() -> bool + { + return s_init_count > 0; + } - static auto is_port_available_tcp(const u16 port) -> bool { - return is_port_available(port, SOCK_STREAM); - } + static auto is_port_available_tcp(const u16 port) -> bool + { + return is_port_available(port, SOCK_STREAM); + } - static auto is_port_available_udp(const u16 port) -> bool { - return is_port_available(port, SOCK_DGRAM); - } + static auto is_port_available_udp(const u16 port) -> bool + { + return is_port_available(port, SOCK_DGRAM); + } - static auto is_would_block() -> bool; + static auto is_would_block() -> bool; - static auto close(const SocketHandle sock) -> void; + static auto close(const SocketHandle sock) -> void; - static auto listen(const SocketHandle sock, const i32 queue_size = 5) - -> Result; + static auto listen(const SocketHandle sock, const i32 queue_size = 5) -> Result; - static auto create_unix_socket() -> Result; + static auto create_unix_socket() -> Result; - static auto bind_unix_socket(const SocketHandle sock, const char *path) - -> Result; - static auto connect_unix_socket(const SocketHandle sock, const char *path) - -> Result; + static auto bind_unix_socket(const SocketHandle sock, const char *path) -> Result; + static auto connect_unix_socket(const SocketHandle sock, const char *path) -> Result; - static auto unlink_file(const char *path) -> void { + static auto unlink_file(const char *path) -> void + { #if IA_PLATFORM_WINDOWS - DeleteFileA(path); + DeleteFileA(path); #elif IA_PLATFORM_UNIX - unlink(path); + unlink(path); #endif - } + } private: - static auto is_port_available(const u16 port, const i32 type) -> bool; + static auto is_port_available(const u16 port, const i32 type) -> bool; private: - static Mut s_init_count; -}; + static Mut s_init_count; + }; } // namespace IACore \ No newline at end of file diff --git a/Src/IACore/inc/IACore/StreamReader.hpp b/Src/IACore/inc/IACore/StreamReader.hpp index b57bfea..2448959 100644 --- a/Src/IACore/inc/IACore/StreamReader.hpp +++ b/Src/IACore/inc/IACore/StreamReader.hpp @@ -19,88 +19,105 @@ #include #include -namespace IACore { -class StreamReader { +namespace IACore +{ + class StreamReader + { public: - enum class StorageType { - NonOwning, - OwningMmap, - OwningVector, - }; + enum class StorageType + { + NonOwning, + OwningMmap, + OwningVector, + }; - static auto create_from_file(Ref path) -> Result; + static auto create_from_file(Ref path) -> Result; - explicit StreamReader(ForwardRef> data); - explicit StreamReader(const Span data); - ~StreamReader(); + explicit StreamReader(ForwardRef> data); + explicit StreamReader(const Span data); + ~StreamReader(); - StreamReader(ForwardRef other); - auto operator=(ForwardRef other) -> MutRef; + StreamReader(ForwardRef other); + auto operator=(ForwardRef other) -> MutRef; - StreamReader(Ref) = delete; - auto operator=(Ref) -> MutRef = delete; + StreamReader(Ref) = delete; + auto operator=(Ref) -> MutRef = delete; - auto read(Mut buffer, const usize size) -> Result; + auto read(Mut buffer, const usize size) -> Result; - template - [[nodiscard("Check for EOF")]] - auto read() -> Result; + template + [[nodiscard("Check for EOF")]] + auto read() -> Result; - auto skip(const usize amount) -> void { - m_cursor = std::min(m_cursor + amount, m_data_size); - } + auto skip(const usize amount) -> void + { + m_cursor = std::min(m_cursor + amount, m_data_size); + } - auto seek(const usize pos) -> void { - m_cursor = (pos > m_data_size) ? m_data_size : pos; - } + auto seek(const usize pos) -> void + { + m_cursor = (pos > m_data_size) ? m_data_size : pos; + } - [[nodiscard]] auto cursor() const -> usize { return m_cursor; } + [[nodiscard]] auto cursor() const -> usize + { + return m_cursor; + } - [[nodiscard]] auto size() const -> usize { return m_data_size; } + [[nodiscard]] auto size() const -> usize + { + return m_data_size; + } - [[nodiscard]] auto remaining() const -> usize { - return m_data_size - m_cursor; - } + [[nodiscard]] auto remaining() const -> usize + { + return m_data_size - m_cursor; + } - [[nodiscard]] auto is_eof() const -> bool { return m_cursor >= m_data_size; } + [[nodiscard]] auto is_eof() const -> bool + { + return m_cursor >= m_data_size; + } private: - Mut m_data = nullptr; - Mut m_cursor = 0; - Mut m_data_size = 0; - Mut> m_owning_vector; - Mut m_storage_type = StorageType::NonOwning; -}; + Mut m_data = nullptr; + Mut m_cursor = 0; + Mut m_data_size = 0; + Mut> m_owning_vector; + Mut m_storage_type = StorageType::NonOwning; + }; -inline auto StreamReader::read(Mut buffer, const usize size) - -> Result { - if (m_cursor + size > m_data_size) [[unlikely]] { - return fail("Unexpected EOF while reading"); + inline auto StreamReader::read(Mut buffer, const usize size) -> Result + { + if (m_cursor + size > m_data_size) [[unlikely]] + { + return fail("Unexpected EOF while reading"); + } + + std::memcpy(buffer, &m_data[m_cursor], size); + m_cursor += size; + + return {}; } - std::memcpy(buffer, &m_data[m_cursor], size); - m_cursor += size; + template + [[nodiscard("Check for EOF")]] + inline auto StreamReader::read() -> Result + { + static_assert(std::is_trivially_copyable_v, "T must be trivially copyable to read via memcpy"); - return {}; -} + constexpr const usize SIZE = sizeof(T); -template -[[nodiscard("Check for EOF")]] -inline auto StreamReader::read() -> Result { - static_assert(std::is_trivially_copyable_v, - "T must be trivially copyable to read via memcpy"); + if (m_cursor + SIZE > m_data_size) [[unlikely]] + { + return fail("Unexpected EOF while reading"); + } - constexpr const usize SIZE = sizeof(T); + Mut value; + std::memcpy(&value, &m_data[m_cursor], SIZE); + m_cursor += SIZE; - if (m_cursor + SIZE > m_data_size) [[unlikely]] { - return fail("Unexpected EOF while reading"); + return value; } - Mut value; - std::memcpy(&value, &m_data[m_cursor], SIZE); - m_cursor += SIZE; - - return value; -} - } // namespace IACore \ No newline at end of file diff --git a/Src/IACore/inc/IACore/StreamWriter.hpp b/Src/IACore/inc/IACore/StreamWriter.hpp index 6c3d3d2..139df58 100644 --- a/Src/IACore/inc/IACore/StreamWriter.hpp +++ b/Src/IACore/inc/IACore/StreamWriter.hpp @@ -17,55 +17,64 @@ #include -namespace IACore { +namespace IACore +{ -class StreamWriter { + class StreamWriter + { public: - enum class StorageType { - NonOwning, - OwningFile, - OwningVector, + enum class StorageType + { + NonOwning, + OwningFile, + OwningVector, + }; + + static auto create_from_file(Ref path) -> Result; + + StreamWriter(); + explicit StreamWriter(const Span data); + + StreamWriter(ForwardRef other); + auto operator=(ForwardRef other) -> MutRef; + + StreamWriter(Ref) = delete; + auto operator=(Ref) -> MutRef = delete; + + ~StreamWriter(); + + auto write(const u8 byte, const usize count) -> Result; + auto write(const void *buffer, const usize size) -> Result; + + template auto write(Ref value) -> Result; + + [[nodiscard]] auto data() const -> const u8 * + { + return m_buffer; + } + + [[nodiscard]] auto cursor() const -> usize + { + return m_cursor; + } + + auto flush() -> Result; + +private: + Mut m_buffer = nullptr; + Mut m_cursor = 0; + Mut m_capacity = 0; + Mut m_file_path; + Mut> m_owning_vector; + Mut m_storage_type = StorageType::OwningVector; + +private: + auto flush_to_disk() -> Result; }; - static auto create_from_file(Ref path) -> Result; - - StreamWriter(); - explicit StreamWriter(const Span data); - - StreamWriter(ForwardRef other); - auto operator=(ForwardRef other) -> MutRef; - - StreamWriter(Ref) = delete; - auto operator=(Ref) -> MutRef = delete; - - ~StreamWriter(); - - auto write(const u8 byte, const usize count) -> Result; - auto write(const void *buffer, const usize size) -> Result; - - template auto write(Ref value) -> Result; - - [[nodiscard]] auto data() const -> const u8 * { return m_buffer; } - - [[nodiscard]] auto cursor() const -> usize { return m_cursor; } - - auto flush() -> Result; - -private: - Mut m_buffer = nullptr; - Mut m_cursor = 0; - Mut m_capacity = 0; - Mut m_file_path; - Mut> m_owning_vector; - Mut m_storage_type = StorageType::OwningVector; - -private: - auto flush_to_disk() -> Result; -}; - -template -inline auto StreamWriter::write(Ref value) -> Result { - return write(&value, sizeof(T)); -} + template inline auto StreamWriter::write(Ref value) -> Result + { + return write(&value, sizeof(T)); + } } // namespace IACore \ No newline at end of file diff --git a/Src/IACore/inc/IACore/StringOps.hpp b/Src/IACore/inc/IACore/StringOps.hpp index cdd3593..600dfd7 100644 --- a/Src/IACore/inc/IACore/StringOps.hpp +++ b/Src/IACore/inc/IACore/StringOps.hpp @@ -17,10 +17,12 @@ #include -namespace IACore { -class StringOps { +namespace IACore +{ + class StringOps + { public: - static auto encode_base64(const Span data) -> String; - static auto decode_base64(Ref data) -> Vec; -}; + static auto encode_base64(const Span data) -> String; + static auto decode_base64(Ref data) -> Vec; + }; } // namespace IACore \ No newline at end of file diff --git a/Src/IACore/inc/IACore/Utils.hpp b/Src/IACore/inc/IACore/Utils.hpp index ba551b6..add3d58 100644 --- a/Src/IACore/inc/IACore/Utils.hpp +++ b/Src/IACore/inc/IACore/Utils.hpp @@ -19,73 +19,78 @@ #include -namespace IACore { -class Utils { +namespace IACore +{ + class Utils + { public: - static auto get_unix_time() -> u64; + static auto get_unix_time() -> u64; - static auto get_ticks_count() -> u64; + static auto get_ticks_count() -> u64; - static auto get_seconds_count() -> f64; + static auto get_seconds_count() -> f64; - static auto get_random() -> f32; - static auto get_random(const u64 max) -> u64; - static auto get_random(const i64 min, const i64 max) -> i64; + static auto get_random() -> f32; + static auto get_random(const u64 max) -> u64; + static auto get_random(const i64 min, const i64 max) -> i64; - static auto sleep(const u64 milliseconds) -> void; + static auto sleep(const u64 milliseconds) -> void; - static auto binary_to_hex_string(const Span data) -> String; + static auto binary_to_hex_string(const Span data) -> String; - static auto hex_string_to_binary(const StringView hex) -> Result>; + static auto hex_string_to_binary(const StringView hex) -> Result>; - template - inline static auto sort(ForwardRef range) -> void { - std::ranges::sort(std::forward(range)); - } - - template - inline static auto binary_search_left(ForwardRef range, Ref value) - -> auto { - return std::ranges::lower_bound(std::forward(range), value); - } - - template - inline static auto binary_search_right(ForwardRef range, Ref value) - -> auto { - return std::ranges::upper_bound(std::forward(range), value); - } - - template - inline static auto hash_combine(MutRef seed, Ref v) -> void { - Mut h = 0; - - if constexpr (std::is_constructible_v) { - const StringView sv(v); - const ankerl::unordered_dense::hash hasher; - h = hasher(sv); - } else { - const ankerl::unordered_dense::hash hasher; - h = hasher(v); + template inline static auto sort(ForwardRef range) -> void + { + std::ranges::sort(std::forward(range)); } - seed ^= h + 0x9e3779b97f4a7c15 + (seed << 6) + (seed >> 2); - } + template + inline static auto binary_search_left(ForwardRef range, Ref value) -> auto + { + return std::ranges::lower_bound(std::forward(range), value); + } - template - inline static auto compute_hash(Ref... args) -> u64 { - Mut seed = 0; - (hash_combine(seed, args), ...); - return seed; - } + template + inline static auto binary_search_right(ForwardRef range, Ref value) -> auto + { + return std::ranges::upper_bound(std::forward(range), value); + } - template - inline static auto compute_hash_flat(Ref obj, const MemberPtrs... members) - -> u64 { - Mut seed = 0; - (hash_combine(seed, obj.*members), ...); - return seed; - } -}; + template inline static auto hash_combine(MutRef seed, Ref v) -> void + { + Mut h = 0; + + if constexpr (std::is_constructible_v) + { + const StringView sv(v); + const ankerl::unordered_dense::hash hasher; + h = hasher(sv); + } + else + { + const ankerl::unordered_dense::hash hasher; + h = hasher(v); + } + + seed ^= h + 0x9e3779b97f4a7c15 + (seed << 6) + (seed >> 2); + } + + template inline static auto compute_hash(Ref... args) -> u64 + { + Mut seed = 0; + (hash_combine(seed, args), ...); + return seed; + } + + template + inline static auto compute_hash_flat(Ref obj, const MemberPtrs... members) -> u64 + { + Mut seed = 0; + (hash_combine(seed, obj.*members), ...); + return seed; + } + }; } // namespace IACore // ----------------------------------------------------------------------------- @@ -97,11 +102,13 @@ public: // 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 { \ - using is_avalanching = void; \ - IA_NODISCARD \ - auto operator()(IACore::Ref v) const noexcept -> IACore::u64 { \ - return IACore::Utils::compute_hash_flat(v, __VA_ARGS__); \ - } \ +#define IA_MAKE_HASHABLE(Type, ...) \ + template<> struct ankerl::unordered_dense::hash \ + { \ + using is_avalanching = void; \ + IA_NODISCARD \ + auto operator()(IACore::Ref v) const noexcept -> IACore::u64 \ + { \ + return IACore::Utils::compute_hash_flat(v, __VA_ARGS__); \ + } \ }; \ No newline at end of file diff --git a/Src/IACore/inc/IACore/XML.hpp b/Src/IACore/inc/IACore/XML.hpp index 0226430..7b0aba8 100644 --- a/Src/IACore/inc/IACore/XML.hpp +++ b/Src/IACore/inc/IACore/XML.hpp @@ -19,21 +19,21 @@ #include -namespace IACore { -class XML { +namespace IACore +{ + class XML + { public: - using Node = pugi::xml_node; - using Document = pugi::xml_document; + using Node = pugi::xml_node; + using Document = pugi::xml_document; public: - static auto parse_from_string(Ref data) -> Result; - static auto parse_from_file(Ref path) -> Result; + static auto parse_from_string(Ref data) -> Result; + static auto parse_from_file(Ref path) -> Result; - static auto serialize_to_string(Ref node, const bool escape = false) - -> String; - static auto serialize_to_string(Ref doc, const bool escape = false) - -> String; + static auto serialize_to_string(Ref node, const bool escape = false) -> String; + static auto serialize_to_string(Ref doc, const bool escape = false) -> String; - static auto escape_xml_string(Ref xml) -> String; -}; + static auto escape_xml_string(Ref xml) -> String; + }; } // namespace IACore \ No newline at end of file diff --git a/Tests/Subjects/LongProcess/Main.cpp b/Tests/Subjects/LongProcess/Main.cpp index 803803b..bbe1f62 100644 --- a/Tests/Subjects/LongProcess/Main.cpp +++ b/Tests/Subjects/LongProcess/Main.cpp @@ -3,10 +3,10 @@ int main(int, char **) { - std::cout << "Started!\n"; - std::cout.flush(); - std::this_thread::sleep_for(std::chrono::seconds(5)); - std::cout << "Ended!\n"; - std::cout.flush(); - return 100; + std::cout << "Started!\n"; + std::cout.flush(); + std::this_thread::sleep_for(std::chrono::seconds(5)); + std::cout << "Ended!\n"; + std::cout.flush(); + return 100; } \ No newline at end of file diff --git a/Tests/Unit/AsyncOps.cpp b/Tests/Unit/AsyncOps.cpp index 66c1b56..71c8cb3 100644 --- a/Tests/Unit/AsyncOps.cpp +++ b/Tests/Unit/AsyncOps.cpp @@ -20,18 +20,24 @@ using namespace IACore; -struct SchedulerGuard { - SchedulerGuard(u8 worker_count = 2) { +struct SchedulerGuard +{ + SchedulerGuard(u8 worker_count = 2) + { - (void)AsyncOps::initialize_scheduler(worker_count); + (void) AsyncOps::initialize_scheduler(worker_count); } - ~SchedulerGuard() { AsyncOps::terminate_scheduler(); } + ~SchedulerGuard() + { + AsyncOps::terminate_scheduler(); + } }; IAT_BEGIN_BLOCK(Core, AsyncOps) -auto test_initialization() -> bool { +auto test_initialization() -> bool +{ AsyncOps::terminate_scheduler(); @@ -50,14 +56,14 @@ auto test_initialization() -> bool { return true; } -auto test_basic_execution() -> bool { +auto test_basic_execution() -> bool +{ SchedulerGuard guard(2); AsyncOps::Schedule schedule; std::atomic run_count{0}; - AsyncOps::schedule_task([&](AsyncOps::WorkerId) { run_count++; }, 0, - &schedule); + AsyncOps::schedule_task([&](AsyncOps::WorkerId) { run_count++; }, 0, &schedule); AsyncOps::wait_for_schedule_completion(&schedule); @@ -66,14 +72,16 @@ auto test_basic_execution() -> bool { return true; } -auto test_concurrency() -> bool { +auto test_concurrency() -> bool +{ SchedulerGuard guard(4); AsyncOps::Schedule schedule; std::atomic run_count{0}; const i32 total_tasks = 100; - for (i32 i = 0; i < total_tasks; ++i) { + for (i32 i = 0; i < total_tasks; ++i) + { AsyncOps::schedule_task( [&](AsyncOps::WorkerId) { std::this_thread::sleep_for(std::chrono::microseconds(10)); @@ -89,17 +97,16 @@ auto test_concurrency() -> bool { return true; } -auto test_priorities() -> bool { +auto test_priorities() -> bool +{ SchedulerGuard guard(2); AsyncOps::Schedule schedule; std::atomic high_priority_ran{0}; std::atomic normal_priority_ran{0}; - AsyncOps::schedule_task([&](AsyncOps::WorkerId) { high_priority_ran++; }, 0, - &schedule, AsyncOps::Priority::High); + AsyncOps::schedule_task([&](AsyncOps::WorkerId) { high_priority_ran++; }, 0, &schedule, AsyncOps::Priority::High); - AsyncOps::schedule_task([&](AsyncOps::WorkerId) { normal_priority_ran++; }, 0, - &schedule, AsyncOps::Priority::Normal); + AsyncOps::schedule_task([&](AsyncOps::WorkerId) { normal_priority_ran++; }, 0, &schedule, AsyncOps::Priority::Normal); AsyncOps::wait_for_schedule_completion(&schedule); @@ -109,14 +116,16 @@ auto test_priorities() -> bool { return true; } -auto test_run_task_fire_and_forget() -> bool { +auto test_run_task_fire_and_forget() -> bool +{ SchedulerGuard guard(2); std::atomic executed{false}; AsyncOps::run_task([&]() { executed = true; }); - for (int i = 0; i < 100; ++i) { + for (int i = 0; i < 100; ++i) + { if (executed.load()) break; std::this_thread::sleep_for(std::chrono::milliseconds(10)); @@ -127,7 +136,8 @@ auto test_run_task_fire_and_forget() -> bool { return true; } -auto test_cancellation_safety() -> bool { +auto test_cancellation_safety() -> bool +{ SchedulerGuard guard(2); AsyncOps::cancel_tasks_of_tag(999); @@ -135,8 +145,7 @@ auto test_cancellation_safety() -> bool { AsyncOps::Schedule schedule; std::atomic counter{0}; - AsyncOps::schedule_task([&](AsyncOps::WorkerId) { counter++; }, 10, - &schedule); + AsyncOps::schedule_task([&](AsyncOps::WorkerId) { counter++; }, 10, &schedule); AsyncOps::wait_for_schedule_completion(&schedule); IAT_CHECK_EQ(counter.load(), 1); diff --git a/Tests/Unit/CLI.cpp b/Tests/Unit/CLI.cpp index 998f508..33d98e6 100644 --- a/Tests/Unit/CLI.cpp +++ b/Tests/Unit/CLI.cpp @@ -20,7 +20,8 @@ using namespace IACore; IAT_BEGIN_BLOCK(Core, CLI) -auto test_basic_traversal() -> bool { +auto test_basic_traversal() -> bool +{ const Vec args = {"ignored", "one", "two", "three"}; CLIParser parser(args); @@ -41,7 +42,8 @@ auto test_basic_traversal() -> bool { return true; } -auto test_peek() -> bool { +auto test_peek() -> bool +{ const Vec args = {"ignored", "peek_val", "next_val"}; CLIParser parser(args); @@ -58,7 +60,8 @@ auto test_peek() -> bool { return true; } -auto test_consume() -> bool { +auto test_consume() -> bool +{ const Vec args = {"ignored", "-v", "--output", "file.txt"}; CLIParser parser(args); @@ -79,7 +82,8 @@ auto test_consume() -> bool { return true; } -auto test_empty() -> bool { +auto test_empty() -> bool +{ const Vec args = {}; CLIParser parser(args); diff --git a/Tests/Unit/CMakeLists.txt b/Tests/Unit/CMakeLists.txt index 1727f18..6797485 100644 --- a/Tests/Unit/CMakeLists.txt +++ b/Tests/Unit/CMakeLists.txt @@ -24,7 +24,11 @@ set(TEST_SOURCES add_executable(IACore_Test_Suite ${TEST_SOURCES}) -target_compile_options(IACore_Test_Suite PRIVATE -fexceptions) +if(MSVC) + target_compile_options(IACore_Test_Suite PRIVATE "/EHsc") +else() + target_compile_options(IACore_Test_Suite PRIVATE "-fexceptions") +endif() set_target_properties(IACore_Test_Suite PROPERTIES USE_EXCEPTIONS ON) target_link_libraries(IACore_Test_Suite PRIVATE IACore) diff --git a/Tests/Unit/DataOps.cpp b/Tests/Unit/DataOps.cpp index 8236b7c..4230365 100644 --- a/Tests/Unit/DataOps.cpp +++ b/Tests/Unit/DataOps.cpp @@ -20,7 +20,8 @@ using namespace IACore; IAT_BEGIN_BLOCK(Core, DataOps) -auto test_crc32() -> bool { +auto test_crc32() -> bool +{ { const String s = "123456789"; const Span span(reinterpret_cast(s.data()), s.size()); @@ -36,20 +37,20 @@ auto test_crc32() -> bool { { Vec buffer(33); - for (usize i = 1; i < 33; ++i) { + for (usize i = 1; i < 33; ++i) + { buffer[i] = static_cast(i); } Vec ref_data(32); - for (usize i = 0; i < 32; ++i) { + for (usize i = 0; i < 32; ++i) + { ref_data[i] = static_cast(i + 1); } - const u32 hash_ref = - DataOps::crc32(Span(ref_data.data(), ref_data.size())); + const u32 hash_ref = DataOps::crc32(Span(ref_data.data(), ref_data.size())); - const u32 hash_unaligned = - DataOps::crc32(Span(buffer.data() + 1, 32)); + const u32 hash_unaligned = DataOps::crc32(Span(buffer.data() + 1, 32)); IAT_CHECK_EQ(hash_ref, hash_unaligned); } @@ -57,7 +58,8 @@ auto test_crc32() -> bool { return true; } -auto test_hash_xxhash() -> bool { +auto test_hash_xxhash() -> bool +{ { const String s = "123456789"; const u32 result = DataOps::hash_xxhash(s); @@ -73,19 +75,18 @@ auto test_hash_xxhash() -> bool { { const String s = "Test"; const u32 r1 = DataOps::hash_xxhash(s); - const u32 r2 = DataOps::hash_xxhash( - Span(reinterpret_cast(s.data()), s.size())); + const u32 r2 = DataOps::hash_xxhash(Span(reinterpret_cast(s.data()), s.size())); IAT_CHECK_EQ(r1, r2); } return true; } -auto test_hash_fnv1a() -> bool { +auto test_hash_fnv1a() -> bool +{ { const String s = "123456789"; - const u32 result = DataOps::hash_fnv1a( - Span(reinterpret_cast(s.data()), s.size())); + const u32 result = DataOps::hash_fnv1a(Span(reinterpret_cast(s.data()), s.size())); IAT_CHECK_EQ(result, 0xbb86b11c); } diff --git a/Tests/Unit/Environment.cpp b/Tests/Unit/Environment.cpp index 9c5dc5b..adb609d 100644 --- a/Tests/Unit/Environment.cpp +++ b/Tests/Unit/Environment.cpp @@ -23,9 +23,10 @@ static constexpr const char *TEST_VAL = "Hello World"; IAT_BEGIN_BLOCK(Core, Environment) -auto test_basic_cycle() -> bool { +auto test_basic_cycle() -> bool +{ - (void)Environment::unset(TEST_KEY); + (void) Environment::unset(TEST_KEY); IAT_CHECK_NOT(Environment::exists(TEST_KEY)); const auto set_res = Environment::set(TEST_KEY, TEST_VAL); @@ -39,23 +40,25 @@ auto test_basic_cycle() -> bool { const String val = Environment::get(TEST_KEY); IAT_CHECK_EQ(val, String(TEST_VAL)); - (void)Environment::unset(TEST_KEY); + (void) Environment::unset(TEST_KEY); return true; } -auto test_overwrite() -> bool { - (void)Environment::set(TEST_KEY, "ValueA"); +auto test_overwrite() -> bool +{ + (void) Environment::set(TEST_KEY, "ValueA"); IAT_CHECK_EQ(Environment::get(TEST_KEY), String("ValueA")); - (void)Environment::set(TEST_KEY, "ValueB"); + (void) Environment::set(TEST_KEY, "ValueB"); IAT_CHECK_EQ(Environment::get(TEST_KEY), String("ValueB")); - (void)Environment::unset(TEST_KEY); + (void) Environment::unset(TEST_KEY); return true; } -auto test_unset() -> bool { - (void)Environment::set(TEST_KEY, "To Be Deleted"); +auto test_unset() -> bool +{ + (void) Environment::set(TEST_KEY, "To Be Deleted"); IAT_CHECK(Environment::exists(TEST_KEY)); const auto unset_res = Environment::unset(TEST_KEY); @@ -69,10 +72,11 @@ auto test_unset() -> bool { return true; } -auto test_defaults() -> bool { +auto test_defaults() -> bool +{ const char *ghost_key = "IA_THIS_KEY_DOES_NOT_EXIST"; - (void)Environment::unset(ghost_key); + (void) Environment::unset(ghost_key); const String empty = Environment::get(ghost_key); IAT_CHECK(empty.empty()); @@ -83,8 +87,9 @@ auto test_defaults() -> bool { return true; } -auto test_empty_value() -> bool { - (void)Environment::set(TEST_KEY, ""); +auto test_empty_value() -> bool +{ + (void) Environment::set(TEST_KEY, ""); #if IA_PLATFORM_WINDOWS @@ -96,13 +101,14 @@ auto test_empty_value() -> bool { IAT_CHECK(opt->empty()); #endif - (void)Environment::unset(TEST_KEY); + (void) Environment::unset(TEST_KEY); IAT_CHECK_NOT(Environment::exists(TEST_KEY)); return true; } -auto test_bad_input() -> bool { +auto test_bad_input() -> bool +{ const auto res = Environment::set("", "Value"); IAT_CHECK_NOT(res.has_value()); diff --git a/Tests/Unit/FileOps.cpp b/Tests/Unit/FileOps.cpp index 1ff3ae5..d35bad0 100644 --- a/Tests/Unit/FileOps.cpp +++ b/Tests/Unit/FileOps.cpp @@ -20,14 +20,17 @@ using namespace IACore; IAT_BEGIN_BLOCK(Core, FileOps) -void cleanup_file(const Path &path) { +void cleanup_file(const Path &path) +{ std::error_code ec; - if (std::filesystem::exists(path, ec)) { + if (std::filesystem::exists(path, ec)) + { std::filesystem::remove(path, ec); } } -auto test_text_io() -> bool { +auto test_text_io() -> bool +{ const Path path = "iatest_fileops_text.txt"; const String content = "Hello IACore FileOps!\nLine 2"; @@ -43,7 +46,8 @@ auto test_text_io() -> bool { return true; } -auto test_binary_io() -> bool { +auto test_binary_io() -> bool +{ const Path path = "iatest_fileops_bin.bin"; const Vec content = {0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0xFF}; @@ -55,7 +59,8 @@ auto test_binary_io() -> bool { IAT_CHECK(read_res.has_value()); IAT_CHECK_EQ(read_res->size(), content.size()); - for (usize i = 0; i < content.size(); ++i) { + for (usize i = 0; i < content.size(); ++i) + { IAT_CHECK_EQ((*read_res)[i], content[i]); } @@ -63,11 +68,12 @@ auto test_binary_io() -> bool { return true; } -auto test_file_mapping() -> bool { +auto test_file_mapping() -> bool +{ const Path path = "iatest_fileops_map.txt"; const String content = "MappedContent"; - (void)FileOps::write_text_file(path, content, true); + (void) FileOps::write_text_file(path, content, true); usize size = 0; const auto map_res = FileOps::map_file(path, size); @@ -86,7 +92,8 @@ auto test_file_mapping() -> bool { return true; } -auto test_shared_memory() -> bool { +auto test_shared_memory() -> bool +{ const String shm_name = "iatest_shm_block"; const usize shm_size = 4096; @@ -112,7 +119,8 @@ auto test_shared_memory() -> bool { return true; } -auto test_stream_integration() -> bool { +auto test_stream_integration() -> bool +{ const Path path = "iatest_fileops_stream.bin"; cleanup_file(path); @@ -121,8 +129,8 @@ auto test_stream_integration() -> bool { IAT_CHECK(writer_res.has_value()); auto &writer = *writer_res; - (void)writer.write(0x12345678); - (void)writer.write(0xFF); + (void) writer.write(0x12345678); + (void) writer.write(0xFF); } { diff --git a/Tests/Unit/IPC.cpp b/Tests/Unit/IPC.cpp index 1cad067..882405f 100644 --- a/Tests/Unit/IPC.cpp +++ b/Tests/Unit/IPC.cpp @@ -21,27 +21,26 @@ using namespace IACore; IAT_BEGIN_BLOCK(Core, IPC) -auto test_layout_constraints() -> bool { +auto test_layout_constraints() -> bool +{ IAT_CHECK_EQ(alignof(IpcSharedMemoryLayout), static_cast(64)); IAT_CHECK_EQ(offsetof(IpcSharedMemoryLayout, meta), static_cast(0)); - IAT_CHECK_EQ(offsetof(IpcSharedMemoryLayout, moni_control), - static_cast(64)); + IAT_CHECK_EQ(offsetof(IpcSharedMemoryLayout, moni_control), static_cast(64)); - IAT_CHECK_EQ(offsetof(IpcSharedMemoryLayout, mino_control), - static_cast(192)); + IAT_CHECK_EQ(offsetof(IpcSharedMemoryLayout, mino_control), static_cast(192)); - IAT_CHECK_EQ(offsetof(IpcSharedMemoryLayout, moni_data_offset), - static_cast(320)); + IAT_CHECK_EQ(offsetof(IpcSharedMemoryLayout, moni_data_offset), static_cast(320)); IAT_CHECK_EQ(sizeof(IpcSharedMemoryLayout) % 64, static_cast(0)); return true; } -auto test_manual_shm_ringbuffer() -> bool { +auto test_manual_shm_ringbuffer() -> bool +{ const String shm_name = "IA_TEST_IPC_LAYOUT_CHECK"; const usize shm_size = 16 * 1024; @@ -67,28 +66,20 @@ auto test_manual_shm_ringbuffer() -> bool { layout->mino_data_offset = header_size + half_data; layout->mino_data_size = half_data; - Span moni_data_span(base_ptr + layout->moni_data_offset, - static_cast(layout->moni_data_size)); - auto moni_res = - RingBufferView::create(&layout->moni_control, moni_data_span, true); + Span moni_data_span(base_ptr + layout->moni_data_offset, static_cast(layout->moni_data_size)); + auto moni_res = RingBufferView::create(&layout->moni_control, moni_data_span, true); IAT_CHECK(moni_res.has_value()); auto moni = std::move(*moni_res); - Span mino_data_span(base_ptr + layout->mino_data_offset, - static_cast(layout->mino_data_size)); - auto mino_res = - RingBufferView::create(&layout->mino_control, mino_data_span, true); + Span mino_data_span(base_ptr + layout->mino_data_offset, static_cast(layout->mino_data_size)); + auto mino_res = RingBufferView::create(&layout->mino_control, mino_data_span, true); IAT_CHECK(mino_res.has_value()); auto _ = std::move(*mino_res); String msg = "IPC_TEST_MESSAGE"; - IAT_CHECK( - moni.push(100, Span(reinterpret_cast(msg.data()), - msg.size())) - .has_value()); + IAT_CHECK(moni.push(100, Span(reinterpret_cast(msg.data()), msg.size())).has_value()); - auto moni_reader_res = - RingBufferView::create(&layout->moni_control, moni_data_span, false); + auto moni_reader_res = RingBufferView::create(&layout->moni_control, moni_data_span, false); IAT_CHECK(moni_reader_res.has_value()); auto moni_reader = std::move(*moni_reader_res); @@ -99,7 +90,7 @@ auto test_manual_shm_ringbuffer() -> bool { IAT_CHECK(pop_res->has_value()); IAT_CHECK_EQ(header.id, static_cast(100)); - String received((char *)buffer, *pop_res.value()); + String received((char *) buffer, *pop_res.value()); IAT_CHECK_EQ(received, msg); FileOps::unmap_file(base_ptr); @@ -108,13 +99,20 @@ auto test_manual_shm_ringbuffer() -> bool { return true; } -class TestManager : public IpcManager { -public: - void on_signal(NativeProcessID, u8) override {} - void on_packet(NativeProcessID, u16, Span) override {} +class TestManager : public IpcManager +{ + public: + void on_signal(NativeProcessID, u8) override + { + } + + void on_packet(NativeProcessID, u16, Span) override + { + } }; -auto test_manager_instantiation() -> bool { +auto test_manager_instantiation() -> bool +{ TestManager mgr; return true; } diff --git a/Tests/Unit/JSON.cpp b/Tests/Unit/JSON.cpp index 3c1cd9b..2427a6b 100644 --- a/Tests/Unit/JSON.cpp +++ b/Tests/Unit/JSON.cpp @@ -18,21 +18,23 @@ using namespace IACore; -struct UserProfile { +struct UserProfile +{ String username; u32 id; bool is_active; Vec roles; - bool operator==(const UserProfile &other) const { - return username == other.username && id == other.id && - is_active == other.is_active && roles == other.roles; + bool operator==(const UserProfile &other) const + { + return username == other.username && id == other.id && is_active == other.is_active && roles == other.roles; } }; IAT_BEGIN_BLOCK(Core, JSON) -auto test_dynamic_parse() -> bool { +auto test_dynamic_parse() -> bool +{ const String json_text = R"({ "string": "Hello World", "int": 42, @@ -69,7 +71,8 @@ auto test_dynamic_parse() -> bool { return true; } -auto test_dynamic_encode() -> bool { +auto test_dynamic_encode() -> bool +{ nlohmann::json j; j["name"] = "IACore"; j["version"] = 2; @@ -83,18 +86,17 @@ auto test_dynamic_encode() -> bool { return true; } -auto test_parse_invalid() -> bool { +auto test_parse_invalid() -> bool +{ const String bad_json = "{ key: value }"; auto res = Json::parse(bad_json); IAT_CHECK_NOT(res.has_value()); return true; } -auto test_struct_round_trip() -> bool { - UserProfile original{.username = "test_user", - .id = 12345, - .is_active = true, - .roles = {"admin", "editor"}}; +auto test_struct_round_trip() -> bool +{ + UserProfile original{.username = "test_user", .id = 12345, .is_active = true, .roles = {"admin", "editor"}}; auto encode_res = Json::encode_struct(original); IAT_CHECK(encode_res.has_value()); @@ -112,14 +114,16 @@ auto test_struct_round_trip() -> bool { return true; } -auto test_struct_parse_error() -> bool { +auto test_struct_parse_error() -> bool +{ const String malformed = "{ broken_json: "; auto res = Json::parse_to_struct(malformed); IAT_CHECK_NOT(res.has_value()); return true; } -auto test_read_only() -> bool { +auto test_read_only() -> bool +{ const String json_text = R"({ "id": 999, "name": "Simd", diff --git a/Tests/Unit/Logger.cpp b/Tests/Unit/Logger.cpp index c1ca899..f600514 100644 --- a/Tests/Unit/Logger.cpp +++ b/Tests/Unit/Logger.cpp @@ -23,7 +23,17 @@ IAT_BEGIN_BLOCK(Core, Logger) static constexpr const char *LOG_FILE = "iacore_test_log.txt"; -auto test_file_logging() -> bool { +void cleanup_file(const Path &path) +{ + std::error_code ec; + if (std::filesystem::exists(path, ec)) + { + std::filesystem::remove(path, ec); + } +} + +auto test_file_logging() -> bool +{ const auto res = Logger::enable_logging_to_disk(LOG_FILE); IAT_CHECK(res.has_value()); @@ -41,9 +51,10 @@ auto test_file_logging() -> bool { Logger::flush_logs(); auto read_res = FileOps::read_text_file(LOG_FILE); - if (!read_res) { - std::cout << console::YELLOW << " Warning: Could not read log file (" - << read_res.error() << "). Skipping verification.\n" + if (!read_res) + { + std::cout << console::YELLOW << " Warning: Could not read log file (" << read_res.error() + << "). Skipping verification.\n" << console::RESET; return true; } @@ -58,10 +69,13 @@ auto test_file_logging() -> bool { IAT_CHECK(content.find("ERROR") != String::npos); IAT_CHECK(content.find("WARN") != String::npos); + cleanup_file(LOG_FILE); + return true; } -auto test_log_levels() -> bool { +auto test_log_levels() -> bool +{ Logger::set_log_level(Logger::LogLevel::Warn); @@ -74,7 +88,8 @@ auto test_log_levels() -> bool { Logger::flush_logs(); auto read_res = FileOps::read_text_file(LOG_FILE); - if (!read_res) { + if (!read_res) + { return true; } @@ -87,7 +102,8 @@ auto test_log_levels() -> bool { return true; } -auto test_formatting() -> bool { +auto test_formatting() -> bool +{ Logger::set_log_level(Logger::LogLevel::Info); const String name = "IACore"; @@ -97,7 +113,8 @@ auto test_formatting() -> bool { Logger::flush_logs(); auto read_res = FileOps::read_text_file(LOG_FILE); - if (!read_res) { + if (!read_res) + { return true; } diff --git a/Tests/Unit/Main.cpp b/Tests/Unit/Main.cpp index 0ba2084..1d25766 100644 --- a/Tests/Unit/Main.cpp +++ b/Tests/Unit/Main.cpp @@ -20,18 +20,15 @@ using namespace IACore; -IACORE_MAIN() { - (void)args; +IACORE_MAIN() +{ + (void) args; AU_TRY_PURE(SocketOps::initialize()); - std::cout - << console::GREEN - << "\n===============================================================\n"; + std::cout << console::GREEN << "\n===============================================================\n"; std::cout << " IACore (Independent Architecture Core) - Unit Test Suite\n"; - std::cout - << "===============================================================\n" - << console::RESET << "\n"; + std::cout << "===============================================================\n" << console::RESET << "\n"; const i32 result = Test::TestRegistry::run_all(); diff --git a/Tests/Unit/Platform.cpp b/Tests/Unit/Platform.cpp index 0379a0f..62dcaa5 100644 --- a/Tests/Unit/Platform.cpp +++ b/Tests/Unit/Platform.cpp @@ -21,7 +21,8 @@ using namespace IACore; IAT_BEGIN_BLOCK(Core, Platform) -auto test_os_name() -> bool { +auto test_os_name() -> bool +{ const char *os_name = Platform::get_operating_system_name(); IAT_CHECK(os_name != nullptr); @@ -41,7 +42,8 @@ auto test_os_name() -> bool { return true; } -auto test_arch_name() -> bool { +auto test_arch_name() -> bool +{ const char *arch_name = Platform::get_architecture_name(); IAT_CHECK(arch_name != nullptr); @@ -59,7 +61,8 @@ auto test_arch_name() -> bool { return true; } -auto test_capabilities() -> bool { +auto test_capabilities() -> bool +{ const bool check_result = Platform::check_cpu(); IAT_CHECK(check_result); @@ -67,13 +70,14 @@ auto test_capabilities() -> bool { const auto &caps = Platform::get_capabilities(); volatile bool has_crc = caps.hardware_crc32; - (void)has_crc; + (void) has_crc; return true; } #if IA_ARCH_X64 -auto test_cpuid() -> bool { +auto test_cpuid() -> bool +{ i32 regs[4] = {0}; Platform::cpuid(0, 0, regs); @@ -91,12 +95,11 @@ auto test_cpuid() -> bool { const String vendor_str(vendor); IAT_CHECK(!vendor_str.empty()); - bool is_known = - (vendor_str == "GenuineIntel" || vendor_str == "AuthenticAMD" || - vendor_str == "KVMKVMKVM" || vendor_str == "Microsoft Hv" || - vendor_str == "VBoxVBoxVBox"); + bool is_known = (vendor_str == "GenuineIntel" || vendor_str == "AuthenticAMD" || vendor_str == "KVMKVMKVM" || + vendor_str == "Microsoft Hv" || vendor_str == "VBoxVBoxVBox"); - if (!is_known) { + if (!is_known) + { std::cout << " [Info] Unknown CPU Vendor: " << vendor_str << "\n"; } diff --git a/Tests/Unit/ProcessOps.cpp b/Tests/Unit/ProcessOps.cpp index d3206a7..626af48 100644 --- a/Tests/Unit/ProcessOps.cpp +++ b/Tests/Unit/ProcessOps.cpp @@ -19,24 +19,24 @@ using namespace IACore; #if IA_PLATFORM_WINDOWS -#define CMD_ECHO_EXE "cmd.exe" -#define CMD_ARG_PREFIX "/c echo" -#define NULL_DEVICE "NUL" +# define CMD_ECHO_EXE "cmd.exe" +# define CMD_ARG_PREFIX "/c echo" +# define NULL_DEVICE "NUL" #else -#define CMD_ECHO_EXE "/bin/echo" -#define CMD_ARG_PREFIX "" -#define NULL_DEVICE "/dev/null" +# define CMD_ECHO_EXE "/bin/echo" +# define CMD_ARG_PREFIX "" +# define NULL_DEVICE "/dev/null" #endif IAT_BEGIN_BLOCK(Core, ProcessOps) -auto test_basic_run() -> bool { +auto test_basic_run() -> bool +{ String captured; - const auto result = - ProcessOps::spawn_process_sync(CMD_ECHO_EXE, CMD_ARG_PREFIX " HelloIA", - [&](StringView line) { captured = line; }); + const auto result = ProcessOps::spawn_process_sync(CMD_ECHO_EXE, CMD_ARG_PREFIX " HelloIA", + [&](StringView line) { captured = line; }); IAT_CHECK(result.has_value()); IAT_CHECK_EQ(*result, 0); @@ -46,18 +46,18 @@ auto test_basic_run() -> bool { return true; } -auto test_arguments() -> bool { +auto test_arguments() -> bool +{ Vec lines; String args = String(CMD_ARG_PREFIX) + " one two"; - if (!args.empty() && args[0] == ' ') { + if (!args.empty() && args[0] == ' ') + { args.erase(0, 1); } const auto result = - ProcessOps::spawn_process_sync(CMD_ECHO_EXE, args, [&](StringView line) { - lines.push_back(String(line)); - }); + ProcessOps::spawn_process_sync(CMD_ECHO_EXE, args, [&](StringView line) { lines.push_back(String(line)); }); IAT_CHECK_EQ(*result, 0); IAT_CHECK(lines.size() > 0); @@ -67,7 +67,8 @@ auto test_arguments() -> bool { return true; } -auto test_exit_codes() -> bool { +auto test_exit_codes() -> bool +{ String cmd; String arg; @@ -80,8 +81,7 @@ auto test_exit_codes() -> bool { arg = "-c \"exit 42\""; #endif - const auto result = - ProcessOps::spawn_process_sync(cmd, arg, [](StringView) {}); + const auto result = ProcessOps::spawn_process_sync(cmd, arg, [](StringView) {}); IAT_CHECK(result.has_value()); IAT_CHECK_EQ(*result, 42); @@ -89,10 +89,10 @@ auto test_exit_codes() -> bool { return true; } -auto test_missing_exe() -> bool { +auto test_missing_exe() -> bool +{ - const auto result = - ProcessOps::spawn_process_sync("sdflkjghsdflkjg", "", [](StringView) {}); + const auto result = ProcessOps::spawn_process_sync("sdflkjghsdflkjg", "", [](StringView) {}); #if IA_PLATFORM_WINDOWS IAT_CHECK_NOT(result.has_value()); @@ -105,11 +105,13 @@ auto test_missing_exe() -> bool { return true; } -auto test_large_output() -> bool { +auto test_large_output() -> bool +{ String massive_string; massive_string.reserve(5000); - for (i32 i = 0; i < 500; ++i) { + for (i32 i = 0; i < 500; ++i) + { massive_string += "1234567890"; } @@ -126,8 +128,7 @@ auto test_large_output() -> bool { #endif String captured; - const auto result = ProcessOps::spawn_process_sync( - cmd, arg, [&](StringView line) { captured += line; }); + const auto result = ProcessOps::spawn_process_sync(cmd, arg, [&](StringView line) { captured += line; }); IAT_CHECK(result.has_value()); IAT_CHECK_EQ(*result, 0); @@ -137,7 +138,8 @@ auto test_large_output() -> bool { return true; } -auto test_multi_line() -> bool { +auto test_multi_line() -> bool +{ String cmd; String arg; @@ -153,16 +155,17 @@ auto test_multi_line() -> bool { bool found_a = false; bool found_b = false; - const auto res = - ProcessOps::spawn_process_sync(cmd, arg, [&](StringView line) { - line_count++; - if (line.find("LineA") != String::npos) { - found_a = true; - } - if (line.find("LineB") != String::npos) { - found_b = true; - } - }); + const auto res = ProcessOps::spawn_process_sync(cmd, arg, [&](StringView line) { + line_count++; + if (line.find("LineA") != String::npos) + { + found_a = true; + } + if (line.find("LineB") != String::npos) + { + found_b = true; + } + }); IAT_CHECK(res.has_value()); IAT_CHECK(found_a); @@ -173,10 +176,10 @@ auto test_multi_line() -> bool { return true; } -auto test_complex_arguments() -> bool { +auto test_complex_arguments() -> bool +{ - const String complex_args = - "-DDEFINED_MSG=\\\"Hello World\\\" -v path/to/file"; + const String complex_args = "-DDEFINED_MSG=\\\"Hello World\\\" -v path/to/file"; const String cmd = CMD_ECHO_EXE; @@ -188,8 +191,7 @@ auto test_complex_arguments() -> bool { #endif String captured; - const auto result = ProcessOps::spawn_process_sync( - cmd, final_args, [&](StringView line) { captured += line; }); + const auto result = ProcessOps::spawn_process_sync(cmd, final_args, [&](StringView line) { captured += line; }); IAT_CHECK(result.has_value()); IAT_CHECK_EQ(*result, 0); diff --git a/Tests/Unit/RingBuffer.cpp b/Tests/Unit/RingBuffer.cpp index 698d52c..5e6edcd 100644 --- a/Tests/Unit/RingBuffer.cpp +++ b/Tests/Unit/RingBuffer.cpp @@ -20,7 +20,8 @@ using namespace IACore; IAT_BEGIN_BLOCK(Core, RingBuffer) -auto test_push_pop() -> bool { +auto test_push_pop() -> bool +{ Vec memory(sizeof(RingBufferView::ControlBlock) + 1024); @@ -33,8 +34,7 @@ auto test_push_pop() -> bool { auto consumer = std::move(*consumer_res); String msg = "Hello RingBuffer"; - const auto push_res = producer.push( - 1, Span(reinterpret_cast(msg.data()), msg.size())); + const auto push_res = producer.push(1, Span(reinterpret_cast(msg.data()), msg.size())); IAT_CHECK(push_res.has_value()); RingBufferView::PacketHeader header; @@ -57,7 +57,8 @@ auto test_push_pop() -> bool { return true; } -auto test_wrap_around() -> bool { +auto test_wrap_around() -> bool +{ Vec memory(sizeof(RingBufferView::ControlBlock) + 100); @@ -87,8 +88,10 @@ auto test_wrap_around() -> bool { IAT_CHECK_EQ(pop_size, static_cast(40)); bool match = true; - for (usize i = 0; i < 40; i++) { - if (out_buf[i] != 0xAA) { + for (usize i = 0; i < 40; i++) + { + if (out_buf[i] != 0xAA) + { match = false; } } diff --git a/Tests/Unit/SIMD/FloatVec4.cpp b/Tests/Unit/SIMD/FloatVec4.cpp index 57c7631..7419917 100644 --- a/Tests/Unit/SIMD/FloatVec4.cpp +++ b/Tests/Unit/SIMD/FloatVec4.cpp @@ -20,7 +20,8 @@ using namespace IACore; IAT_BEGIN_BLOCK(Core, FloatVec4) -auto test_float_arithmetic() -> bool { +auto test_float_arithmetic() -> bool +{ FloatVec4 v1(10.0f, 20.0f, 30.0f, 40.0f); FloatVec4 v2(2.0f, 4.0f, 5.0f, 8.0f); @@ -39,7 +40,8 @@ auto test_float_arithmetic() -> bool { return true; } -auto test_math_helpers() -> bool { +auto test_math_helpers() -> bool +{ alignas(16) f32 res[4]; FloatVec4 v_sq(4.0f, 9.0f, 16.0f, 25.0f); @@ -61,7 +63,8 @@ auto test_math_helpers() -> bool { return true; } -auto test_approx_math() -> bool { +auto test_approx_math() -> bool +{ alignas(16) f32 res[4]; FloatVec4 v(16.0f, 25.0f, 100.0f, 1.0f); @@ -73,7 +76,8 @@ auto test_approx_math() -> bool { return true; } -auto test_linear_algebra() -> bool { +auto test_linear_algebra() -> bool +{ FloatVec4 v1(1.0f, 2.0f, 3.0f, 4.0f); FloatVec4 v2(1.0f, 0.0f, 1.0f, 0.0f); diff --git a/Tests/Unit/SIMD/IntVec4.cpp b/Tests/Unit/SIMD/IntVec4.cpp index 36c6f0e..f6fec73 100644 --- a/Tests/Unit/SIMD/IntVec4.cpp +++ b/Tests/Unit/SIMD/IntVec4.cpp @@ -20,7 +20,8 @@ using namespace IACore; IAT_BEGIN_BLOCK(Core, IntVec4) -auto test_constructors() -> bool { +auto test_constructors() -> bool +{ IntVec4 v_broadcast(10); alignas(16) u32 store_buf[4]; v_broadcast.store(store_buf); @@ -41,7 +42,8 @@ auto test_constructors() -> bool { return true; } -auto test_arithmetic() -> bool { +auto test_arithmetic() -> bool +{ const IntVec4 v1(10, 20, 30, 40); const IntVec4 v2(1, 2, 3, 4); @@ -64,9 +66,10 @@ auto test_arithmetic() -> bool { return true; } -auto test_bitwise() -> bool { +auto test_bitwise() -> bool +{ const IntVec4 v_all_ones(0xFFFFFFFF); - const IntVec4 v_zero((u32)0); + const IntVec4 v_zero((u32) 0); const IntVec4 v_pattern(0xAAAAAAAA); alignas(16) u32 res[4]; @@ -94,7 +97,8 @@ auto test_bitwise() -> bool { return true; } -auto test_saturation() -> bool { +auto test_saturation() -> bool +{ const u32 max = 0xFFFFFFFF; const IntVec4 v_high(max - 10); const IntVec4 v_add(20); @@ -112,7 +116,8 @@ auto test_saturation() -> bool { return true; } -auto test_advanced_ops() -> bool { +auto test_advanced_ops() -> bool +{ const IntVec4 v(0, 50, 100, 150); alignas(16) u32 res[4]; diff --git a/Tests/Unit/SocketOps.cpp b/Tests/Unit/SocketOps.cpp index 0701b9c..d5ac4a5 100644 --- a/Tests/Unit/SocketOps.cpp +++ b/Tests/Unit/SocketOps.cpp @@ -20,7 +20,8 @@ using namespace IACore; IAT_BEGIN_BLOCK(Core, SocketOps) -auto test_initialization() -> bool { +auto test_initialization() -> bool +{ IAT_CHECK(SocketOps::is_initialized()); const auto res = SocketOps::initialize(); @@ -33,17 +34,19 @@ auto test_initialization() -> bool { return true; } -auto test_port_availability() -> bool { +auto test_port_availability() -> bool +{ const u16 port = 54321; - (void)SocketOps::is_port_available_tcp(port); - (void)SocketOps::is_port_available_udp(port); + (void) SocketOps::is_port_available_tcp(port); + (void) SocketOps::is_port_available_udp(port); return true; } -auto test_unix_socket_lifecycle() -> bool { +auto test_unix_socket_lifecycle() -> bool +{ const String socket_path = "iatest_ipc.sock"; SocketOps::unlink_file(socket_path.c_str()); @@ -53,7 +56,8 @@ auto test_unix_socket_lifecycle() -> bool { SocketHandle server = *server_res; auto bind_res = SocketOps::bind_unix_socket(server, socket_path.c_str()); - if (!bind_res) { + if (!bind_res) + { SocketOps::close(server); return false; @@ -66,8 +70,7 @@ auto test_unix_socket_lifecycle() -> bool { IAT_CHECK(client_res.has_value()); SocketHandle client = *client_res; - auto connect_res = - SocketOps::connect_unix_socket(client, socket_path.c_str()); + auto connect_res = SocketOps::connect_unix_socket(client, socket_path.c_str()); IAT_CHECK(connect_res.has_value()); SocketOps::close(client); @@ -77,7 +80,8 @@ auto test_unix_socket_lifecycle() -> bool { return true; } -auto test_unix_socket_errors() -> bool { +auto test_unix_socket_errors() -> bool +{ const String socket_path = "iatest_missing.sock"; SocketOps::unlink_file(socket_path.c_str()); @@ -86,8 +90,7 @@ auto test_unix_socket_errors() -> bool { IAT_CHECK(client_res.has_value()); SocketHandle client = *client_res; - auto connect_res = - SocketOps::connect_unix_socket(client, socket_path.c_str()); + auto connect_res = SocketOps::connect_unix_socket(client, socket_path.c_str()); IAT_CHECK_NOT(connect_res.has_value()); SocketOps::close(client); diff --git a/Tests/Unit/StreamReader.cpp b/Tests/Unit/StreamReader.cpp index 4062a98..6734afe 100644 --- a/Tests/Unit/StreamReader.cpp +++ b/Tests/Unit/StreamReader.cpp @@ -20,7 +20,8 @@ using namespace IACore; IAT_BEGIN_BLOCK(Core, StreamReader) -auto test_read_uint8() -> bool { +auto test_read_uint8() -> bool +{ u8 data[] = {0xAA, 0xBB, 0xCC}; StreamReader reader(data); @@ -36,7 +37,8 @@ auto test_read_uint8() -> bool { return true; } -auto test_read_multi_byte() -> bool { +auto test_read_multi_byte() -> bool +{ u8 data[] = {0x01, 0x02, 0x03, 0x04}; StreamReader reader(data); @@ -52,7 +54,8 @@ auto test_read_multi_byte() -> bool { return true; } -auto test_read_float() -> bool { +auto test_read_float() -> bool +{ const f32 pi = 3.14159f; u8 data[4]; @@ -67,7 +70,8 @@ auto test_read_float() -> bool { return true; } -auto test_read_buffer() -> bool { +auto test_read_buffer() -> bool +{ u8 src[] = {1, 2, 3, 4, 5}; u8 dst[3] = {0}; StreamReader reader(src); @@ -84,7 +88,8 @@ auto test_read_buffer() -> bool { return true; } -auto test_navigation() -> bool { +auto test_navigation() -> bool +{ u8 data[10] = {0}; StreamReader reader(data); @@ -106,11 +111,12 @@ auto test_navigation() -> bool { return true; } -auto test_boundary_checks() -> bool { +auto test_boundary_checks() -> bool +{ u8 data[] = {0x00, 0x00}; StreamReader reader(data); - (void)reader.read(); + (void) reader.read(); IAT_CHECK(reader.is_eof()); auto val = reader.read(); diff --git a/Tests/Unit/StreamWriter.cpp b/Tests/Unit/StreamWriter.cpp index 75547db..d3a9328 100644 --- a/Tests/Unit/StreamWriter.cpp +++ b/Tests/Unit/StreamWriter.cpp @@ -21,7 +21,8 @@ using namespace IACore; IAT_BEGIN_BLOCK(Core, StreamWriter) -auto test_memory_writer() -> bool { +auto test_memory_writer() -> bool +{ StreamWriter writer; IAT_CHECK(writer.write(static_cast(0xAA), 1).has_value()); @@ -39,7 +40,8 @@ auto test_memory_writer() -> bool { return true; } -auto test_fixed_buffer() -> bool { +auto test_fixed_buffer() -> bool +{ u8 buffer[4] = {0}; StreamWriter writer(Span(buffer, 4)); @@ -60,10 +62,12 @@ auto test_fixed_buffer() -> bool { return true; } -auto test_file_writer() -> bool { +auto test_file_writer() -> bool +{ const Path path = "test_stream_writer.bin"; - if (std::filesystem::exists(path)) { + if (std::filesystem::exists(path)) + { std::filesystem::remove(path); } @@ -81,8 +85,7 @@ auto test_file_writer() -> bool { auto read_res = FileOps::read_binary_file(path); IAT_CHECK(read_res.has_value()); - const String read_str(reinterpret_cast(read_res->data()), - read_res->size()); + const String read_str(reinterpret_cast(read_res->data()), read_res->size()); IAT_CHECK_EQ(read_str, String("Hello World")); std::filesystem::remove(path); @@ -90,7 +93,8 @@ auto test_file_writer() -> bool { return true; } -auto test_primitives() -> bool { +auto test_primitives() -> bool +{ StreamWriter writer; const f32 f = 1.5f; diff --git a/Tests/Unit/StringOps.cpp b/Tests/Unit/StringOps.cpp index 5bb222b..f0e7ea3 100644 --- a/Tests/Unit/StringOps.cpp +++ b/Tests/Unit/StringOps.cpp @@ -20,7 +20,8 @@ using namespace IACore; IAT_BEGIN_BLOCK(Core, StringOps) -auto test_base64_encode() -> bool { +auto test_base64_encode() -> bool +{ { const String s = "Hello World"; @@ -58,13 +59,13 @@ auto test_base64_encode() -> bool { return true; } -auto test_base64_decode() -> bool { +auto test_base64_decode() -> bool +{ { const String encoded = "SGVsbG8gV29ybGQ="; const Vec decoded = StringOps::decode_base64(encoded); - const String result(reinterpret_cast(decoded.data()), - decoded.size()); + const String result(reinterpret_cast(decoded.data()), decoded.size()); IAT_CHECK_EQ(result, String("Hello World")); } @@ -76,10 +77,12 @@ auto test_base64_decode() -> bool { return true; } -auto test_base64_round_trip() -> bool { +auto test_base64_round_trip() -> bool +{ Vec original; original.reserve(256); - for (usize i = 0; i < 256; ++i) { + for (usize i = 0; i < 256; ++i) + { original.push_back(static_cast(i)); } @@ -89,8 +92,10 @@ auto test_base64_round_trip() -> bool { IAT_CHECK_EQ(original.size(), decoded.size()); bool match = true; - for (usize i = 0; i < original.size(); ++i) { - if (original[i] != decoded[i]) { + for (usize i = 0; i < original.size(); ++i) + { + if (original[i] != decoded[i]) + { match = false; break; } diff --git a/Tests/Unit/Utils.cpp b/Tests/Unit/Utils.cpp index 7c7be36..fc9ad1a 100644 --- a/Tests/Unit/Utils.cpp +++ b/Tests/Unit/Utils.cpp @@ -18,10 +18,12 @@ using namespace IACore; -struct TestVec3 { +struct TestVec3 +{ f32 x, y, z; - bool operator==(const TestVec3 &other) const { + bool operator==(const TestVec3 &other) const + { return x == other.x && y == other.y && z == other.z; } }; @@ -30,7 +32,8 @@ IA_MAKE_HASHABLE(TestVec3, &TestVec3::x, &TestVec3::y, &TestVec3::z); IAT_BEGIN_BLOCK(Core, Utils) -auto test_hex_conversion() -> bool { +auto test_hex_conversion() -> bool +{ u8 bin[] = {0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0xFF}; String hex = Utils::binary_to_hex_string(bin); @@ -57,7 +60,8 @@ auto test_hex_conversion() -> bool { return true; } -auto test_hex_errors() -> bool { +auto test_hex_errors() -> bool +{ auto odd = Utils::hex_string_to_binary("ABC"); IAT_CHECK_NOT(odd.has_value()); @@ -72,7 +76,8 @@ auto test_hex_errors() -> bool { return true; } -auto test_sort() -> bool { +auto test_sort() -> bool +{ Vec nums = {5, 1, 4, 2, 3}; Utils::sort(nums); @@ -86,7 +91,8 @@ auto test_sort() -> bool { return true; } -auto test_binary_search() -> bool { +auto test_binary_search() -> bool +{ Vec nums = {10, 20, 20, 20, 30}; @@ -106,7 +112,8 @@ auto test_binary_search() -> bool { return true; } -auto test_hash_basics() -> bool { +auto test_hash_basics() -> bool +{ u64 h1 = Utils::compute_hash(10, 20.5f, "Hello"); u64 h2 = Utils::compute_hash(10, 20.5f, "Hello"); u64 h3 = Utils::compute_hash(10, 20.5f, "World"); @@ -122,7 +129,8 @@ auto test_hash_basics() -> bool { return true; } -auto test_hash_macro() -> bool { +auto test_hash_macro() -> bool +{ TestVec3 v1{1.0f, 2.0f, 3.0f}; TestVec3 v2{1.0f, 2.0f, 3.0f}; TestVec3 v3{1.0f, 2.0f, 4.0f}; diff --git a/Tests/Unit/XML.cpp b/Tests/Unit/XML.cpp index d5e2f2c..f48c83e 100644 --- a/Tests/Unit/XML.cpp +++ b/Tests/Unit/XML.cpp @@ -21,7 +21,8 @@ using namespace IACore; IAT_BEGIN_BLOCK(Core, XML) -auto test_parse_string() -> bool { +auto test_parse_string() -> bool +{ const String xml_content = R"( Value1 @@ -47,14 +48,16 @@ auto test_parse_string() -> bool { return true; } -auto test_parse_error() -> bool { +auto test_parse_error() -> bool +{ const String invalid_xml = ""; auto res = XML::parse_from_string(invalid_xml); IAT_CHECK_NOT(res.has_value()); return true; } -auto test_serialize() -> bool { +auto test_serialize() -> bool +{ const String xml_content = "Text"; auto res = XML::parse_from_string(xml_content); IAT_CHECK(res.has_value()); @@ -67,7 +70,8 @@ auto test_serialize() -> bool { return true; } -auto test_escape() -> bool { +auto test_escape() -> bool +{ const String raw = "< & > \" '"; const String escaped = XML::escape_xml_string(raw); @@ -80,7 +84,8 @@ auto test_escape() -> bool { return true; } -auto test_file_io() -> bool { +auto test_file_io() -> bool +{ const Path path = "test_temp_xml_doc.xml"; const String content = "1.0"; @@ -91,8 +96,7 @@ auto test_file_io() -> bool { IAT_CHECK(parse_res.has_value()); auto &doc = *parse_res; - IAT_CHECK_EQ(String(doc.child("config").child("ver").child_value()), - String("1.0")); + IAT_CHECK_EQ(String(doc.child("config").child("ver").child_value()), String("1.0")); std::filesystem::remove(path);