From cd2ede593acee9c4956c79da4377ce890ac3a9c0 Mon Sep 17 00:00:00 2001 From: Alexandre Bouvier Date: Sun, 20 Nov 2022 21:49:18 +0100 Subject: [PATCH] Squashed 'externals/zycore/' changes from 0c372cde..1401fb85 1401fb85 Fix `a label can only be part of a statement` warning (#61) 5f650a18 CMake: Enable `CMAKE_MSVC_RUNTIME_LIBRARY` (MSVC) 6c958cfe Fix no-libc build on "other" platforms (#58) 59819206 Bump version to v1.4.0 4bc563f6 Fix build-system to better work with vcpkg (#56) 4a8b5e2a CMake: rename target `doc` -> `ZycoreDoc` a754e112 Bump version to 1.3.0 3e95307d Add support for ppc(64) and riscv64 (#52) 8f39333a build: only enable CXX if needed 7bd75696 build: add doc target 7c33e13e Fix `ZYAN_TRUE`/`ZYAN_FALSE` signedness a0feec7f Fix warning `C4668` bdbd3ff4 Bump version to v1.2 60b6ef1c Fix for dynamic libraries too 310f362c Adding ARCHIVE DESTINATION to fix CMake error b01063b8 Improved logic for enabling LTO c58d7fb5 Don't enable C11 for MSVC ee784564 Switch minimum C standard supported to C11 5c341bf1 Implement an initial set of cross-compiler atomic operations b4949ccc Minor fixes 9a305f6a Add CI workflow dd2211a0 Get rid of CMake export headers f0fb3f78 Fix `ZYAN_VECTOR_FOREACH_MUTABLE` macro 3f263290 format: handle encoding on wasm 95d7fb6c format: handle hex encoding on wasm 0d37fc54 defines: add wasm/wasi detection 8983325b build: use -pthread when possible 3de49d41 build: use system GTest when available 8d46cb58 test: make tests runnable with ctest 636bb299 Remove `float`s from the project (kernel mode compatibility) (#36) e2b37b10 Assert to ensure sane growth factors 94185407 Added limits for integer types 767719d9 build(cmake): export and install zyan_* functions (#33) 6c93d9a3 build(cmake): add version and soversion to the library fc2798d4 build(cmake): fix PUBLIC include dir of installed lib 22ce9c2d Add `ZYAN_FORCE_ASSERTS` CMake option 9a301424 Remove disabling source files in no-libc mode in CMake 3be54fca Thread.c: add missing SDK prototypes for old versions of Windows d7fc85fd Exclude API/Memory.c and API/Process.c from compilation in no-libc mode 8da0001a Add back #ifdef guards to "API" headers/sources for no-libc mode f6a48866 Fix cmake config files (#27) 4f3746fa Merge pull request #26 from Tsn0w/master a9bb54ad Replace fallthrough attribute to __fallthrough__ 99a74acb Add `ZYDIS_NOINLINE` macro git-subtree-dir: externals/zycore git-subtree-split: 1401fb85ac313f6605ec795c52bf99ea3f292a69 --- .github/FUNDING.yml | 1 + .github/workflows/main.yml | 86 ++++++++++ CMakeLists.txt | 222 ++++++++++++++----------- README.md | 4 + cmake/zyan-functions.cmake | 45 +++++ cmake/zycore-config.cmake.in | 9 + examples/Vector.c | 3 +- include/Zycore/API/Memory.h | 5 +- include/Zycore/API/Process.h | 5 +- include/Zycore/API/Synchronization.h | 5 +- include/Zycore/API/Terminal.h | 1 - include/Zycore/API/Thread.h | 5 +- include/Zycore/Allocator.h | 1 - include/Zycore/Atomic.h | 236 +++++++++++++++++++++++++++ include/Zycore/Bitset.h | 23 ++- include/Zycore/Defines.h | 92 ++++++++++- include/Zycore/Format.h | 1 - include/Zycore/Internal/AtomicGNU.h | 117 +++++++++++++ include/Zycore/Internal/AtomicMSVC.h | 141 ++++++++++++++++ include/Zycore/List.h | 1 - include/Zycore/String.h | 61 ++++--- include/Zycore/Types.h | 47 +++++- include/Zycore/Vector.h | 45 +++-- include/Zycore/Zycore.h | 3 +- resources/VersionInfo.rc | Bin 4500 -> 2190 bytes src/API/Memory.c | 4 + src/API/Process.c | 15 +- src/API/Synchronization.c | 4 + src/API/Terminal.c | 4 + src/API/Thread.c | 52 +++++- src/Bitset.c | 8 +- src/Format.c | 8 +- src/String.c | 8 +- src/Vector.c | 36 ++-- tests/Vector.cpp | 50 +++++- 35 files changed, 1120 insertions(+), 228 deletions(-) create mode 100644 .github/FUNDING.yml create mode 100644 .github/workflows/main.yml create mode 100644 cmake/zyan-functions.cmake create mode 100644 include/Zycore/Atomic.h create mode 100644 include/Zycore/Internal/AtomicGNU.h create mode 100644 include/Zycore/Internal/AtomicMSVC.h diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..c18b510f --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +github: flobernd \ No newline at end of file diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 00000000..953e4d65 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,86 @@ +name: GitHub Actions CI + +on: + push: + branches: + - master + pull_request: + types: [opened, synchronize, reopened] + +jobs: + build-linux: + name: Build ${{ matrix.platform.name }} ${{ matrix.compiler.name }} ${{ matrix.flavor }} (${{ matrix.mode.name }}) + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + platform: + - { name: x86, flags: "-m32" } + - { name: x64, flags: "-m64" } + compiler: + - { name: GNU, CC: gcc } + - { name: LLVM, CC: clang } + flavor: + - Debug + - Release + mode: + - { name: default, args: "" } + - { name: NO_LIBC, args: -DZYAN_NO_LIBC=ON } + + steps: + - name: Checkout + uses: actions/checkout@v3.1.0 + + - if: matrix.platform.name == 'x86' + name: Bootstrap + run: | + sudo dpkg --add-architecture i386 + sudo rm /etc/apt/sources.list.d/* && sudo apt-get update + sudo apt-get install -y g++-multilib g++ + + - name: Configure + env: + CC: ${{ matrix.compiler.CC }} + CXX: ${{ matrix.compiler.CXX }} + run: | + mkdir build + cd build + cmake -DCMAKE_C_FLAGS=${{ matrix.platform.flags }} -DCMAKE_CXX_FLAGS=${{ matrix.platform.flags }} -DZYAN_DEV_MODE=ON ${{ matrix.mode.args }} .. + + - name: Build + run: | + cmake --build build --config ${{ matrix.flavor }} + + build-windows: + name: Build ${{ matrix.platform.name }} ${{ matrix.compiler.name }} ${{ matrix.flavor }} (${{ matrix.mode.name }}) + runs-on: windows-latest + + strategy: + fail-fast: false + matrix: + platform: + - { name: x86, flags: "Win32" } + - { name: x64, flags: "x64" } + compiler: + - { name: MSVC } + flavor: + - Debug + - Release + mode: + - { name: default, args: "" } + - { name: NO_LIBC, args: -DZYAN_NO_LIBC=ON } + + steps: + - name: Checkout + uses: actions/checkout@v3.1.0 + + - name: Configure + run: | + mkdir build + cd build + cmake -DCMAKE_GENERATOR_PLATFORM=${{ matrix.platform.flags }} -DZYAN_DEV_MODE=ON ${{ matrix.mode.args }} .. + + - name: Build + run: | + cmake --build build --config ${{ matrix.flavor }} diff --git a/CMakeLists.txt b/CMakeLists.txt index ad01d650..e14145c6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,13 +2,18 @@ if (TARGET Zycore) return() endif () -cmake_minimum_required(VERSION 3.1 FATAL_ERROR) -include(GenerateExportHeader) +cmake_minimum_required(VERSION 3.9 FATAL_ERROR) + +if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.15") + # Enable runtime library selection via CMAKE_MSVC_RUNTIME_LIBRARY + cmake_policy(SET CMP0091 NEW) +endif () + +project(Zycore VERSION 1.4.0.0 LANGUAGES C) + include(GNUInstallDirs) include(CMakePackageConfigHelpers) -project(Zycore VERSION 1.0.0.0 LANGUAGES C CXX) - # =============================================================================================== # # Overridable options # # =============================================================================================== # @@ -23,6 +28,9 @@ option(ZYAN_NO_LIBC option(ZYAN_DEV_MODE "Enable developer mode (-Wall, -Werror, ...)" OFF) +option(ZYAN_FORCE_ASSERTS + "Forces asserts in release builds." + OFF) # Build configuration option(ZYCORE_BUILD_SHARED_LIB @@ -35,81 +43,70 @@ option(ZYCORE_BUILD_TESTS "Build tests" OFF) +# =============================================================================================== # +# Forced assertions hack # +# =============================================================================================== # + +# The code for this is adapted from how LLVM forces asserts. +if (ZYAN_FORCE_ASSERTS) + set(vars + CMAKE_CXX_FLAGS_RELEASE + CMAKE_CXX_FLAGS_RELWITHDEBINFO + CMAKE_CXX_FLAGS_MINSIZEREL + CMAKE_C_FLAGS_RELEASE + CMAKE_C_FLAGS_RELWITHDEBINFO + CMAKE_C_FLAGS_MINSIZEREL) + + foreach (var ${vars}) + string (REGEX REPLACE "(^| )[/-]D *NDEBUG($| )" " " "${var}" "${${var}}") + set("${var}" "${${var}} -UNDEBUG" CACHE STRING "" FORCE) + endforeach() +endif () + # =============================================================================================== # # GoogleTest # # =============================================================================================== # -# Download and unpack googletest +# Search for GoogleTest, and fallback to downloading it if not found if (ZYCORE_BUILD_TESTS) - if (NOT DEFINED ZYCORE_DOWNLOADED_GTEST) - configure_file("CMakeLists.txt.in" "${CMAKE_BINARY_DIR}/gtest/download/CMakeLists.txt") - execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . - RESULT_VARIABLE result - WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/gtest/download") - if (result) - message(FATAL_ERROR "CMake step for googletest failed: ${result}") - endif() - execute_process(COMMAND ${CMAKE_COMMAND} --build . - RESULT_VARIABLE result - WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/gtest/download") - if (result) - message(FATAL_ERROR "Build step for googletest failed: ${result}") - endif() + find_package(GTest QUIET) + if (GTest_FOUND) + # CMake 3.20 and upstream GTestConfig.cmake + if (TARGET GTest::gtest) + add_library(gtest ALIAS GTest::gtest) + # Older FindGTest + else () + add_library(gtest ALIAS GTest::GTest) + endif () + else () + if (NOT DEFINED ZYCORE_DOWNLOADED_GTEST) + configure_file("CMakeLists.txt.in" "${CMAKE_BINARY_DIR}/gtest/download/CMakeLists.txt") + execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . + RESULT_VARIABLE result + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/gtest/download") + if (result) + message(FATAL_ERROR "CMake step for googletest failed: ${result}") + endif() + execute_process(COMMAND ${CMAKE_COMMAND} --build . + RESULT_VARIABLE result + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/gtest/download") + if (result) + message(FATAL_ERROR "Build step for googletest failed: ${result}") + endif() - set(ZYCORE_DOWNLOADED_GTEST TRUE CACHE BOOL "") - mark_as_advanced(ZYCORE_DOWNLOADED_GTEST) - endif () + set(ZYCORE_DOWNLOADED_GTEST TRUE CACHE BOOL "") + mark_as_advanced(ZYCORE_DOWNLOADED_GTEST) + endif () set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) add_subdirectory("${CMAKE_BINARY_DIR}/gtest/src" "${CMAKE_BINARY_DIR}/gtest/build" EXCLUDE_FROM_ALL) + endif () endif () -# =============================================================================================== # -# Exported functions # -# =============================================================================================== # - -function (zyan_set_common_flags target) - if (NOT MSVC) - target_compile_options("${target}" PRIVATE "-std=c99") - endif () - - if (ZYAN_DEV_MODE) - # If in developer mode, be pedantic. - if (MSVC) - target_compile_options("${target}" PUBLIC "/WX" "/W4") - else () - target_compile_options("${target}" PUBLIC "-Wall" "-pedantic" "-Wextra" "-Werror") - endif () - endif () -endfunction () - -function (zyan_set_source_group target) - if (ZYAN_DEV_MODE) - if (((CMAKE_MAJOR_VERSION GREATER 3) OR (CMAKE_MAJOR_VERSION EQUAL 3)) AND - ((CMAKE_MINOR_VERSION GREATER 8) OR (CMAKE_MINOR_VERSION EQUAL 8))) - # Mirror directory structure in project files - get_property("TARGET_SOURCE_FILES" TARGET "${target}" PROPERTY SOURCES) - source_group(TREE "${CMAKE_CURRENT_LIST_DIR}" FILES ${TARGET_SOURCE_FILES}) - endif () - endif () -endfunction () - -function (zyan_maybe_enable_wpo target) - if (ZYAN_WHOLE_PROGRAM_OPTIMIZATION AND MSVC) - set_target_properties("${target}" PROPERTIES COMPILE_FLAGS "/GL") - set_target_properties("${target}" PROPERTIES LINK_FLAGS_RELEASE "/LTCG") - endif () -endfunction () - -function (zyan_maybe_enable_wpo_for_lib target) - if (ZYAN_WHOLE_PROGRAM_OPTIMIZATION AND MSVC) - set_target_properties("${target}" PROPERTIES COMPILE_FLAGS "/GL") - set_target_properties("${target}" PROPERTIES LINK_FLAGS_RELEASE "/LTCG") - set_target_properties("${target}" PROPERTIES STATIC_LIBRARY_FLAGS_RELEASE "/LTCG") - endif () -endfunction () +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") +include(zyan-functions) # =============================================================================================== # # Library configuration # @@ -119,16 +116,23 @@ if (ZYCORE_BUILD_SHARED_LIB) add_library("Zycore" SHARED) else () add_library("Zycore" STATIC) + target_compile_definitions("Zycore" PUBLIC "ZYCORE_STATIC_BUILD") endif () -set_target_properties("Zycore" PROPERTIES LINKER_LANGUAGE C) +set_target_properties("Zycore" PROPERTIES + LINKER_LANGUAGE C + VERSION "${Zycore_VERSION}" + SOVERSION "${Zycore_VERSION_MAJOR}.${Zycore_VERSION_MINOR}" + DEFINE_SYMBOL "ZYCORE_SHOULD_EXPORT") target_include_directories("Zycore" - PUBLIC "include" ${PROJECT_BINARY_DIR} + PUBLIC + $ + $ + $ PRIVATE "src") -target_compile_definitions("Zycore" PRIVATE "_CRT_SECURE_NO_WARNINGS" "ZYCORE_EXPORTS") +target_compile_definitions("Zycore" PRIVATE "_CRT_SECURE_NO_WARNINGS") zyan_set_common_flags("Zycore") -zyan_maybe_enable_wpo_for_lib("Zycore") -generate_export_header("Zycore" BASE_NAME "ZYCORE" EXPORT_FILE_NAME "ZycoreExportConfig.h") +zyan_maybe_enable_wpo("Zycore") if (ZYAN_NO_LIBC) target_compile_definitions("Zycore" PUBLIC "ZYAN_NO_LIBC") @@ -148,6 +152,7 @@ target_sources("Zycore" # Common "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/Allocator.h" "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/ArgParse.h" + "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/Atomic.h" "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/Bitset.h" "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/Comparison.h" "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/Defines.h" @@ -160,6 +165,14 @@ target_sources("Zycore" "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/Types.h" "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/Vector.h" "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/Zycore.h" + "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/Internal/AtomicGNU.h" + "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/Internal/AtomicMSVC.h" + # API + "src/API/Memory.c" + "src/API/Process.c" + "src/API/Synchronization.c" + "src/API/Terminal.c" + "src/API/Thread.c" # Common "src/Allocator.c" "src/ArgParse.c" @@ -170,17 +183,6 @@ target_sources("Zycore" "src/Vector.c" "src/Zycore.c") -if (NOT ZYAN_NO_LIBC) - target_sources("Zycore" - PRIVATE - # API - "src/API/Memory.c" - "src/API/Process.c" - "src/API/Synchronization.c" - "src/API/Terminal.c" - "src/API/Thread.c") -endif () - if (ZYCORE_BUILD_SHARED_LIB AND WIN32) target_sources("Zycore" PRIVATE "resources/VersionInfo.rc") endif () @@ -189,28 +191,51 @@ zyan_set_source_group("Zycore") if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" AND NOT ZYAN_NO_LIBC) target_compile_definitions("Zycore" PRIVATE "_GNU_SOURCE") + set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) target_link_libraries("Zycore" Threads::Threads) endif () configure_package_config_file(cmake/zycore-config.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/zycore-config.cmake" - INSTALL_DESTINATION "${CMAKE_INSTALL_PREFIX}/cmake" + INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/zycore" +) +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/zycore-config-version.cmake" + COMPATIBILITY SameMajorVersion ) install(FILES + "cmake/zyan-functions.cmake" "${CMAKE_CURRENT_BINARY_DIR}/zycore-config.cmake" - DESTINATION "${CMAKE_INSTALL_PREFIX}/cmake" + "${CMAKE_CURRENT_BINARY_DIR}/zycore-config-version.cmake" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/zycore" ) -install(TARGETS "Zycore" +install(TARGETS "Zycore" EXPORT "zycore-targets" ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) -install(FILES - "${PROJECT_BINARY_DIR}/ZycoreExportConfig.h" - DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}") + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) + +install(EXPORT "zycore-targets" + NAMESPACE "Zycore::" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/zycore") install(DIRECTORY "include/" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) +# =============================================================================================== # +# Doxygen documentation # +# =============================================================================================== # + +find_package(Doxygen) +if (DOXYGEN_FOUND) + doxygen_add_docs(ZycoreDoc "include/Zycore/" ALL) + install( + DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/html/" + DESTINATION "${CMAKE_INSTALL_DOCDIR}/api" + COMPONENT Documentation + ) +endif() + # =============================================================================================== # # Developer mode # # =============================================================================================== # @@ -245,19 +270,22 @@ endif () function (zyan_add_test test) add_executable("Test${test}" "tests/${test}.cpp") - - if (NOT MSVC) - target_compile_options("Test${test}" PRIVATE "-std=c++17") - endif () - - target_link_libraries("Test${test}" "Zycore") - target_link_libraries("Test${test}" "gtest") - set_target_properties("Test${test}" PROPERTIES FOLDER "Tests") + target_link_libraries("Test${test}" "Zycore" "gtest") + set_target_properties("Test${test}" PROPERTIES + LANGUAGE CXX + CXX_STANDARD 17 + CXX_EXTENSIONS OFF + CXX_STANDARD_REQUIRED ON + FOLDER "Tests" + ) target_compile_definitions("Test${test}" PRIVATE "_CRT_SECURE_NO_WARNINGS") zyan_maybe_enable_wpo("Test${test}") + add_test("${test}" "Test${test}") endfunction () if (ZYCORE_BUILD_TESTS) + enable_language(CXX) + enable_testing() zyan_add_test("String") zyan_add_test("Vector") zyan_add_test("ArgParse") diff --git a/README.md b/README.md index 309a73b6..ff2fc410 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ # Zyan Core Library for C +License: MIT +GitHub Actions +Discord + Internal library providing platform independent types, macros and a fallback for environments without LibC. ## Features diff --git a/cmake/zyan-functions.cmake b/cmake/zyan-functions.cmake new file mode 100644 index 00000000..17b0f03a --- /dev/null +++ b/cmake/zyan-functions.cmake @@ -0,0 +1,45 @@ +# =============================================================================================== # +# Exported functions # +# =============================================================================================== # + +function (zyan_set_common_flags target) + if (MSVC) + # MSVC support for C11 is still pretty lacking, so we instead just disable the warnings + # about using non-standard C extensions. + target_compile_options("${target}" PUBLIC "/wd4201") + else () + # For the more civilized compilers, we go with C11. + set_target_properties("${target}" PROPERTIES C_STANDARD 11) + endif () + + if (ZYAN_DEV_MODE) + # If in developer mode, be pedantic. + if (MSVC) + target_compile_options("${target}" PUBLIC "/WX" "/W4") + else () + target_compile_options("${target}" PUBLIC "-Wall" "-pedantic" "-Wextra" "-Werror") + endif () + endif () +endfunction () + +function (zyan_set_source_group target) + if (ZYAN_DEV_MODE) + if (((CMAKE_MAJOR_VERSION GREATER 3) OR (CMAKE_MAJOR_VERSION EQUAL 3)) AND + ((CMAKE_MINOR_VERSION GREATER 8) OR (CMAKE_MINOR_VERSION EQUAL 8))) + # Mirror directory structure in project files + get_property("TARGET_SOURCE_FILES" TARGET "${target}" PROPERTY SOURCES) + source_group(TREE "${CMAKE_CURRENT_LIST_DIR}" FILES ${TARGET_SOURCE_FILES}) + endif () + endif () +endfunction () + +function (zyan_maybe_enable_wpo target) + if (ZYAN_WHOLE_PROGRAM_OPTIMIZATION) + set_property(TARGET "${target}" PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE) + endif () +endfunction () + +# deprecated alias for `zyan_maybe_enable_wpo`, for backward compatibility. +function (zyan_maybe_enable_wpo_for_lib target) + zyan_maybe_enable_wpo("${target}") +endfunction () diff --git a/cmake/zycore-config.cmake.in b/cmake/zycore-config.cmake.in index 400ab53a..67eedc48 100644 --- a/cmake/zycore-config.cmake.in +++ b/cmake/zycore-config.cmake.in @@ -2,6 +2,15 @@ set(zycore_VERSION @PROJECT_VERSION@) @PACKAGE_INIT@ +include(CMakeFindDependencyMacro) +if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" AND NOT @ZYAN_NO_LIBC@) + find_dependency(Threads) +endif() + +include("${CMAKE_CURRENT_LIST_DIR}/zyan-functions.cmake") + +include("${CMAKE_CURRENT_LIST_DIR}/zycore-targets.cmake") + set_and_check(zycore_INCLUDE_DIR "${PACKAGE_PREFIX_DIR}/@CMAKE_INSTALL_INCLUDEDIR@") set_and_check(zycore_LIB_DIR "${PACKAGE_PREFIX_DIR}/@CMAKE_INSTALL_LIBDIR@") diff --git a/examples/Vector.c b/examples/Vector.c index 090ad330..3624efee 100644 --- a/examples/Vector.c +++ b/examples/Vector.c @@ -98,6 +98,7 @@ static ZyanStatus PerformBasicTests(ZyanVector* vector) { InitTestdata(&e_v, i); ZYAN_CHECK(ZyanVectorPushBack(vector, &e_v)); + printf("i=%d cap=%" PRIuPTR, i, vector->capacity); } // Remove elements `#05..#09` @@ -332,7 +333,7 @@ static ZyanStatus TestAllocator(void) // dynamic shrinking is disabled ZyanVector vector; ZYAN_CHECK(ZyanVectorInitEx(&vector, sizeof(TestStruct), 5, ZYAN_NULL, &allocator, - 10.0f, 0.0f)); + 10, 0)); static TestStruct e_v; diff --git a/include/Zycore/API/Memory.h b/include/Zycore/API/Memory.h index c5fa8a9b..1030e83f 100644 --- a/include/Zycore/API/Memory.h +++ b/include/Zycore/API/Memory.h @@ -32,11 +32,12 @@ #ifndef ZYCORE_API_MEMORY_H #define ZYCORE_API_MEMORY_H -#include #include #include #include +#ifndef ZYAN_NO_LIBC + #if defined(ZYAN_WINDOWS) # include #elif defined(ZYAN_POSIX) @@ -131,4 +132,6 @@ ZYCORE_EXPORT ZyanStatus ZyanMemoryVirtualFree(void* address, ZyanUSize size); /* ============================================================================================== */ +#endif /* ZYAN_NO_LIBC */ + #endif /* ZYCORE_API_MEMORY_H */ diff --git a/include/Zycore/API/Process.h b/include/Zycore/API/Process.h index 0b6a5c6b..f8e1e4f2 100644 --- a/include/Zycore/API/Process.h +++ b/include/Zycore/API/Process.h @@ -32,10 +32,11 @@ #ifndef ZYCORE_API_PROCESS_H #define ZYCORE_API_PROCESS_H -#include #include #include +#ifndef ZYAN_NO_LIBC + /* ============================================================================================== */ /* Enums and types */ /* ============================================================================================== */ @@ -64,4 +65,6 @@ ZYCORE_EXPORT ZyanStatus ZyanProcessFlushInstructionCache(void* address, ZyanUSi /* ============================================================================================== */ +#endif /* ZYAN_NO_LIBC */ + #endif /* ZYCORE_API_PROCESS_H */ diff --git a/include/Zycore/API/Synchronization.h b/include/Zycore/API/Synchronization.h index 8414a44b..ec32f066 100644 --- a/include/Zycore/API/Synchronization.h +++ b/include/Zycore/API/Synchronization.h @@ -32,12 +32,11 @@ #ifndef ZYCORE_API_SYNCHRONIZATION_H #define ZYCORE_API_SYNCHRONIZATION_H -#ifndef ZYAN_NO_LIBC - -#include #include #include +#ifndef ZYAN_NO_LIBC + #ifdef __cplusplus extern "C" { #endif diff --git a/include/Zycore/API/Terminal.h b/include/Zycore/API/Terminal.h index 17dc384b..3bff8c15 100644 --- a/include/Zycore/API/Terminal.h +++ b/include/Zycore/API/Terminal.h @@ -32,7 +32,6 @@ #ifndef ZYCORE_API_TERMINAL_H #define ZYCORE_API_TERMINAL_H -#include #include #include diff --git a/include/Zycore/API/Thread.h b/include/Zycore/API/Thread.h index b1ec085e..402a2da5 100644 --- a/include/Zycore/API/Thread.h +++ b/include/Zycore/API/Thread.h @@ -32,12 +32,11 @@ #ifndef ZYCORE_API_THREAD_H #define ZYCORE_API_THREAD_H -#ifndef ZYAN_NO_LIBC - -#include #include #include +#ifndef ZYAN_NO_LIBC + #ifdef __cplusplus extern "C" { #endif diff --git a/include/Zycore/Allocator.h b/include/Zycore/Allocator.h index 64351719..ff80a2c3 100644 --- a/include/Zycore/Allocator.h +++ b/include/Zycore/Allocator.h @@ -32,7 +32,6 @@ #ifndef ZYCORE_ALLOCATOR_H #define ZYCORE_ALLOCATOR_H -#include #include #include diff --git a/include/Zycore/Atomic.h b/include/Zycore/Atomic.h new file mode 100644 index 00000000..f5dcf273 --- /dev/null +++ b/include/Zycore/Atomic.h @@ -0,0 +1,236 @@ +/*************************************************************************************************** + + Zyan Core Library (Zyan-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * Cross compiler atomic intrinsics. + */ + +#ifndef ZYCORE_ATOMIC_H +#define ZYCORE_ATOMIC_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +/* ============================================================================================== */ +/* Enums and Types */ +/* ============================================================================================== */ + +/* + * Wraps a 32-bit value to provide atomic access. + */ +typedef struct ZyanAtomic32_ +{ + ZyanU32 volatile value; +} ZyanAtomic32; + +/* + * Wraps a 64-bit value to provide atomic access. + */ +typedef struct ZyanAtomic64_ +{ + ZyanU64 volatile value; +} ZyanAtomic64; + +/* + * Wraps a pointer-sized value to provide atomic access. + */ +typedef struct ZyanAtomicPointer_ +{ + ZyanVoidPointer volatile value; +} ZyanAtomicPointer; + +/* ============================================================================================== */ +/* Macros */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Pointer sized */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * @copydoc ZyanAtomicCompareExchange + */ +#define ZYAN_ATOMIC_COMPARE_EXCHANGE(destination, comparand, value) \ + ZyanAtomicCompareExchange((ZyanAtomicPointer*)&(destination), (comparand), (value)) + +/** + * @copydoc ZyanAtomicIncrement + */ +#define ZYAN_ATOMIC_INCREMENT(destination) \ + ZyanAtomicIncrement((ZyanAtomicPointer*)&(destination)); + +/** + * @copydoc ZyanAtomicDecrement + */ +#define ZYAN_ATOMIC_DECREMENT(destination) \ + ZyanAtomicDecrement((ZyanAtomicPointer*)&(destination)); + +/* ---------------------------------------------------------------------------------------------- */ +/* 32-bit */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * @copydoc ZyanAtomicCompareExchange + */ +#define ZYAN_ATOMIC_COMPARE_EXCHANGE32(destination, comparand, value) \ + ZyanAtomicCompareExchange32((ZyanAtomic32*)&(destination), (comparand), (value)) + +/** + * @copydoc ZyanAtomicIncrement + */ +#define ZYAN_ATOMIC_INCREMENT32(destination) \ + ZyanAtomicIncrement32((ZyanAtomic32*)&(destination)); + +/** + * @copydoc ZyanAtomicDecrement + */ +#define ZYAN_ATOMIC_DECREMENT32(destination) \ + ZyanAtomicDecrement32((ZyanAtomic32*)&(destination)); + +/* ---------------------------------------------------------------------------------------------- */ +/* 64-bit */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * @copydoc ZyanAtomicCompareExchange + */ +#define ZYAN_ATOMIC_COMPARE_EXCHANGE64(destination, comparand, value) \ + ZyanAtomicCompareExchange64((ZyanAtomic64*)&(destination), (comparand), (value)) + +/** + * @copydoc ZyanAtomicIncrement + */ +#define ZYAN_ATOMIC_INCREMENT64(destination) \ + ZyanAtomicIncrement64((ZyanAtomic64*)&(destination)); + +/** + * @copydoc ZyanAtomicDecrement + */ +#define ZYAN_ATOMIC_DECREMENT64(destination) \ + ZyanAtomicDecrement64((ZyanAtomic64*)&(destination)); + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ +/* Functions */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Pointer sized */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Compares two values for equality and, if they are equal, replaces the first value. + * + * @param destination A pointer to the destination value. + * @param comparand The value to compare with. + * @param value The replacement value. + * + * @return The original value. + */ +static ZyanUPointer ZyanAtomicCompareExchange(ZyanAtomicPointer* destination, + ZyanUPointer comparand, ZyanUPointer value); + +/** + * Increments the given value and stores the result, as an atomic operation. + * + * @param destination A pointer to the destination value. + * + * @return The incremented value. +*/ +static ZyanUPointer ZyanAtomicIncrement(ZyanAtomicPointer* destination); + +/** + * Decrements the given value and stores the result, as an atomic operation. + * + * @param destination A pointer to the destination value. + * + * @return The decremented value. +*/ +static ZyanUPointer ZyanAtomicDecrement(ZyanAtomicPointer* destination); + +/* ---------------------------------------------------------------------------------------------- */ +/* 32-bit */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * @copydoc ZyanAtomicCompareExchange + */ +static ZyanU32 ZyanAtomicCompareExchange32(ZyanAtomic32* destination, + ZyanU32 comparand, ZyanU32 value); + +/** + * @copydoc ZyanAtomicIncrement + */ +static ZyanU32 ZyanAtomicIncrement32(ZyanAtomic32* destination); + +/** + * @copydoc ZyanAtomicDecrement + */ +static ZyanU32 ZyanAtomicDecrement32(ZyanAtomic32* destination); + +/* ---------------------------------------------------------------------------------------------- */ +/* 64-bit */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * @copydoc ZyanAtomicCompareExchange + */ +static ZyanU64 ZyanAtomicCompareExchange64(ZyanAtomic64* destination, + ZyanU64 comparand, ZyanU64 value); + +/** + * @copydoc ZyanAtomicIncrement + */ +static ZyanU64 ZyanAtomicIncrement64(ZyanAtomic64* destination); + +/** + * @copydoc ZyanAtomicDecrement + */ +static ZyanU64 ZyanAtomicDecrement64(ZyanAtomic64* destination); + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ + +#if defined(ZYAN_CLANG) || defined(ZYAN_GCC) || defined(ZYAN_ICC) +# include +#elif defined(ZYAN_MSVC) +# include +#else +# error "Unsupported compiler detected" +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* ZYCORE_ATOMIC_H */ diff --git a/include/Zycore/Bitset.h b/include/Zycore/Bitset.h index 8c7eb1f3..0404f873 100644 --- a/include/Zycore/Bitset.h +++ b/include/Zycore/Bitset.h @@ -32,7 +32,6 @@ #ifndef ZYCORE_BITSET_H #define ZYCORE_BITSET_H -#include #include #include #include @@ -96,7 +95,7 @@ typedef ZyanStatus (*ZyanBitsetByteOperation)(ZyanU8* v1, const ZyanU8* v2); * @return A zyan status code. * * The space for the bitset is dynamically allocated by the default allocator using the default - * growth factor of `2.0f` and the default shrink threshold of `0.5f`. + * growth factor and the default shrink threshold. */ ZYCORE_EXPORT ZYAN_REQUIRES_LIBC ZyanStatus ZyanBitsetInit(ZyanBitset* bitset, ZyanUSize count); @@ -109,16 +108,16 @@ ZYCORE_EXPORT ZYAN_REQUIRES_LIBC ZyanStatus ZyanBitsetInit(ZyanBitset* bitset, Z * @param bitset A pointer to the `ZyanBitset` instance. * @param count The initial amount of bits. * @param allocator A pointer to a `ZyanAllocator` instance. - * @param growth_factor The growth factor (from `1.0f` to `x.xf`). - * @param shrink_threshold The shrink threshold (from `0.0f` to `1.0f`). + * @param growth_factor The growth factor. + * @param shrink_threshold The shrink threshold. * * @return A zyan status code. * - * A growth factor of `1.0f` disables overallocation and a shrink threshold of `0.0f` disables + * A growth factor of `1` disables overallocation and a shrink threshold of `0` disables * dynamic shrinking. */ ZYCORE_EXPORT ZyanStatus ZyanBitsetInitEx(ZyanBitset* bitset, ZyanUSize count, - ZyanAllocator* allocator, float growth_factor, float shrink_threshold); + ZyanAllocator* allocator, ZyanU8 growth_factor, ZyanU8 shrink_threshold); /** * Initializes the given `ZyanBitset` instance and configures it to use a custom user @@ -266,7 +265,7 @@ ZYCORE_EXPORT ZyanStatus ZyanBitsetToggle(ZyanBitset* bitset, ZyanUSize index); * @param index The bit index. * * @return `ZYAN_STATUS_TRUE`, if the bit is set or `ZYAN_STATUS_FALSE`, if not, Another zyan - * status code, if an error occured. + * status code, if an error occurred. */ ZYCORE_EXPORT ZyanStatus ZyanBitsetTest(ZyanBitset* bitset, ZyanUSize index); @@ -276,7 +275,7 @@ ZYCORE_EXPORT ZyanStatus ZyanBitsetTest(ZyanBitset* bitset, ZyanUSize index); * @param bitset A pointer to the `ZyanBitset` instance. * * @return `ZYAN_STATUS_TRUE`, if the bit is set or `ZYAN_STATUS_FALSE`, if not. Another zyan - * status code, if an error occured. + * status code, if an error occurred. */ ZYCORE_EXPORT ZyanStatus ZyanBitsetTestMSB(ZyanBitset* bitset); @@ -286,7 +285,7 @@ ZYCORE_EXPORT ZyanStatus ZyanBitsetTestMSB(ZyanBitset* bitset); * @param bitset A pointer to the `ZyanBitset` instance. * * @return `ZYAN_STATUS_TRUE`, if the bit is set or `ZYAN_STATUS_FALSE`, if not. Another zyan - * status code, if an error occured. + * status code, if an error occurred. */ ZYCORE_EXPORT ZyanStatus ZyanBitsetTestLSB(ZyanBitset* bitset); @@ -427,7 +426,7 @@ ZYCORE_EXPORT ZyanStatus ZyanBitsetCount(const ZyanBitset* bitset, ZyanUSize* co * @param bitset A pointer to the `ZyanBitset` instance. * * @return `ZYAN_STATUS_TRUE`, if all bits are set, `ZYAN_STATUS_FALSE`, if not. Another zyan - * status code, if an error occured. + * status code, if an error occurred. */ ZYCORE_EXPORT ZyanStatus ZyanBitsetAll(const ZyanBitset* bitset); @@ -437,7 +436,7 @@ ZYCORE_EXPORT ZyanStatus ZyanBitsetAll(const ZyanBitset* bitset); * @param bitset A pointer to the `ZyanBitset` instance. * * @return `ZYAN_STATUS_TRUE`, if at least one bit is set, `ZYAN_STATUS_FALSE`, if not. Another - * zyan status code, if an error occured. + * zyan status code, if an error occurred. */ ZYCORE_EXPORT ZyanStatus ZyanBitsetAny(const ZyanBitset* bitset); @@ -447,7 +446,7 @@ ZYCORE_EXPORT ZyanStatus ZyanBitsetAny(const ZyanBitset* bitset); * @param bitset A pointer to the `ZyanBitset` instance. * * @return `ZYAN_STATUS_TRUE`, if none bits are set, `ZYAN_STATUS_FALSE`, if not. Another zyan - * status code, if an error occured. + * status code, if an error occurred. */ ZYCORE_EXPORT ZyanStatus ZyanBitsetNone(const ZyanBitset* bitset); diff --git a/include/Zycore/Defines.h b/include/Zycore/Defines.h index 65afbaa3..2030abb6 100644 --- a/include/Zycore/Defines.h +++ b/include/Zycore/Defines.h @@ -85,6 +85,9 @@ # define ZYAN_WINDOWS #elif defined(__EMSCRIPTEN__) # define ZYAN_EMSCRIPTEN +#elif defined(__wasi__) || defined(__WASI__) +// via: https://reviews.llvm.org/D57155 +# define ZYAN_WASI #elif defined(__APPLE__) # define ZYAN_APPLE # define ZYAN_POSIX @@ -131,8 +134,14 @@ # define ZYAN_AARCH64 #elif defined(_M_ARM) || defined(_M_ARMT) || defined(__arm__) || defined(__thumb__) # define ZYAN_ARM -#elif defined(__EMSCRIPTEN__) - // Nothing to do, `ZYAN_EMSCRIPTEN` is both platform and arch macro for this one. +#elif defined(__EMSCRIPTEN__) || defined(__wasm__) || defined(__WASM__) +# define ZYAN_WASM +#elif defined(__powerpc64__) +# define ZYAN_PPC64 +#elif defined(__powerpc__) +# define ZYAN_PPC +#elif defined(__riscv) && __riscv_xlen == 64 +# define ZYAN_RISCV64 #else # error "Unsupported architecture detected" #endif @@ -157,6 +166,73 @@ # define ZYAN_RELEASE #endif +/* ============================================================================================== */ +/* Deprecation hint */ +/* ============================================================================================== */ + +#if defined(ZYAN_GCC) || defined(ZYAN_CLANG) +# define ZYAN_DEPRECATED __attribute__((__deprecated__)) +#elif defined(ZYAN_MSVC) +# define ZYAN_DEPRECATED __declspec(deprecated) +#else +# define ZYAN_DEPRECATED +#endif + +/* ============================================================================================== */ +/* Generic DLL import/export helpers */ +/* ============================================================================================== */ + +#if defined(ZYAN_MSVC) +# define ZYAN_DLLEXPORT __declspec(dllexport) +# define ZYAN_DLLIMPORT __declspec(dllimport) +#else +# define ZYAN_DLLEXPORT +# define ZYAN_DLLIMPORT +#endif + +/* ============================================================================================== */ +/* Zycore dll{export,import} */ +/* ============================================================================================== */ + +// This is a cut-down version of what CMake's `GenerateExportHeader` would usually generate. To +// simplify builds without CMake, we define these things manually instead of relying on CMake +// to generate the header. +// +// For static builds, our CMakeList will define `ZYCORE_STATIC_BUILD`. For shared library builds, +// our CMake will define `ZYCORE_SHOULD_EXPORT` depending on whether the target is being imported or +// exported. If CMake isn't used, users can manually define these to fit their use-case. + +// Backward compatibility: CMake would previously generate these variables names. However, because +// they have pretty cryptic names, we renamed them when we got rid of `GenerateExportHeader`. For +// backward compatibility for users that don't use CMake and previously manually defined these, we +// translate the old defines here and print a warning. +#if defined(ZYCORE_STATIC_DEFINE) +# pragma message("ZYCORE_STATIC_DEFINE was renamed to ZYCORE_STATIC_BUILD.") +# define ZYCORE_STATIC_BUILD +#endif +#if defined(Zycore_EXPORTS) +# pragma message("Zycore_EXPORTS was renamed to ZYCORE_SHOULD_EXPORT.") +# define ZYCORE_SHOULD_EXPORT +#endif + +/** + * Symbol is exported in shared library builds. + */ +#if defined(ZYCORE_STATIC_BUILD) +# define ZYCORE_EXPORT +#else +# if defined(ZYCORE_SHOULD_EXPORT) +# define ZYCORE_EXPORT ZYAN_DLLEXPORT +# else +# define ZYCORE_EXPORT ZYAN_DLLIMPORT +# endif +#endif + +/** + * Symbol is not exported and for internal use only. + */ +#define ZYCORE_NO_EXPORT + /* ============================================================================================== */ /* Misc compatibility macros */ /* ============================================================================================== */ @@ -173,6 +249,14 @@ # define ZYAN_INLINE static inline #endif +#if defined(ZYAN_MSVC) +# define ZYAN_NOINLINE __declspec(noinline) +#elif defined(ZYAN_GCC) || defined(ZYAN_CLANG) +# define ZYAN_NOINLINE __attribute__((noinline)) +#else +# define ZYAN_NOINLINE +#endif + /* ============================================================================================== */ /* Debugging and optimization macros */ /* ============================================================================================== */ @@ -193,7 +277,7 @@ /** * Compiler-time assertion. */ -#if __STDC_VERSION__ >= 201112L && !defined(__cplusplus) +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__cplusplus) # define ZYAN_STATIC_ASSERT(x) _Static_assert(x, #x) #elif (defined(__cplusplus) && __cplusplus >= 201103L) || \ (defined(__cplusplus) && defined (_MSC_VER) && (_MSC_VER >= 1600)) || \ @@ -256,7 +340,7 @@ * Intentional fallthrough. */ #if defined(ZYAN_GCC) && __GNUC__ >= 7 -# define ZYAN_FALLTHROUGH __attribute__((fallthrough)) +# define ZYAN_FALLTHROUGH ; __attribute__((__fallthrough__)) #else # define ZYAN_FALLTHROUGH #endif diff --git a/include/Zycore/Format.h b/include/Zycore/Format.h index b0401e62..006ca312 100644 --- a/include/Zycore/Format.h +++ b/include/Zycore/Format.h @@ -32,7 +32,6 @@ #ifndef ZYCORE_FORMAT_H #define ZYCORE_FORMAT_H -#include #include #include #include diff --git a/include/Zycore/Internal/AtomicGNU.h b/include/Zycore/Internal/AtomicGNU.h new file mode 100644 index 00000000..49d4b6fd --- /dev/null +++ b/include/Zycore/Internal/AtomicGNU.h @@ -0,0 +1,117 @@ +/*************************************************************************************************** + + Zyan Core Library (Zyan-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +#ifndef ZYCORE_ATOMIC_GNU_H +#define ZYCORE_ATOMIC_GNU_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +/* ============================================================================================== */ +/* Functions */ +/* ============================================================================================== */ + +#if defined(ZYAN_CLANG) || defined(ZYAN_GCC) || defined(ZYAN_ICC) + +/* ---------------------------------------------------------------------------------------------- */ +/* Pointer sized */ +/* ---------------------------------------------------------------------------------------------- */ + +ZYAN_INLINE ZyanUPointer ZyanAtomicCompareExchange(ZyanAtomicPointer* destination, + ZyanUPointer comparand, ZyanUPointer value) +{ + return (ZyanUPointer)(__sync_val_compare_and_swap( + &destination->value, (void*)comparand, (void*)value, &destination->value)); +} + +ZYAN_INLINE ZyanUPointer ZyanAtomicIncrement(ZyanAtomicPointer* destination) +{ + return (ZyanUPointer)(__sync_fetch_and_add(&destination->value, (void*)1, + &destination->value)) + 1; +} + +ZYAN_INLINE ZyanUPointer ZyanAtomicDecrement(ZyanAtomicPointer* destination) +{ + return (ZyanUPointer)(__sync_sub_and_fetch(&destination->value, (void*)1, &destination->value)); +} + +/* ---------------------------------------------------------------------------------------------- */ +/* 32-bit */ +/* ---------------------------------------------------------------------------------------------- */ + +ZYAN_INLINE ZyanU32 ZyanAtomicCompareExchange32(ZyanAtomic32* destination, + ZyanU32 comparand, ZyanU32 value) +{ + return (ZyanU32)(__sync_val_compare_and_swap(&destination->value, comparand, value, + &destination->value)); +} + +ZYAN_INLINE ZyanU32 ZyanAtomicIncrement32(ZyanAtomic32* destination) +{ + return (ZyanU32)(__sync_fetch_and_add(&destination->value, 1, &destination->value)) + 1; +} + +ZYAN_INLINE ZyanU32 ZyanAtomicDecrement32(ZyanAtomic32* destination) +{ + return (ZyanU32)(__sync_sub_and_fetch(&destination->value, 1, &destination->value)); +} + +/* ---------------------------------------------------------------------------------------------- */ +/* 64-bit */ +/* ---------------------------------------------------------------------------------------------- */ + +ZYAN_INLINE ZyanU64 ZyanAtomicCompareExchange64(ZyanAtomic64* destination, + ZyanU64 comparand, ZyanU64 value) +{ + return (ZyanU64)(__sync_val_compare_and_swap(&destination->value, comparand, value, + &destination->value)); +} + +ZYAN_INLINE ZyanU64 ZyanAtomicIncrement64(ZyanAtomic64* destination) +{ + return (ZyanU64)(__sync_fetch_and_add(&destination->value, 1, &destination->value)) + 1; +} + +ZYAN_INLINE ZyanU64 ZyanAtomicDecrement64(ZyanAtomic64* destination) +{ + return (ZyanU64)(__sync_sub_and_fetch(&destination->value, 1, &destination->value)); +} + +/* ---------------------------------------------------------------------------------------------- */ + +#endif + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZYCORE_ATOMIC_GNU_H */ diff --git a/include/Zycore/Internal/AtomicMSVC.h b/include/Zycore/Internal/AtomicMSVC.h new file mode 100644 index 00000000..f4dc1e60 --- /dev/null +++ b/include/Zycore/Internal/AtomicMSVC.h @@ -0,0 +1,141 @@ +/*************************************************************************************************** + + Zyan Core Library (Zyan-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +#ifndef ZYCORE_ATOMIC_MSVC_H +#define ZYCORE_ATOMIC_MSVC_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include +#include + +/* ============================================================================================== */ +/* Functions */ +/* ============================================================================================== */ + +#if defined(ZYAN_MSVC) + +/* ---------------------------------------------------------------------------------------------- */ +/* Pointer sized */ +/* ---------------------------------------------------------------------------------------------- */ + +#if defined(ZYAN_X86) + +static ZYAN_INLINE ZyanUPointer ZyanAtomicCompareExchange(ZyanAtomicPointer* destination, + ZyanUPointer comparand, ZyanUPointer value) +{ + return (ZyanUPointer)ZyanAtomicCompareExchange32((ZyanAtomic32*)destination, comparand, value); +} + +static ZYAN_INLINE ZyanUPointer ZyanAtomicIncrement(ZyanAtomicPointer* destination) +{ + return (ZyanUPointer)ZyanAtomicIncrement32((ZyanAtomic32*)destination); +} + +static ZYAN_INLINE ZyanUPointer ZyanAtomicDecrement(ZyanAtomicPointer* destination) +{ + return (ZyanUPointer)ZyanAtomicDecrement32((ZyanAtomic32*)destination); +} + +#elif defined(ZYAN_X64) + +static ZYAN_INLINE ZyanUPointer ZyanAtomicCompareExchange(ZyanAtomicPointer* destination, + ZyanUPointer comparand, ZyanUPointer value) +{ + return (ZyanUPointer)ZyanAtomicCompareExchange64((ZyanAtomic64*)destination, comparand, value); +} + +static ZYAN_INLINE ZyanUPointer ZyanAtomicIncrement(ZyanAtomicPointer* destination) +{ + return (ZyanUPointer)ZyanAtomicIncrement64((ZyanAtomic64*)destination); +} + +static ZYAN_INLINE ZyanUPointer ZyanAtomicDecrement(ZyanAtomicPointer* destination) +{ + return (ZyanUPointer)ZyanAtomicDecrement64((ZyanAtomic64*)destination); +} + +#else +# error "Unsupported architecture detected" +#endif + +/* ---------------------------------------------------------------------------------------------- */ +/* 32-bit */ +/* ---------------------------------------------------------------------------------------------- */ + +static ZYAN_INLINE ZyanU32 ZyanAtomicCompareExchange32(ZyanAtomic32* destination, + ZyanU32 comparand, ZyanU32 value) +{ + return (ZyanU32)(_InterlockedCompareExchange((volatile LONG*)&(destination->value), + (LONG)value, (LONG)comparand)); +} + +static ZYAN_INLINE ZyanU32 ZyanAtomicIncrement32(ZyanAtomic32* destination) +{ + return (ZyanU32)(_InterlockedIncrement((volatile LONG*)&(destination->value))); +} + +static ZYAN_INLINE ZyanU32 ZyanAtomicDecrement32(ZyanAtomic32* destination) +{ + return (ZyanU32)(_InterlockedDecrement((volatile LONG*)&(destination->value))); +} + +/* ---------------------------------------------------------------------------------------------- */ +/* 64-bit */ +/* ---------------------------------------------------------------------------------------------- */ + +static ZYAN_INLINE ZyanU64 ZyanAtomicCompareExchange64(ZyanAtomic64* destination, + ZyanU64 comparand, ZyanU64 value) +{ + return (ZyanU64)(_InterlockedCompareExchange64((volatile LONG64*)&(destination->value), + (LONG64)value, (LONG64)comparand)); +} + +static ZYAN_INLINE ZyanU64 ZyanAtomicIncrement64(ZyanAtomic64* destination) +{ + return (ZyanU64)(_InterlockedIncrement64((volatile LONG64*)&(destination->value))); +} + +static ZYAN_INLINE ZyanU64 ZyanAtomicDecrement64(ZyanAtomic64* destination) +{ + return (ZyanU64)(_InterlockedDecrement64((volatile LONG64*)&(destination->value))); +} + +/* ---------------------------------------------------------------------------------------------- */ + +#endif + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZYCORE_ATOMIC_MSVC_H */ diff --git a/include/Zycore/List.h b/include/Zycore/List.h index 015a324d..86244b88 100644 --- a/include/Zycore/List.h +++ b/include/Zycore/List.h @@ -32,7 +32,6 @@ #ifndef ZYCORE_LIST_H #define ZYCORE_LIST_H -#include #include #include #include diff --git a/include/Zycore/String.h b/include/Zycore/String.h index c3157bc3..7bffaa67 100644 --- a/include/Zycore/String.h +++ b/include/Zycore/String.h @@ -32,7 +32,6 @@ #ifndef ZYCORE_STRING_H #define ZYCORE_STRING_H -#include #include #include #include @@ -55,12 +54,12 @@ extern "C" { /** * The default growth factor for all string instances. */ -#define ZYAN_STRING_DEFAULT_GROWTH_FACTOR 2.00f +#define ZYAN_STRING_DEFAULT_GROWTH_FACTOR 2 /** * The default shrink threshold for all string instances. */ -#define ZYAN_STRING_DEFAULT_SHRINK_THRESHOLD 0.25f +#define ZYAN_STRING_DEFAULT_SHRINK_THRESHOLD 4 /* ============================================================================================== */ /* Enums and types */ @@ -71,7 +70,7 @@ extern "C" { /* ---------------------------------------------------------------------------------------------- */ /** - * Defines the `ZyanStringFlags` datatype. + * Defines the `ZyanStringFlags` data-type. */ typedef ZyanU8 ZyanStringFlags; @@ -181,8 +180,8 @@ typedef struct ZyanStringView_ /* vector */ \ { \ /* allocator */ ZYAN_NULL, \ - /* growth_factor */ 1.0f, \ - /* shrink_threshold */ 0.0f, \ + /* growth_factor */ 1, \ + /* shrink_threshold */ 0, \ /* size */ sizeof(string), \ /* capacity */ sizeof(string), \ /* element_size */ sizeof(char), \ @@ -213,7 +212,7 @@ typedef struct ZyanStringView_ * @return A zyan status code. * * The memory for the string is dynamically allocated by the default allocator using the default - * growth factor of `2.0f` and the default shrink threshold of `0.25f`. + * growth factor and the default shrink threshold. * * The allocated buffer will be at least one character larger than the given `capacity`, to reserve * space for the terminating '\0'. @@ -231,12 +230,12 @@ ZYCORE_EXPORT ZYAN_REQUIRES_LIBC ZyanStatus ZyanStringInit(ZyanString* string, Z * @param string A pointer to the `ZyanString` instance. * @param capacity The initial capacity (number of characters). * @param allocator A pointer to a `ZyanAllocator` instance. - * @param growth_factor The growth factor (from `1.0f` to `x.xf`). - * @param shrink_threshold The shrink threshold (from `0.0f` to `1.0f`). + * @param growth_factor The growth factor. + * @param shrink_threshold The shrink threshold. * * @return A zyan status code. * - * A growth factor of `1.0f` disables overallocation and a shrink threshold of `0.0f` disables + * A growth factor of `1` disables overallocation and a shrink threshold of `0` disables * dynamic shrinking. * * The allocated buffer will be at least one character larger than the given `capacity`, to reserve @@ -245,7 +244,7 @@ ZYCORE_EXPORT ZYAN_REQUIRES_LIBC ZyanStatus ZyanStringInit(ZyanString* string, Z * Finalization with `ZyanStringDestroy` is required for all strings created by this function. */ ZYCORE_EXPORT ZyanStatus ZyanStringInitEx(ZyanString* string, ZyanUSize capacity, - ZyanAllocator* allocator, float growth_factor, float shrink_threshold); + ZyanAllocator* allocator, ZyanU8 growth_factor, ZyanU8 shrink_threshold); /** * Initializes the given `ZyanString` instance and configures it to use a custom user @@ -295,7 +294,7 @@ ZYCORE_EXPORT ZyanStatus ZyanStringDestroy(ZyanString* string); * string or `destination` points to an already initialized `ZyanString` instance. * * The memory for the string is dynamically allocated by the default allocator using the default - * growth factor of `2.0f` and the default shrink threshold of `0.25f`. + * growth factor and the default shrink threshold. * * The allocated buffer will be at least one character larger than the given `capacity`, to reserve * space for the terminating '\0'. @@ -318,15 +317,15 @@ ZYCORE_EXPORT ZYAN_REQUIRES_LIBC ZyanStatus ZyanStringDuplicate(ZyanString* dest * This value is automatically adjusted to the size of the source * string, if a smaller value was passed. * @param allocator A pointer to a `ZyanAllocator` instance. - * @param growth_factor The growth factor (from `1.0f` to `x.xf`). - * @param shrink_threshold The shrink threshold (from `0.0f` to `1.0f`). + * @param growth_factor The growth factor. + * @param shrink_threshold The shrink threshold. * * @return A zyan status code. * * The behavior of this function is undefined, if `source` is a view into the `destination` * string or `destination` points to an already initialized `ZyanString` instance. * - * A growth factor of `1.0f` disables overallocation and a shrink threshold of `0.0f` disables + * A growth factor of `1` disables overallocation and a shrink threshold of `0` disables * dynamic shrinking. * * The allocated buffer will be at least one character larger than the given `capacity`, to reserve @@ -336,7 +335,7 @@ ZYCORE_EXPORT ZYAN_REQUIRES_LIBC ZyanStatus ZyanStringDuplicate(ZyanString* dest */ ZYCORE_EXPORT ZyanStatus ZyanStringDuplicateEx(ZyanString* destination, const ZyanStringView* source, ZyanUSize capacity, ZyanAllocator* allocator, - float growth_factor, float shrink_threshold); + ZyanU8 growth_factor, ZyanU8 shrink_threshold); /** * Initializes a new `ZyanString` instance by duplicating an existing string and @@ -387,7 +386,7 @@ ZYCORE_EXPORT ZyanStatus ZyanStringDuplicateCustomBuffer(ZyanString* destination * string or `destination` points to an already initialized `ZyanString` instance. * * The memory for the string is dynamically allocated by the default allocator using the default - * growth factor of `2.0f` and the default shrink threshold of `0.25f`. + * growth factor and the default shrink threshold. * * The allocated buffer will be at least one character larger than the given `capacity`, to reserve * space for the terminating '\0'. @@ -414,15 +413,15 @@ ZYCORE_EXPORT ZYAN_REQUIRES_LIBC ZyanStatus ZyanStringConcat(ZyanString* destina * This value is automatically adjusted to the combined size of the * source strings, if a smaller value was passed. * @param allocator A pointer to a `ZyanAllocator` instance. - * @param growth_factor The growth factor (from `1.0f` to `x.xf`). - * @param shrink_threshold The shrink threshold (from `0.0f` to `1.0f`). + * @param growth_factor The growth factor. + * @param shrink_threshold The shrink threshold. * * @return A zyan status code. * * The behavior of this function is undefined, if `s1` or `s2` are views into the `destination` * string or `destination` points to an already initialized `ZyanString` instance. * - * A growth factor of `1.0f` disables overallocation and a shrink threshold of `0.0f` disables + * A growth factor of `1` disables overallocation and a shrink threshold of `0` disables * dynamic shrinking. * * The allocated buffer will be at least one character larger than the given `capacity`, to reserve @@ -431,8 +430,8 @@ ZYCORE_EXPORT ZYAN_REQUIRES_LIBC ZyanStatus ZyanStringConcat(ZyanString* destina * Finalization with `ZyanStringDestroy` is required for all strings created by this function. */ ZYCORE_EXPORT ZyanStatus ZyanStringConcatEx(ZyanString* destination, const ZyanStringView* s1, - const ZyanStringView* s2, ZyanUSize capacity, ZyanAllocator* allocator, float growth_factor, - float shrink_threshold); + const ZyanStringView* s2, ZyanUSize capacity, ZyanAllocator* allocator, ZyanU8 growth_factor, + ZyanU8 shrink_threshold); /** * Initializes a new `ZyanString` instance by concatenating two existing strings and @@ -531,8 +530,8 @@ ZYCORE_EXPORT ZyanStatus ZyanStringViewGetSize(const ZyanStringView* view, ZyanU * * @warning The string is not guaranteed to be null terminated! * - * @param string A pointer to the `ZyanStringView` instance. - * @param value Receives a pointer to the C-style string. + * @param view A pointer to the `ZyanStringView` instance. + * @param buffer Receives a pointer to the C-style string. * * @return A zyan status code. */ @@ -741,7 +740,7 @@ ZYCORE_EXPORT ZyanStatus ZyanStringLPosI(const ZyanStringView* haystack, * `index`. * * @return `ZYAN_STATUS_TRUE`, if the needle was found, `ZYAN_STATUS_FALSE`, if not, or another - * zyan status code, if an error occured. + * zyan status code, if an error occurred. * * The `found_index` is set to `-1`, if the needle was not found. */ @@ -758,7 +757,7 @@ ZYCORE_EXPORT ZyanStatus ZyanStringLPosIEx(const ZyanStringView* haystack, * `needle`. * * @return `ZYAN_STATUS_TRUE`, if the needle was found, `ZYAN_STATUS_FALSE`, if not, or another - * zyan status code, if an error occured. + * zyan status code, if an error occurred. * * The `found_index` is set to `-1`, if the needle was not found. */ @@ -778,7 +777,7 @@ ZYCORE_EXPORT ZyanStatus ZyanStringRPos(const ZyanStringView* haystack, * `index`. * * @return `ZYAN_STATUS_TRUE`, if the needle was found, `ZYAN_STATUS_FALSE`, if not, or another - * zyan status code, if an error occured. + * zyan status code, if an error occurred. * * The `found_index` is set to `-1`, if the needle was not found. */ @@ -795,7 +794,7 @@ ZYCORE_EXPORT ZyanStatus ZyanStringRPosEx(const ZyanStringView* haystack, * `needle`. * * @return `ZYAN_STATUS_TRUE`, if the needle was found, `ZYAN_STATUS_FALSE`, if not, or another - * zyan status code, if an error occured. + * zyan status code, if an error occurred. * * The `found_index` is set to `-1`, if the needle was not found. */ @@ -815,7 +814,7 @@ ZYCORE_EXPORT ZyanStatus ZyanStringRPosI(const ZyanStringView* haystack, * `index`. * * @return `ZYAN_STATUS_TRUE`, if the needle was found, `ZYAN_STATUS_FALSE`, if not, or another - * zyan status code, if an error occured. + * zyan status code, if an error occurred. * * The `found_index` is set to `-1`, if the needle was not found. */ @@ -841,7 +840,7 @@ ZYCORE_EXPORT ZyanStatus ZyanStringRPosIEx(const ZyanStringView* haystack, * in `s1` than in `s2`. * * @return `ZYAN_STATUS_TRUE`, if the strings are equal, `ZYAN_STATUS_FALSE`, if not, or another - * zyan status code, if an error occured. + * zyan status code, if an error occurred. */ ZYCORE_EXPORT ZyanStatus ZyanStringCompare(const ZyanStringView* s1, const ZyanStringView* s2, ZyanI32* result); @@ -861,7 +860,7 @@ ZYCORE_EXPORT ZyanStatus ZyanStringCompare(const ZyanStringView* s1, const ZyanS * in `s1` than in `s2`. * * @return `ZYAN_STATUS_TRUE`, if the strings are equal, `ZYAN_STATUS_FALSE`, if not, or another - * zyan status code, if an error occured. + * zyan status code, if an error occurred. */ ZYCORE_EXPORT ZyanStatus ZyanStringCompareI(const ZyanStringView* s1, const ZyanStringView* s2, ZyanI32* result); diff --git a/include/Zycore/Types.h b/include/Zycore/Types.h index 74fe9056..de66b1c1 100644 --- a/include/Zycore/Types.h +++ b/include/Zycore/Types.h @@ -77,6 +77,34 @@ # else # error "Unsupported compiler for no-libc mode." # endif + +# if defined(ZYAN_MSVC) +# define ZYAN_INT8_MIN (-127i8 - 1) +# define ZYAN_INT16_MIN (-32767i16 - 1) +# define ZYAN_INT32_MIN (-2147483647i32 - 1) +# define ZYAN_INT64_MIN (-9223372036854775807i64 - 1) +# define ZYAN_INT8_MAX 127i8 +# define ZYAN_INT16_MAX 32767i16 +# define ZYAN_INT32_MAX 2147483647i32 +# define ZYAN_INT64_MAX 9223372036854775807i64 +# define ZYAN_UINT8_MAX 0xffui8 +# define ZYAN_UINT16_MAX 0xffffui16 +# define ZYAN_UINT32_MAX 0xffffffffui32 +# define ZYAN_UINT64_MAX 0xffffffffffffffffui64 +# else +# define ZYAN_INT8_MAX __INT8_MAX__ +# define ZYAN_INT8_MIN (-ZYAN_INT8_MAX - 1) +# define ZYAN_INT16_MAX __INT16_MAX__ +# define ZYAN_INT16_MIN (-ZYAN_INT16_MAX - 1) +# define ZYAN_INT32_MAX __INT32_MAX__ +# define ZYAN_INT32_MIN (-ZYAN_INT32_MAX - 1) +# define ZYAN_INT64_MAX __INT64_MAX__ +# define ZYAN_INT64_MIN (-ZYAN_INT64_MAX - 1) +# define ZYAN_UINT8_MAX __UINT8_MAX__ +# define ZYAN_UINT16_MAX __UINT16_MAX__ +# define ZYAN_UINT32_MAX __UINT32_MAX__ +# define ZYAN_UINT64_MAX __UINT64_MAX__ +# endif #else // If is LibC present, we use stdint types. # include @@ -93,6 +121,19 @@ typedef ptrdiff_t ZyanISize; typedef uintptr_t ZyanUPointer; typedef intptr_t ZyanIPointer; + +# define ZYAN_INT8_MIN INT8_MIN +# define ZYAN_INT16_MIN INT16_MIN +# define ZYAN_INT32_MIN INT32_MIN +# define ZYAN_INT64_MIN INT64_MIN +# define ZYAN_INT8_MAX INT8_MAX +# define ZYAN_INT16_MAX INT16_MAX +# define ZYAN_INT32_MAX INT32_MAX +# define ZYAN_INT64_MAX INT64_MAX +# define ZYAN_UINT8_MAX UINT8_MAX +# define ZYAN_UINT16_MAX UINT16_MAX +# define ZYAN_UINT32_MAX UINT32_MAX +# define ZYAN_UINT64_MAX UINT64_MAX #endif // Verify size assumptions. @@ -122,7 +163,7 @@ ZYAN_STATIC_ASSERT((ZyanI64)-1 >> 1 < (ZyanI64)((ZyanU64)-1 >> 1)); /** * Defines the `ZyanVoidPointer` data-type. */ -typedef char* ZyanVoidPointer; +typedef void* ZyanVoidPointer; /** * Defines the `ZyanConstVoidPointer` data-type. @@ -139,8 +180,8 @@ typedef const void* ZyanConstVoidPointer; /* Boolean */ /* ---------------------------------------------------------------------------------------------- */ -#define ZYAN_FALSE 0 -#define ZYAN_TRUE 1 +#define ZYAN_FALSE 0u +#define ZYAN_TRUE 1u /** * Defines the `ZyanBool` data-type. diff --git a/include/Zycore/Vector.h b/include/Zycore/Vector.h index 47e728cc..3bf7cbcf 100644 --- a/include/Zycore/Vector.h +++ b/include/Zycore/Vector.h @@ -32,7 +32,6 @@ #ifndef ZYCORE_VECTOR_H #define ZYCORE_VECTOR_H -#include #include #include #include @@ -56,12 +55,12 @@ extern "C" { /** * The default growth factor for all vector instances. */ -#define ZYAN_VECTOR_DEFAULT_GROWTH_FACTOR 2.00f +#define ZYAN_VECTOR_DEFAULT_GROWTH_FACTOR 2 /** * The default shrink threshold for all vector instances. */ -#define ZYAN_VECTOR_DEFAULT_SHRINK_THRESHOLD 0.25f +#define ZYAN_VECTOR_DEFAULT_SHRINK_THRESHOLD 4 /* ============================================================================================== */ /* Enums and types */ @@ -82,11 +81,11 @@ typedef struct ZyanVector_ /** * The growth factor. */ - float growth_factor; + ZyanU8 growth_factor; /** * The shrink threshold. */ - float shrink_threshold; + ZyanU8 shrink_threshold; /** * The current number of elements in the vector. */ @@ -123,8 +122,8 @@ typedef struct ZyanVector_ #define ZYAN_VECTOR_INITIALIZER \ { \ /* allocator */ ZYAN_NULL, \ - /* growth_factor */ 0.0f, \ - /* shrink_threshold */ 0.0f, \ + /* growth_factor */ 0, \ + /* shrink_threshold */ 0, \ /* size */ 0, \ /* capacity */ 0, \ /* element_size */ 0, \ @@ -223,7 +222,7 @@ typedef struct ZyanVector_ * @return A zyan status code. * * The memory for the vector elements is dynamically allocated by the default allocator using the - * default growth factor of `2.0f` and the default shrink threshold of `0.25f`. + * default growth factor and the default shrink threshold. * * Finalization with `ZyanVectorDestroy` is required for all instances created by this function. */ @@ -242,19 +241,19 @@ ZYCORE_EXPORT ZYAN_REQUIRES_LIBC ZyanStatus ZyanVectorInit(ZyanVector* vector, * @param destructor A destructor callback that is invoked every time an item is deleted, * or `ZYAN_NULL` if not needed. * @param allocator A pointer to a `ZyanAllocator` instance. - * @param growth_factor The growth factor (from `1.0f` to `x.xf`). - * @param shrink_threshold The shrink threshold (from `0.0f` to `1.0f`). + * @param growth_factor The growth factor. + * @param shrink_threshold The shrink threshold. * * @return A zyan status code. * - * A growth factor of `1.0f` disables overallocation and a shrink threshold of `0.0f` disables + * A growth factor of `1` disables overallocation and a shrink threshold of `0` disables * dynamic shrinking. * * Finalization with `ZyanVectorDestroy` is required for all instances created by this function. */ ZYCORE_EXPORT ZyanStatus ZyanVectorInitEx(ZyanVector* vector, ZyanUSize element_size, ZyanUSize capacity, ZyanMemberProcedure destructor, ZyanAllocator* allocator, - float growth_factor, float shrink_threshold); + ZyanU8 growth_factor, ZyanU8 shrink_threshold); /** * Initializes the given `ZyanVector` instance and configures it to use a custom user @@ -302,7 +301,7 @@ ZYCORE_EXPORT ZyanStatus ZyanVectorDestroy(ZyanVector* vector); * @return A zyan status code. * * The memory for the vector is dynamically allocated by the default allocator using the default - * growth factor of `2.0f` and the default shrink threshold of `0.25f`. + * growth factor and the default shrink threshold. * * Finalization with `ZyanVectorDestroy` is required for all instances created by this function. */ @@ -322,18 +321,18 @@ ZYCORE_EXPORT ZYAN_REQUIRES_LIBC ZyanStatus ZyanVectorDuplicate(ZyanVector* dest * This value is automatically adjusted to the size of the source * vector, if a smaller value was passed. * @param allocator A pointer to a `ZyanAllocator` instance. - * @param growth_factor The growth factor (from `1.0f` to `x.xf`). - * @param shrink_threshold The shrink threshold (from `0.0f` to `1.0f`). + * @param growth_factor The growth factor. + * @param shrink_threshold The shrink threshold. * * @return A zyan status code. * - * A growth factor of `1.0f` disables overallocation and a shrink threshold of `0.0f` disables + * A growth factor of `1` disables overallocation and a shrink threshold of `0` disables * dynamic shrinking. * * Finalization with `ZyanVectorDestroy` is required for all instances created by this function. */ ZYCORE_EXPORT ZyanStatus ZyanVectorDuplicateEx(ZyanVector* destination, const ZyanVector* source, - ZyanUSize capacity, ZyanAllocator* allocator, float growth_factor, float shrink_threshold); + ZyanUSize capacity, ZyanAllocator* allocator, ZyanU8 growth_factor, ZyanU8 shrink_threshold); /** * Initializes a new `ZyanVector` instance by duplicating an existing vector and @@ -365,7 +364,7 @@ ZYCORE_EXPORT ZyanStatus ZyanVectorDuplicateCustomBuffer(ZyanVector* destination * @param index The element index. * * @return A constant pointer to the desired element in the vector or `ZYAN_NULL`, if an error - * occured. + * occurred. * * Note that the returned pointer might get invalid when the vector is resized by either a manual * call to the memory-management functions or implicitly by inserting or removing elements. @@ -382,7 +381,7 @@ ZYCORE_EXPORT const void* ZyanVectorGet(const ZyanVector* vector, ZyanUSize inde * @param index The element index. * * @return A mutable pointer to the desired element in the vector or `ZYAN_NULL`, if an error - * occured. + * occurred. * * Note that the returned pointer might get invalid when the vector is resized by either a manual * call to the memory-management functions or implicitly by inserting or removing elements. @@ -576,7 +575,7 @@ ZYCORE_EXPORT ZyanStatus ZyanVectorClear(ZyanVector* vector); * @param comparison The comparison function to use. * * @return `ZYAN_STATUS_TRUE` if the element was found, `ZYAN_STATUS_FALSE` if not or a generic - * zyan status code if an error occured. + * zyan status code if an error occurred. * * The `found_index` is set to `-1`, if the element was not found. */ @@ -594,7 +593,7 @@ ZYCORE_EXPORT ZyanStatus ZyanVectorFind(const ZyanVector* vector, const void* el * @param count The maximum number of elements to iterate, beginning from the start `index`. * * @return `ZYAN_STATUS_TRUE` if the element was found, `ZYAN_STATUS_FALSE` if not or a generic - * zyan status code if an error occured. + * zyan status code if an error occurred. * * The `found_index` is set to `-1`, if the element was not found. */ @@ -611,7 +610,7 @@ ZYCORE_EXPORT ZyanStatus ZyanVectorFindEx(const ZyanVector* vector, const void* * @param comparison The comparison function to use. * * @return `ZYAN_STATUS_TRUE` if the element was found, `ZYAN_STATUS_FALSE` if not or a generic - * zyan status code if an error occured. + * zyan status code if an error occurred. * * If found, `found_index` contains the zero-based index of `element`. If not found, `found_index` * contains the index of the first entry larger than `element`. @@ -633,7 +632,7 @@ ZYCORE_EXPORT ZyanStatus ZyanVectorBinarySearch(const ZyanVector* vector, const * @param count The maximum number of elements to iterate, beginning from the start `index`. * * @return `ZYAN_STATUS_TRUE` if the element was found, `ZYAN_STATUS_FALSE` if not or a generic - * zyan status code if an error occured. + * zyan status code if an error occurred. * * If found, `found_index` contains the zero-based index of `element`. If not found, `found_index` * contains the index of the first entry larger than `element`. diff --git a/include/Zycore/Zycore.h b/include/Zycore/Zycore.h index e136acf5..adfeff03 100644 --- a/include/Zycore/Zycore.h +++ b/include/Zycore/Zycore.h @@ -32,7 +32,6 @@ #ifndef ZYCORE_H #define ZYCORE_H -#include #include // TODO: @@ -52,7 +51,7 @@ extern "C" { /** * A macro that defines the zycore version. */ -#define ZYCORE_VERSION (ZyanU64)0x0001000000000000 +#define ZYCORE_VERSION (ZyanU64)0x0001000400010000 /* ---------------------------------------------------------------------------------------------- */ /* Helper macros */ diff --git a/resources/VersionInfo.rc b/resources/VersionInfo.rc index ab8c480203634cfbb01d0aa62a4510574aee3202..6e09fd59c81b4b83adcf91e845dde2426765b0e1 100644 GIT binary patch literal 2190 zcmcIlO>^Q#5WVv&y2xdBOTpmyklLG&2AHytC`sVh7nhJmFe#yNNg@vUNBJB1WqCaa zeFIv`UeBoe>dW_k1_PppQ&y9&+pKNXVOyz&0=;dr=0u+!PK9nivs2XQ zovyQr++(*l4Sl6qWg3mhscPy1E?;P+nuBgzZEDgj?Ny_;C)zbx-KoN%vQdgmN%=l& zcFLj7P*$JlNi{73%(lyPt?M0Sl$)m$d(BKwSe+(PfvOHMAT%YE;`bI%gOMPI+}Kn8{_k(g)oq z;c!%9-?fYf3C9*vn6N_!Q|OX^mDTrj+*Z2XJA@JfeS7TS*|ITLHAg|s6)M@P%8~tQ6^d9?iv4VBep6PK6-%}0z}nW|o`@xLKIwj|-Dg!rTh*5j$x&>W81bSET94bd z!+p@WNKdA*dH<<+bm6fOlti=i&W#1hgjR91k-qS0=q6YX9lDe0B3h>ekJt^R6Oj#p74K*9%dD8pHdL}DqzbcDpPk=S5C z$-)f+&c<-=8Zu%gN?x?OkL7%k(jp3c0pnDFpF0i2IUCe@fh(5|`R>x4Gsl=B09ldj zd8SEs3&B>->f+<2G74Fb7lmnzr31Nf`VxI76XB2>%Y-X4i=(Ag%GE^>asUURp*RC^ zyfxHc7?CgB0B|_1@S^qNKN<|ae{=hCH5mMGex1=1aNY5qkM_gCV3Ry< zP+XMc5oZ)pzu^A^oNjzJ*04a>7RO5k}j#uJHSK;bloqL^|ZIZVJhY_M1Lll z29bA*)`wnG?`CL*vM$Z=y!GPr#&OIkZnopIi`{tV#+Hp6tOX4{b9h3p4zq*8Yd8D@ z1EbTW&R;{{ICE-WwRxkT`2FSpJ7GM74t|*|B^saipWz$Kgg$gKx*1JIZ%Dq$Br#YT z%%lsihf|ImAEE|omsK9xwC!ii>19EG{Yls3$(JsS~rPh5> z&dEnbRecz;YD{s=yH~21od2^TedxD}B0}FD^yRm|3!AL@)b_B5vhDxP zaJ3YrAh6M^K%mIoIsNm`>~i_Y)w$`vG*8jnKpI!!Lf5Uducf;i7U3aWhTJ^8(@b0QjIPSK zdluz3oL4-(lHRe+-&mAF|GA+AVTf?Q9_1RVw`Wyt;E9^OzE6r1fRBvig z=MsFe-ky{9mGiOMWq5O)FG8Lx&%{#QFU(i@nk$!k<=|P<@zEFkL>9Sm;W_^y?9?&p z#7>w?i(GT-0Pk|LrC+I^*S!eumX%69H7>j9MC|9`vm&I`k!qaDS8kr*yvj{nFNq&k zN9_DnD=JGzU(3U(`Kk7yXYW1kS_x&nc3xpRhW_^bg4KxUJ0ZQVWc{sLZ*64dC>+Sw zC=9g6jl&1+eM6h+Xpa4CD9JQ*w9_8wVm0rY1bM@1_CeBdIFjB(_pJ0WlwM!skD9?Z zyK3J?@1@_DFM97F{AMu@=JXk#tAhUE_uy_ zXCMS0EzY5=VGEtE*d%i@+0&DANcLSDrR=_YSH?r#oRBE$YH3b`FdWEQ`ck>|&3F z*NDjDQu8XN*!{5vo7R$hi5)mGJnKj~%^V0LEYaC;>9u#ugt5L_ePtv6KF)gEw$jMw zC+)E54bG0-DEEF&QiayXrDo9Nnu@bewnFG-@0w4>Asw96Byh_-maJe_y05QforN8B zPIGy=uJ4NbT4QtqEAm?w(R)jKX_GZiYX@FFGxB4G9^~^*)>FKT|gJ1UuYe z4QKM?9(I=YoCi1+tmakMZ&vjE{W-5$uv5A3x5DT@$C%h+Upy8<*Lzd?O!ASC?}?+T zR*cL}b7<9Zq@3*8f4Ztk%b4Nh=;tEd^=&c3>9V7a;3VL6cPrnw*1aWZ)oU}vjNaHk0g*fnBXfYo%15@%TD+;{A^E*ILYzdwO+$5 zLwEBeY=aUDyBj&j+A^wkOf~l{?FyVJpTfbh;_x-H5XOg%%+il^!vEVVt8t&-F`R<- y%YDhaXMJXM$C!%2`z4>x*(+ANb1ZLgREYWXedzte&h0x1>wCv~rTG=K3HN_k4P+(& diff --git a/src/API/Memory.c b/src/API/Memory.c index 490f5cdf..3f0c3d84 100644 --- a/src/API/Memory.c +++ b/src/API/Memory.c @@ -26,6 +26,8 @@ #include +#ifndef ZYAN_NO_LIBC + #if defined(ZYAN_WINDOWS) #elif defined(ZYAN_POSIX) @@ -126,3 +128,5 @@ ZyanStatus ZyanMemoryVirtualFree(void* address, ZyanUSize size) /* ---------------------------------------------------------------------------------------------- */ /* ============================================================================================== */ + +#endif /* ZYAN_NO_LIBC */ diff --git a/src/API/Process.c b/src/API/Process.c index dbda8d1c..88371bd4 100644 --- a/src/API/Process.c +++ b/src/API/Process.c @@ -25,14 +25,21 @@ ***************************************************************************************************/ #include -#if defined(ZYAN_WINDOWS) -# include +#include + +#ifndef ZYAN_NO_LIBC + +#if defined(ZYAN_WINDOWS) +#if defined(ZYAN_KERNEL) +# include +#else +# include +#endif #elif defined(ZYAN_POSIX) # include #else # error "Unsupported platform detected" #endif -#include /* ============================================================================================== */ /* Exported functions */ @@ -66,3 +73,5 @@ ZyanStatus ZyanProcessFlushInstructionCache(void* address, ZyanUSize size) /* ---------------------------------------------------------------------------------------------- */ /* ============================================================================================== */ + +#endif /* ZYAN_NO_LIBC */ diff --git a/src/API/Synchronization.c b/src/API/Synchronization.c index 9be79af2..48080bbc 100644 --- a/src/API/Synchronization.c +++ b/src/API/Synchronization.c @@ -26,6 +26,8 @@ #include +#ifndef ZYAN_NO_LIBC + /* ============================================================================================== */ /* Internal functions */ /* ============================================================================================== */ @@ -198,3 +200,5 @@ ZyanStatus ZyanCriticalSectionDelete(ZyanCriticalSection* critical_section) #endif /* ============================================================================================== */ + +#endif /* ZYAN_NO_LIBC */ diff --git a/src/API/Terminal.c b/src/API/Terminal.c index 376d8e12..382bd789 100644 --- a/src/API/Terminal.c +++ b/src/API/Terminal.c @@ -26,6 +26,8 @@ #include +#ifndef ZYAN_NO_LIBC + #if defined(ZYAN_POSIX) # include #elif defined(ZYAN_WINDOWS) @@ -154,3 +156,5 @@ ZyanStatus ZyanTerminalIsTTY(ZyanStandardStream stream) } /* ============================================================================================== */ + +#endif /* ZYAN_NO_LIBC */ diff --git a/src/API/Thread.c b/src/API/Thread.c index 34158c3f..0cc3d8ca 100644 --- a/src/API/Thread.c +++ b/src/API/Thread.c @@ -26,14 +26,62 @@ #include +#ifndef ZYAN_NO_LIBC + /* ============================================================================================== */ /* Internal functions */ /* ============================================================================================== */ /* ---------------------------------------------------------------------------------------------- */ -/* */ +/* Legacy Windows import declarations */ /* ---------------------------------------------------------------------------------------------- */ +#if defined(ZYAN_WINDOWS) && defined(_WIN32_WINNT) && \ + (_WIN32_WINNT >= 0x0501) && (_WIN32_WINNT < 0x0600) + +/** + * The Windows SDK conditionally declares the following prototypes: the target OS must be Vista + * (0x0600) or above. MSDN states the same incorrect minimum requirement for the Fls* functions. + * + * However, these functions exist and work perfectly fine on XP (SP3) and Server 2003. + * Preserve backward compatibility with these OSes by declaring the prototypes here if needed. + */ + +#ifndef FLS_OUT_OF_INDEXES +#define FLS_OUT_OF_INDEXES ((DWORD)0xFFFFFFFF) +#endif + +WINBASEAPI +DWORD +WINAPI +FlsAlloc( + _In_opt_ PFLS_CALLBACK_FUNCTION lpCallback + ); + +WINBASEAPI +PVOID +WINAPI +FlsGetValue( + _In_ DWORD dwFlsIndex + ); + +WINBASEAPI +BOOL +WINAPI +FlsSetValue( + _In_ DWORD dwFlsIndex, + _In_opt_ PVOID lpFlsData + ); + +WINBASEAPI +BOOL +WINAPI +FlsFree( + _In_ DWORD dwFlsIndex + ); + +#endif /* (_WIN32_WINNT >= 0x0501) && (_WIN32_WINNT < 0x0600)*/ + /* ---------------------------------------------------------------------------------------------- */ @@ -192,3 +240,5 @@ ZyanStatus ZyanThreadTlsSetValue(ZyanThreadTlsIndex index, void* data) #endif /* ============================================================================================== */ + +#endif /* ZYAN_NO_LIBC */ diff --git a/src/Bitset.c b/src/Bitset.c index 289aa69d..b1c733d6 100644 --- a/src/Bitset.c +++ b/src/Bitset.c @@ -31,8 +31,8 @@ /* Internal constants */ /* ============================================================================================== */ -#define ZYAN_BITSET_GROWTH_FACTOR 2.00f -#define ZYAN_BITSET_SHRINK_THRESHOLD 0.50f +#define ZYAN_BITSET_GROWTH_FACTOR 2 +#define ZYAN_BITSET_SHRINK_THRESHOLD 2 /* ============================================================================================== */ /* Internal macros */ @@ -56,7 +56,7 @@ * @return The amount of bytes needed to fit `x` bits. */ #define ZYAN_BITSET_BITS_TO_BYTES(x) \ - ZYAN_BITSET_CEIL((x) / 8.0f) + ZYAN_BITSET_CEIL((x) / 8) /** * Returns the offset of the given bit. @@ -140,7 +140,7 @@ ZyanStatus ZyanBitsetInit(ZyanBitset* bitset, ZyanUSize count) #endif // ZYAN_NO_LIBC ZyanStatus ZyanBitsetInitEx(ZyanBitset* bitset, ZyanUSize count, ZyanAllocator* allocator, - float growth_factor, float shrink_threshold) + ZyanU8 growth_factor, ZyanU8 shrink_threshold) { if (!bitset) { diff --git a/src/Format.c b/src/Format.c index d187d2a2..bd8e8e89 100644 --- a/src/Format.c +++ b/src/Format.c @@ -83,7 +83,7 @@ static const ZyanStringView STR_SUB = ZYAN_DEFINE_STRING_VIEW("-"); /* Decimal */ /* ---------------------------------------------------------------------------------------------- */ -#if defined(ZYAN_X86) || defined(ZYAN_ARM) || defined(ZYAN_EMSCRIPTEN) +#if defined(ZYAN_X86) || defined(ZYAN_ARM) || defined(ZYAN_EMSCRIPTEN) || defined(ZYAN_WASM) || defined(ZYAN_PPC) ZyanStatus ZyanStringAppendDecU32(ZyanString* string, ZyanU32 value, ZyanU8 padding_length) { if (!string) @@ -179,7 +179,7 @@ ZyanStatus ZyanStringAppendDecU64(ZyanString* string, ZyanU64 value, ZyanU8 padd /* Hexadecimal */ /* ---------------------------------------------------------------------------------------------- */ -#if defined(ZYAN_X86) || defined(ZYAN_ARM) || defined(ZYAN_EMSCRIPTEN) +#if defined(ZYAN_X86) || defined(ZYAN_ARM) || defined(ZYAN_EMSCRIPTEN) || defined(ZYAN_WASM) || defined(ZYAN_PPC) ZyanStatus ZyanStringAppendHexU32(ZyanString* string, ZyanU32 value, ZyanU8 padding_length, ZyanBool uppercase) { @@ -423,7 +423,7 @@ ZyanStatus ZyanStringAppendFormat(ZyanString* string, const char* format, ...) ZyanStatus ZyanStringAppendDecU(ZyanString* string, ZyanU64 value, ZyanU8 padding_length) { -#if defined(ZYAN_X64) || defined(ZYAN_AARCH64) +#if defined(ZYAN_X64) || defined(ZYAN_AARCH64) || defined(ZYAN_PPC64) || defined(ZYAN_RISCV64) return ZyanStringAppendDecU64(string, value, padding_length); #else // Working with 64-bit values is slow on non 64-bit systems @@ -464,7 +464,7 @@ ZyanStatus ZyanStringAppendDecS(ZyanString* string, ZyanI64 value, ZyanU8 paddin ZyanStatus ZyanStringAppendHexU(ZyanString* string, ZyanU64 value, ZyanU8 padding_length, ZyanBool uppercase) { -#if defined(ZYAN_X64) || defined(ZYAN_AARCH64) +#if defined(ZYAN_X64) || defined(ZYAN_AARCH64) || defined(ZYAN_PPC64) || defined(ZYAN_RISCV64) return ZyanStringAppendHexU64(string, value, padding_length, uppercase); #else // Working with 64-bit values is slow on non 64-bit systems diff --git a/src/String.c b/src/String.c index feeb04d0..9dce43f4 100644 --- a/src/String.c +++ b/src/String.c @@ -62,7 +62,7 @@ ZyanStatus ZyanStringInit(ZyanString* string, ZyanUSize capacity) #endif // ZYAN_NO_LIBC ZyanStatus ZyanStringInitEx(ZyanString* string, ZyanUSize capacity, ZyanAllocator* allocator, - float growth_factor, float shrink_threshold) + ZyanU8 growth_factor, ZyanU8 shrink_threshold) { if (!string) { @@ -133,7 +133,7 @@ ZyanStatus ZyanStringDuplicate(ZyanString* destination, const ZyanStringView* so #endif // ZYAN_NO_LIBC ZyanStatus ZyanStringDuplicateEx(ZyanString* destination, const ZyanStringView* source, - ZyanUSize capacity, ZyanAllocator* allocator, float growth_factor, float shrink_threshold) + ZyanUSize capacity, ZyanAllocator* allocator, ZyanU8 growth_factor, ZyanU8 shrink_threshold) { if (!source || !source->string.vector.size) { @@ -194,8 +194,8 @@ ZyanStatus ZyanStringConcat(ZyanString* destination, const ZyanStringView* s1, #endif // ZYAN_NO_LIBC ZyanStatus ZyanStringConcatEx(ZyanString* destination, const ZyanStringView* s1, - const ZyanStringView* s2, ZyanUSize capacity, ZyanAllocator* allocator, float growth_factor, - float shrink_threshold) + const ZyanStringView* s2, ZyanUSize capacity, ZyanAllocator* allocator, ZyanU8 growth_factor, + ZyanU8 shrink_threshold) { if (!s1 || !s2 || !s1->string.vector.size || !s2->string.vector.size) { diff --git a/src/Vector.c b/src/Vector.c index 6b8d67c4..f92c9de0 100644 --- a/src/Vector.c +++ b/src/Vector.c @@ -52,7 +52,7 @@ * @return `ZYAN_TRUE`, if the vector should shrink or `ZYAN_FALSE`, if not. */ #define ZYCORE_VECTOR_SHOULD_SHRINK(size, capacity, threshold) \ - ((size) < (capacity) * (threshold)) + (((threshold) != 0) && ((size) * (threshold) < (capacity))) /** * Returns the offset of the element at the given `index`. @@ -119,8 +119,7 @@ static ZyanStatus ZyanVectorReallocate(ZyanVector* vector, ZyanUSize capacity) } /** - * Shifts all elements starting at the specified `index` by the amount of - * `count` to the left. + * Shifts all elements starting at the specified `index` by the amount of `count` to the left. * * @param vector A pointer to the `ZyanVector` instance. * @param index The start index. @@ -136,17 +135,16 @@ static ZyanStatus ZyanVectorShiftLeft(ZyanVector* vector, ZyanUSize index, ZyanU ZYAN_ASSERT(count > 0); //ZYAN_ASSERT((ZyanISize)count - (ZyanISize)index + 1 >= 0); - void* const source = ZYCORE_VECTOR_OFFSET(vector, index + count); - void* const dest = ZYCORE_VECTOR_OFFSET(vector, index); - const ZyanUSize size = (vector->size - index - count) * vector->element_size; + const void* const source = ZYCORE_VECTOR_OFFSET(vector, index + count); + void* const dest = ZYCORE_VECTOR_OFFSET(vector, index); + const ZyanUSize size = (vector->size - index - count) * vector->element_size; ZYAN_MEMMOVE(dest, source, size); return ZYAN_STATUS_SUCCESS; } /** - * Shifts all elements starting at the specified `index` by the amount of - * `count` to the right. + * Shifts all elements starting at the specified `index` by the amount of `count` to the right. * * @param vector A pointer to the `ZyanVector` instance. * @param index The start index. @@ -162,9 +160,9 @@ static ZyanStatus ZyanVectorShiftRight(ZyanVector* vector, ZyanUSize index, Zyan ZYAN_ASSERT(count > 0); ZYAN_ASSERT(vector->size + count <= vector->capacity); - void* const source = ZYCORE_VECTOR_OFFSET(vector, index); - void* const dest = ZYCORE_VECTOR_OFFSET(vector, index + count); - const ZyanUSize size = (vector->size - index) * vector->element_size; + const void* const source = ZYCORE_VECTOR_OFFSET(vector, index); + void* const dest = ZYCORE_VECTOR_OFFSET(vector, index + count); + const ZyanUSize size = (vector->size - index) * vector->element_size; ZYAN_MEMMOVE(dest, source, size); return ZYAN_STATUS_SUCCESS; @@ -192,11 +190,10 @@ ZyanStatus ZyanVectorInit(ZyanVector* vector, ZyanUSize element_size, ZyanUSize #endif // ZYAN_NO_LIBC ZyanStatus ZyanVectorInitEx(ZyanVector* vector, ZyanUSize element_size, ZyanUSize capacity, - ZyanMemberProcedure destructor, ZyanAllocator* allocator, float growth_factor, - float shrink_threshold) + ZyanMemberProcedure destructor, ZyanAllocator* allocator, ZyanU8 growth_factor, + ZyanU8 shrink_threshold) { - if (!vector || !element_size || !allocator || (growth_factor < 1.0f) || - (shrink_threshold < 0.0f) || (shrink_threshold > 1.0f)) + if (!vector || !element_size || !allocator || (growth_factor < 1)) { return ZYAN_STATUS_INVALID_ARGUMENT; } @@ -225,8 +222,8 @@ ZyanStatus ZyanVectorInitCustomBuffer(ZyanVector* vector, ZyanUSize element_size } vector->allocator = ZYAN_NULL; - vector->growth_factor = 1.0f; - vector->shrink_threshold = 0.0f; + vector->growth_factor = 1; + vector->shrink_threshold = 0; vector->size = 0; vector->capacity = capacity; vector->element_size = element_size; @@ -281,7 +278,7 @@ ZyanStatus ZyanVectorDuplicate(ZyanVector* destination, const ZyanVector* source #endif // ZYAN_NO_LIBC ZyanStatus ZyanVectorDuplicateEx(ZyanVector* destination, const ZyanVector* source, - ZyanUSize capacity, ZyanAllocator* allocator, float growth_factor, float shrink_threshold) + ZyanUSize capacity, ZyanAllocator* allocator, ZyanU8 growth_factor, ZyanU8 shrink_threshold) { if (!source) { @@ -774,8 +771,9 @@ ZyanStatus ZyanVectorResizeEx(ZyanVector* vector, ZyanUSize size, const void* in if (ZYCORE_VECTOR_SHOULD_GROW(size, vector->capacity) || ZYCORE_VECTOR_SHOULD_SHRINK(size, vector->capacity, vector->shrink_threshold)) { + ZYAN_ASSERT(vector->growth_factor >= 1); ZYAN_CHECK(ZyanVectorReallocate(vector, (ZyanUSize)(size * vector->growth_factor))); - }; + } if (initializer && (size > vector->size)) { diff --git a/tests/Vector.cpp b/tests/Vector.cpp index ade6b09f..26fbb6d0 100644 --- a/tests/Vector.cpp +++ b/tests/Vector.cpp @@ -146,8 +146,8 @@ TEST(VectorTest, InitBasic) ASSERT_EQ(ZyanVectorInit(&vector, sizeof(ZyanU64), 0, reinterpret_cast(ZYAN_NULL)), ZYAN_STATUS_SUCCESS); EXPECT_EQ(vector.allocator, ZyanAllocatorDefault()); - EXPECT_FLOAT_EQ(vector.growth_factor, ZYAN_VECTOR_DEFAULT_GROWTH_FACTOR); - EXPECT_FLOAT_EQ(vector.shrink_threshold, ZYAN_VECTOR_DEFAULT_SHRINK_THRESHOLD); + EXPECT_EQ(vector.growth_factor, ZYAN_VECTOR_DEFAULT_GROWTH_FACTOR); + EXPECT_EQ(vector.shrink_threshold, ZYAN_VECTOR_DEFAULT_SHRINK_THRESHOLD); EXPECT_EQ(vector.size, static_cast(0)); EXPECT_EQ(vector.capacity, static_cast(ZYAN_VECTOR_MIN_CAPACITY)); EXPECT_EQ(vector.element_size, sizeof(ZyanU64)); @@ -166,11 +166,11 @@ TEST(VectorTest, InitAdvanced) ZyanVector vector; ASSERT_EQ(ZyanVectorInitEx(&vector, sizeof(ZyanU16), 0, - reinterpret_cast(ZYAN_NULL), ZyanAllocatorDefault(), 1.0f, 0.0f), + reinterpret_cast(ZYAN_NULL), ZyanAllocatorDefault(), 1, 0), ZYAN_STATUS_SUCCESS); EXPECT_EQ(vector.allocator, ZyanAllocatorDefault()); - EXPECT_FLOAT_EQ(vector.growth_factor, 1.0f); - EXPECT_FLOAT_EQ(vector.shrink_threshold, 0.0f); + EXPECT_EQ(vector.growth_factor, 1); + EXPECT_EQ(vector.shrink_threshold, 0); EXPECT_EQ(vector.size, static_cast(0)); EXPECT_EQ(vector.capacity, static_cast(ZYAN_VECTOR_MIN_CAPACITY)); EXPECT_EQ(vector.element_size, sizeof(ZyanU16)); @@ -179,7 +179,7 @@ TEST(VectorTest, InitAdvanced) // Custom capacity EXPECT_EQ(ZyanVectorInitEx(&vector, sizeof(ZyanU16), 10, - reinterpret_cast(ZYAN_NULL), ZyanAllocatorDefault(), 1.0f, 0.0f), + reinterpret_cast(ZYAN_NULL), ZyanAllocatorDefault(), 1, 0), ZYAN_STATUS_SUCCESS); EXPECT_EQ(vector.capacity, static_cast(ZYAN_MAX(ZYAN_VECTOR_MIN_CAPACITY, 10))); EXPECT_EQ(ZyanVectorDestroy(&vector), ZYAN_STATUS_SUCCESS); @@ -196,8 +196,8 @@ TEST(VectorTest, InitCustomBuffer) ZYAN_ARRAY_LENGTH(buffer), reinterpret_cast(ZYAN_NULL)), ZYAN_STATUS_SUCCESS); EXPECT_EQ(vector.allocator, ZYAN_NULL); - EXPECT_FLOAT_EQ(vector.growth_factor, 1.0f); - EXPECT_FLOAT_EQ(vector.shrink_threshold, 0.0f); + EXPECT_EQ(vector.growth_factor, 1); + EXPECT_EQ(vector.shrink_threshold, 0); EXPECT_EQ(vector.size, static_cast(0)); EXPECT_EQ(vector.capacity, ZYAN_ARRAY_LENGTH(buffer)); EXPECT_EQ(vector.element_size, sizeof(ZyanU16)); @@ -249,6 +249,40 @@ TEST(VectorTest, Destructor) } } +TEST(VectorTest, TestGrowingAndShrinking) +{ + ZyanVector vector; + + ASSERT_EQ(ZyanVectorInit(&vector, sizeof(ZyanU64), 0, + reinterpret_cast(ZYAN_NULL)), ZYAN_STATUS_SUCCESS); + + for (ZyanU64 i = 0; i < 100; ++i) + { + ZyanUSize expected_capacity = vector.capacity; + if (expected_capacity < (i + 1)) + { + expected_capacity = (expected_capacity + 1) * vector.growth_factor; + } + ASSERT_EQ(ZyanVectorPushBack(&vector, &i), ZYAN_STATUS_SUCCESS); + ASSERT_EQ(vector.capacity, expected_capacity); + } + + for (ZyanU64 i = 100; i > 0; --i) + { + const auto index = static_cast(i - 1); + + ZyanUSize expected_capacity = vector.capacity; + if ((vector.shrink_threshold != 0) && (index * vector.shrink_threshold < vector.capacity)) + { + expected_capacity = ZYAN_MAX(1, (ZyanUSize)(index * vector.growth_factor)); + } + ASSERT_EQ(ZyanVectorDelete(&vector, index), ZYAN_STATUS_SUCCESS); + ASSERT_EQ(vector.capacity, expected_capacity); + } + + EXPECT_EQ(ZyanVectorDestroy(&vector), ZYAN_STATUS_SUCCESS); +} + TEST_P(VectorTestFilled, ElementAccess) { static const ZyanU64 element_in = 1337;