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 ab8c4802..6e09fd59 100644 Binary files a/resources/VersionInfo.rc and b/resources/VersionInfo.rc differ 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;