├── .github ├── FUNDING.yml └── workflows │ └── main.yml ├── .gitignore ├── CMakeLists.txt ├── CMakeLists.txt.in ├── Doxyfile.in ├── LICENSE ├── README.md ├── cmake ├── zyan-functions.cmake └── zycore-config.cmake.in ├── examples ├── String.c ├── Vector.c └── meson.build ├── include └── Zycore │ ├── API │ ├── Memory.h │ ├── Process.h │ ├── Synchronization.h │ ├── Terminal.h │ └── Thread.h │ ├── Allocator.h │ ├── ArgParse.h │ ├── Atomic.h │ ├── Bitset.h │ ├── Comparison.h │ ├── Defines.h │ ├── Format.h │ ├── Internal │ ├── AtomicGNU.h │ └── AtomicMSVC.h │ ├── LibC.h │ ├── List.h │ ├── Object.h │ ├── Status.h │ ├── String.h │ ├── Types.h │ ├── Vector.h │ └── Zycore.h ├── meson.build ├── meson_options.txt ├── resources └── VersionInfo.rc ├── src ├── API │ ├── Memory.c │ ├── Process.c │ ├── Synchronization.c │ ├── Terminal.c │ └── Thread.c ├── Allocator.c ├── ArgParse.c ├── Bitset.c ├── Format.c ├── List.c ├── String.c ├── Vector.c └── Zycore.c ├── subprojects └── gtest.wrap └── tests ├── ArgParse.cpp ├── String.cpp ├── Vector.cpp └── meson.build /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: flobernd -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: GitHub Actions CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | types: [opened, synchronize, reopened] 9 | 10 | jobs: 11 | build-linux-cmake: 12 | name: CMake Build ${{ matrix.platform.name }} ${{ matrix.compiler.name }} ${{ matrix.flavor }} (${{ matrix.mode.name }}) 13 | runs-on: ubuntu-22.04 14 | 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | platform: 19 | - { name: x86, flags: "-m32" } 20 | - { name: x64, flags: "-m64" } 21 | compiler: 22 | - { name: GNU, CC: gcc, CXX: g++ } 23 | - { name: LLVM, CC: clang, CXX: clang++ } 24 | flavor: 25 | - Debug 26 | - Release 27 | mode: 28 | - { name: default, args: "" } 29 | - { name: NO_LIBC, args: -DZYAN_NO_LIBC=ON } 30 | 31 | steps: 32 | - name: Checkout 33 | uses: actions/checkout@v4 34 | 35 | - if: matrix.platform.name == 'x86' 36 | name: Bootstrap 37 | run: | 38 | sudo dpkg --add-architecture i386 39 | sudo rm /etc/apt/sources.list.d/* && sudo apt-get update 40 | sudo apt-get install -y g++-multilib g++ 41 | 42 | - name: Configure 43 | env: 44 | CC: ${{ matrix.compiler.CC }} 45 | CXX: ${{ matrix.compiler.CXX }} 46 | run: | 47 | mkdir build 48 | cd build 49 | cmake -DCMAKE_C_FLAGS=${{ matrix.platform.flags }} -DCMAKE_CXX_FLAGS=${{ matrix.platform.flags }} -DZYAN_DEV_MODE=ON ${{ matrix.mode.args }} .. 50 | 51 | - name: Build 52 | run: | 53 | cmake --build build --config ${{ matrix.flavor }} 54 | 55 | build-linux-meson: 56 | name: Meson Build ${{ matrix.platform.name }} ${{ matrix.compiler.name }} ${{ matrix.flavor }} (${{ matrix.mode.name }}) 57 | runs-on: ubuntu-22.04 58 | 59 | strategy: 60 | fail-fast: false 61 | matrix: 62 | platform: 63 | - { name: x86, flags: "-m32" } 64 | - { name: x64, flags: "-m64" } 65 | compiler: 66 | - { name: GNU, CC: gcc, CXX: g++ } 67 | - { name: LLVM, CC: clang, CXX: clang++ } 68 | flavor: 69 | - debug 70 | - release 71 | mode: 72 | - { name: default, args: -Dtests=enabled } 73 | - { name: NO_LIBC, args: -Dnolibc=true } 74 | 75 | steps: 76 | - name: Setup meson 77 | run: | 78 | pipx install meson 79 | sudo apt-get install -y ninja-build 80 | 81 | - name: Checkout 82 | uses: actions/checkout@v4 83 | 84 | - if: matrix.platform.name == 'x86' 85 | name: Bootstrap 86 | run: | 87 | sudo dpkg --add-architecture i386 88 | sudo rm /etc/apt/sources.list.d/* && sudo apt-get update 89 | sudo apt-get install -y g++-multilib g++ 90 | 91 | - name: Configure 92 | env: 93 | CC: ${{ matrix.compiler.CC }} 94 | CXX: ${{ matrix.compiler.CXX }} 95 | run: | 96 | meson setup build-${{ matrix.flavor }} --buildtype=${{ matrix.flavor }} ${{ matrix.mode.args }} -Dc_extra_args="${{ matrix.platform.flags }}" -Dcpp_extra_args="${{ matrix.platform.flags }}" 97 | 98 | - name: Build 99 | run: | 100 | meson compile -C build-${{ matrix.flavor }} 101 | 102 | - name: Run tests 103 | run: | 104 | meson test -C build-${{ matrix.flavor }} 105 | 106 | build-windows-cmake: 107 | name: CMake Build ${{ matrix.platform.name }} ${{ matrix.compiler.name }} ${{ matrix.flavor }} (${{ matrix.mode.name }}) 108 | runs-on: windows-latest 109 | 110 | strategy: 111 | fail-fast: false 112 | matrix: 113 | platform: 114 | - { name: x86, flags: "Win32" } 115 | - { name: x64, flags: "x64" } 116 | compiler: 117 | - { name: MSVC } 118 | flavor: 119 | - Debug 120 | - Release 121 | mode: 122 | - { name: default, args: "" } 123 | - { name: NO_LIBC, args: -DZYAN_NO_LIBC=ON } 124 | 125 | steps: 126 | - name: Checkout 127 | uses: actions/checkout@v4 128 | 129 | - name: Configure 130 | run: | 131 | mkdir build 132 | cd build 133 | cmake -DCMAKE_GENERATOR_PLATFORM=${{ matrix.platform.flags }} -DZYAN_DEV_MODE=ON ${{ matrix.mode.args }} .. 134 | 135 | - name: Build 136 | run: | 137 | cmake --build build --config ${{ matrix.flavor }} 138 | 139 | build-windows-meson: 140 | name: Meson Build ${{ matrix.platform.name }} ${{ matrix.compiler.name }} ${{ matrix.flavor }} (${{ matrix.mode.name }}) 141 | runs-on: windows-latest 142 | 143 | strategy: 144 | fail-fast: false 145 | matrix: 146 | platform: 147 | - { name: x86, flags: "amd64_x86" } 148 | - { name: x64, flags: "amd64" } 149 | compiler: 150 | - { name: MSVC } 151 | flavor: 152 | - debug 153 | - release 154 | mode: 155 | - { name: default, args: -Dtests=enabled } 156 | - { name: NO_LIBC, args: -Dnolibc=true } 157 | 158 | steps: 159 | - name: Setup meson 160 | run: | 161 | pipx install meson 162 | choco install ninja 163 | 164 | - name: Checkout 165 | uses: actions/checkout@v4 166 | 167 | - name: Configure 168 | run: | 169 | $VCPATH = vswhere -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath -latest 170 | & $VCPATH\VC\Auxiliary\Build\vcvarsall.bat ${{ matrix.platform.flags }} 171 | meson setup build-${{ matrix.flavor }} --buildtype=${{ matrix.flavor }} ${{ matrix.mode.args }} 172 | 173 | - name: Build 174 | run: | 175 | meson compile -C build-${{ matrix.flavor }} 176 | 177 | - name: Run tests 178 | run: | 179 | meson test -C build-${{ matrix.flavor }} 180 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.gitignore.io/api/c,c++,cmake 2 | 3 | ### C ### 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Libraries 15 | *.lib 16 | *.a 17 | *.la 18 | *.lo 19 | 20 | # Shared objects (inc. Windows DLLs) 21 | *.dll 22 | *.so 23 | *.so.* 24 | *.dylib 25 | 26 | # Executables 27 | *.exe 28 | *.out 29 | *.app 30 | *.i*86 31 | *.x86_64 32 | *.hex 33 | 34 | # Debug files 35 | *.dSYM/ 36 | *.su 37 | 38 | 39 | ### C++ ### 40 | # Compiled Object files 41 | *.slo 42 | *.lo 43 | *.o 44 | *.obj 45 | 46 | # Precompiled Headers 47 | *.gch 48 | *.pch 49 | 50 | # Compiled Dynamic libraries 51 | *.so 52 | *.dylib 53 | *.dll 54 | 55 | # Fortran module files 56 | *.mod 57 | 58 | # Compiled Static libraries 59 | *.lai 60 | *.la 61 | *.a 62 | *.lib 63 | 64 | # Executables 65 | *.exe 66 | *.out 67 | *.app 68 | 69 | 70 | ### CMake ### 71 | CMakeCache.txt 72 | CMakeFiles 73 | CMakeScripts 74 | Makefile 75 | cmake_install.cmake 76 | install_manifest.txt 77 | CTestTestfile.cmake 78 | 79 | 80 | # MacOS 81 | .DS_Store 82 | 83 | build* 84 | 85 | # MSVC 86 | .vs 87 | *.vcxproj.user 88 | *.suo 89 | *.sdf 90 | *.opensdf 91 | *.VC.db 92 | *.VC.opendb 93 | msvc/**/obj/ 94 | msvc/**/bin/ 95 | 96 | doc/html 97 | 98 | /.vscode 99 | /.idea 100 | /cmake-build-* 101 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | if (TARGET Zycore) 2 | return() 3 | endif () 4 | 5 | cmake_minimum_required(VERSION 3.10 FATAL_ERROR) 6 | 7 | if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.15") 8 | # Enable runtime library selection via CMAKE_MSVC_RUNTIME_LIBRARY 9 | cmake_policy(SET CMP0091 NEW) 10 | endif () 11 | 12 | project(Zycore VERSION 1.5.2.0 LANGUAGES C) 13 | 14 | include(GNUInstallDirs) 15 | include(CMakePackageConfigHelpers) 16 | 17 | # =============================================================================================== # 18 | # Overridable options # 19 | # =============================================================================================== # 20 | 21 | # Global configuration 22 | option(ZYAN_WHOLE_PROGRAM_OPTIMIZATION 23 | "Enable whole program optimization (all targets)" 24 | OFF) 25 | option(ZYAN_NO_LIBC 26 | "Don't use any C standard library functions (for exotic build-envs like kernel drivers)" 27 | OFF) 28 | option(ZYAN_DEV_MODE 29 | "Enable developer mode (-Wall, -Werror, ...)" 30 | OFF) 31 | option(ZYAN_FORCE_ASSERTS 32 | "Forces asserts in release builds." 33 | OFF) 34 | 35 | # Build configuration 36 | option(ZYCORE_BUILD_SHARED_LIB 37 | "Build shared library" 38 | OFF) 39 | option(ZYCORE_BUILD_EXAMPLES 40 | "Build examples" 41 | OFF) 42 | option(ZYCORE_BUILD_TESTS 43 | "Build tests" 44 | OFF) 45 | 46 | # =============================================================================================== # 47 | # Forced assertions hack # 48 | # =============================================================================================== # 49 | 50 | # The code for this is adapted from how LLVM forces asserts. 51 | if (ZYAN_FORCE_ASSERTS) 52 | set(vars 53 | CMAKE_CXX_FLAGS_RELEASE 54 | CMAKE_CXX_FLAGS_RELWITHDEBINFO 55 | CMAKE_CXX_FLAGS_MINSIZEREL 56 | CMAKE_C_FLAGS_RELEASE 57 | CMAKE_C_FLAGS_RELWITHDEBINFO 58 | CMAKE_C_FLAGS_MINSIZEREL) 59 | 60 | foreach (var ${vars}) 61 | string (REGEX REPLACE "(^| )[/-]D *NDEBUG($| )" " " "${var}" "${${var}}") 62 | set("${var}" "${${var}} -UNDEBUG" CACHE STRING "" FORCE) 63 | endforeach() 64 | endif () 65 | 66 | # =============================================================================================== # 67 | # GoogleTest # 68 | # =============================================================================================== # 69 | 70 | # Search for GoogleTest, and fallback to downloading it if not found 71 | if (ZYCORE_BUILD_TESTS) 72 | find_package(GTest QUIET) 73 | if (GTest_FOUND) 74 | # CMake 3.20 and upstream GTestConfig.cmake 75 | if (TARGET GTest::gtest) 76 | add_library(gtest ALIAS GTest::gtest) 77 | # Older FindGTest 78 | else () 79 | add_library(gtest ALIAS GTest::GTest) 80 | endif () 81 | else () 82 | if (NOT DEFINED ZYCORE_DOWNLOADED_GTEST) 83 | configure_file("CMakeLists.txt.in" "${CMAKE_BINARY_DIR}/gtest/download/CMakeLists.txt") 84 | execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . 85 | RESULT_VARIABLE result 86 | WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/gtest/download") 87 | if (result) 88 | message(FATAL_ERROR "CMake step for googletest failed: ${result}") 89 | endif() 90 | execute_process(COMMAND ${CMAKE_COMMAND} --build . 91 | RESULT_VARIABLE result 92 | WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/gtest/download") 93 | if (result) 94 | message(FATAL_ERROR "Build step for googletest failed: ${result}") 95 | endif() 96 | 97 | set(ZYCORE_DOWNLOADED_GTEST TRUE CACHE BOOL "") 98 | mark_as_advanced(ZYCORE_DOWNLOADED_GTEST) 99 | endif () 100 | 101 | set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) 102 | 103 | add_subdirectory("${CMAKE_BINARY_DIR}/gtest/src" "${CMAKE_BINARY_DIR}/gtest/build" 104 | EXCLUDE_FROM_ALL) 105 | endif () 106 | endif () 107 | 108 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") 109 | include(zyan-functions) 110 | 111 | # =============================================================================================== # 112 | # Library configuration # 113 | # =============================================================================================== # 114 | 115 | if (ZYCORE_BUILD_SHARED_LIB) 116 | add_library("Zycore" SHARED) 117 | else () 118 | add_library("Zycore" STATIC) 119 | target_compile_definitions("Zycore" PUBLIC "ZYCORE_STATIC_BUILD") 120 | endif () 121 | add_library("Zycore::Zycore" ALIAS "Zycore") 122 | 123 | set_target_properties("Zycore" PROPERTIES 124 | LINKER_LANGUAGE C 125 | VERSION "${Zycore_VERSION}" 126 | SOVERSION "${Zycore_VERSION_MAJOR}.${Zycore_VERSION_MINOR}" 127 | DEFINE_SYMBOL "ZYCORE_SHOULD_EXPORT" 128 | C_VISIBILITY_PRESET hidden) 129 | target_include_directories("Zycore" 130 | PUBLIC 131 | $ 132 | $ 133 | $ 134 | PRIVATE "src") 135 | target_compile_definitions("Zycore" PRIVATE "_CRT_SECURE_NO_WARNINGS") 136 | zyan_set_common_flags("Zycore") 137 | zyan_maybe_enable_wpo("Zycore") 138 | 139 | if (ZYAN_NO_LIBC) 140 | target_compile_definitions("Zycore" PUBLIC "ZYAN_NO_LIBC") 141 | if (UNIX) 142 | set_target_properties("Zycore" PROPERTIES LINK_FLAGS "-nostdlib -nodefaultlibs") 143 | endif () 144 | endif () 145 | 146 | target_sources("Zycore" 147 | PRIVATE 148 | # API 149 | "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/API/Memory.h" 150 | "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/API/Process.h" 151 | "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/API/Synchronization.h" 152 | "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/API/Terminal.h" 153 | "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/API/Thread.h" 154 | # Common 155 | "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/Allocator.h" 156 | "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/ArgParse.h" 157 | "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/Atomic.h" 158 | "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/Bitset.h" 159 | "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/Comparison.h" 160 | "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/Defines.h" 161 | "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/Format.h" 162 | "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/LibC.h" 163 | "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/List.h" 164 | "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/Object.h" 165 | "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/Status.h" 166 | "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/String.h" 167 | "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/Types.h" 168 | "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/Vector.h" 169 | "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/Zycore.h" 170 | "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/Internal/AtomicGNU.h" 171 | "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/Internal/AtomicMSVC.h" 172 | # API 173 | "src/API/Memory.c" 174 | "src/API/Process.c" 175 | "src/API/Synchronization.c" 176 | "src/API/Terminal.c" 177 | "src/API/Thread.c" 178 | # Common 179 | "src/Allocator.c" 180 | "src/ArgParse.c" 181 | "src/Bitset.c" 182 | "src/Format.c" 183 | "src/List.c" 184 | "src/String.c" 185 | "src/Vector.c" 186 | "src/Zycore.c") 187 | 188 | if (ZYCORE_BUILD_SHARED_LIB AND WIN32) 189 | target_sources("Zycore" PRIVATE "resources/VersionInfo.rc") 190 | endif () 191 | 192 | zyan_set_source_group("Zycore") 193 | 194 | if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" AND NOT ZYAN_NO_LIBC) 195 | target_compile_definitions("Zycore" PRIVATE "_GNU_SOURCE") 196 | set(THREADS_PREFER_PTHREAD_FLAG ON) 197 | find_package(Threads REQUIRED) 198 | target_link_libraries("Zycore" Threads::Threads) 199 | endif () 200 | 201 | configure_package_config_file(cmake/zycore-config.cmake.in 202 | "${CMAKE_CURRENT_BINARY_DIR}/zycore-config.cmake" 203 | INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/zycore" 204 | ) 205 | write_basic_package_version_file( 206 | "${CMAKE_CURRENT_BINARY_DIR}/zycore-config-version.cmake" 207 | COMPATIBILITY SameMajorVersion 208 | ) 209 | install(FILES 210 | "cmake/zyan-functions.cmake" 211 | "${CMAKE_CURRENT_BINARY_DIR}/zycore-config.cmake" 212 | "${CMAKE_CURRENT_BINARY_DIR}/zycore-config-version.cmake" 213 | DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/zycore" 214 | ) 215 | 216 | install(TARGETS "Zycore" EXPORT "zycore-targets" 217 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} 218 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 219 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} 220 | ) 221 | 222 | install(EXPORT "zycore-targets" 223 | NAMESPACE "Zycore::" 224 | DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/zycore") 225 | install(DIRECTORY "include/" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) 226 | 227 | # =============================================================================================== # 228 | # Doxygen documentation # 229 | # =============================================================================================== # 230 | 231 | find_package(Doxygen) 232 | if (DOXYGEN_FOUND) 233 | set(DOXYGEN_GENERATE_MAN YES) 234 | doxygen_add_docs(ZycoreDoc "include/Zycore/" ALL) 235 | install( 236 | DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/html/" 237 | DESTINATION "${CMAKE_INSTALL_DOCDIR}/api" 238 | COMPONENT Documentation 239 | ) 240 | install( 241 | DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/man/man3/" 242 | DESTINATION "${CMAKE_INSTALL_MANDIR}/man3" 243 | COMPONENT Documentation 244 | ) 245 | endif() 246 | 247 | # =============================================================================================== # 248 | # Developer mode # 249 | # =============================================================================================== # 250 | 251 | if (ZYAN_DEV_MODE) 252 | set_property(GLOBAL PROPERTY USE_FOLDERS ON) 253 | endif () 254 | 255 | # =============================================================================================== # 256 | # Examples # 257 | # =============================================================================================== # 258 | 259 | if (ZYCORE_BUILD_EXAMPLES) 260 | add_executable("String" "examples/String.c") 261 | zyan_set_common_flags("String" "Zycore") 262 | target_link_libraries("String" "Zycore") 263 | set_target_properties("String" PROPERTIES FOLDER "Examples") 264 | target_compile_definitions("String" PRIVATE "_CRT_SECURE_NO_WARNINGS") 265 | zyan_maybe_enable_wpo("String") 266 | 267 | add_executable("Vector" "examples/Vector.c") 268 | zyan_set_common_flags("Vector" "Zycore") 269 | target_link_libraries("Vector" "Zycore") 270 | set_target_properties("Vector" PROPERTIES FOLDER "Examples") 271 | target_compile_definitions("Vector" PRIVATE "_CRT_SECURE_NO_WARNINGS") 272 | zyan_maybe_enable_wpo("Vector") 273 | endif () 274 | 275 | # =============================================================================================== # 276 | # Tests # 277 | # =============================================================================================== # 278 | 279 | function (zyan_add_test test) 280 | add_executable("Test${test}" "tests/${test}.cpp") 281 | target_link_libraries("Test${test}" "Zycore" "gtest") 282 | set_target_properties("Test${test}" PROPERTIES 283 | LANGUAGE CXX 284 | CXX_STANDARD 17 285 | CXX_EXTENSIONS OFF 286 | CXX_STANDARD_REQUIRED ON 287 | FOLDER "Tests" 288 | ) 289 | target_compile_definitions("Test${test}" PRIVATE "_CRT_SECURE_NO_WARNINGS") 290 | zyan_maybe_enable_wpo("Test${test}") 291 | add_test("${test}" "Test${test}") 292 | endfunction () 293 | 294 | if (ZYCORE_BUILD_TESTS) 295 | enable_language(CXX) 296 | enable_testing() 297 | zyan_add_test("String") 298 | zyan_add_test("Vector") 299 | zyan_add_test("ArgParse") 300 | endif () 301 | 302 | # =============================================================================================== # 303 | -------------------------------------------------------------------------------- /CMakeLists.txt.in: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10 FATAL_ERROR) 2 | 3 | project(googletest-download NONE) 4 | 5 | include(ExternalProject) 6 | ExternalProject_Add(googletest 7 | GIT_REPOSITORY https://github.com/google/googletest.git 8 | GIT_TAG v1.17.0 9 | SOURCE_DIR "${CMAKE_BINARY_DIR}/gtest/src" 10 | BINARY_DIR "${CMAKE_BINARY_DIR}/gtest/build" 11 | CONFIGURE_COMMAND "" 12 | BUILD_COMMAND "" 13 | INSTALL_COMMAND "" 14 | TEST_COMMAND "" 15 | ) 16 | -------------------------------------------------------------------------------- /Doxyfile.in: -------------------------------------------------------------------------------- 1 | PROJECT_NAME = Zycore 2 | PROJECT_NUMBER = @VERSION@ 3 | PROJECT_BRIEF = "Zyan Core Library for C" 4 | OUTPUT_DIRECTORY = "@TOP_BUILDDIR@/doc" 5 | STRIP_FROM_PATH = "@TOP_SRCDIR@" 6 | JAVADOC_AUTOBRIEF = YES 7 | QT_AUTOBRIEF = YES 8 | OPTIMIZE_OUTPUT_FOR_C = YES 9 | TOC_INCLUDE_HEADINGS = 0 10 | EXTRACT_ALL = YES 11 | EXTRACT_LOCAL_CLASSES = NO 12 | HIDE_SCOPE_NAMES = YES 13 | INPUT = "@TOP_SRCDIR@/include" \ 14 | "@TOP_SRCDIR@/README.md" 15 | RECURSIVE = YES 16 | EXAMPLE_PATH = "@TOP_SRCDIR@/examples" 17 | USE_MDFILE_AS_MAINPAGE = "@TOP_SRCDIR@/README.md" 18 | GENERATE_TREEVIEW = YES 19 | USE_MATHJAX = YES 20 | MATHJAX_VERSION = MathJax_3 21 | GENERATE_LATEX = NO 22 | MACRO_EXPANSION = YES 23 | PREDEFINED = @PREDEFINED@ 24 | DOT_COMMON_ATTR = "fontname=\"sans-serif\",fontsize=10" 25 | DOT_EDGE_ATTR = "labelfontname=\"sans-serif\",labelfontsize=10" 26 | DOT_IMAGE_FORMAT = svg 27 | INTERACTIVE_SVG = YES 28 | HAVE_DOT = @HAVE_DOT@ 29 | DOT_MULTI_TARGETS = @HAVE_DOT_1_8_10@ 30 | DOT_PATH = "@DOT_PATH@" 31 | HTML_FORMULA_FORMAT = @HTML_FORMULA_FORMAT@ 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018-2024 Florian Bernd 4 | Copyright (c) 2018-2024 Joel Höner 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Zyan Core Library for C 2 | 3 | License: MIT 4 | GitHub Actions 5 | Discord 6 | 7 | Internal library providing platform independent types, macros and a fallback for environments without LibC. 8 | 9 | ## Features 10 | 11 | - Platform independent types 12 | - Integer types (`ZyanU8`, `ZyanI32`, `ZyanUSize`, ...) 13 | - `ZyanBool` (+ `ZYAN_FALSE`, `ZYAN_TRUE`) 14 | - `ZYAN_NULL` 15 | - Macros 16 | - Compiler/Platform/Architecture detection 17 | - Asserts and static asserts 18 | - Utils (`ARRAY_LENGTH`, `FALLTHROUGH`, `UNUSED`, ...) 19 | - Common types 20 | - `ZyanBitset` 21 | - `ZyanString`/`ZyanStringView` 22 | - Container types 23 | - `ZyanVector` 24 | - `ZyanList` 25 | - LibC abstraction (WiP) 26 | 27 | ## License 28 | 29 | Zycore is licensed under the MIT license. 30 | -------------------------------------------------------------------------------- /cmake/zyan-functions.cmake: -------------------------------------------------------------------------------- 1 | # =============================================================================================== # 2 | # Exported functions # 3 | # =============================================================================================== # 4 | 5 | function (zyan_set_common_flags target) 6 | if (MSVC) 7 | # MSVC support for C11 is still pretty lacking, so we instead just disable the warnings 8 | # about using non-standard C extensions. 9 | target_compile_options("${target}" PUBLIC "/wd4201") 10 | else () 11 | # For the more civilized compilers, we go with C11. 12 | set_target_properties("${target}" PROPERTIES C_STANDARD 11) 13 | endif () 14 | 15 | if (ZYAN_DEV_MODE) 16 | # If in developer mode, be pedantic. 17 | if (MSVC) 18 | target_compile_options("${target}" PUBLIC "/WX" "/W4") 19 | else () 20 | target_compile_options("${target}" PUBLIC "-Wall" "-pedantic" "-Wextra" "-Werror") 21 | endif () 22 | endif () 23 | endfunction () 24 | 25 | function (zyan_set_source_group target) 26 | if (ZYAN_DEV_MODE) 27 | if (((CMAKE_MAJOR_VERSION GREATER 3) OR (CMAKE_MAJOR_VERSION EQUAL 3)) AND 28 | ((CMAKE_MINOR_VERSION GREATER 8) OR (CMAKE_MINOR_VERSION EQUAL 8))) 29 | # Mirror directory structure in project files 30 | get_property("TARGET_SOURCE_FILES" TARGET "${target}" PROPERTY SOURCES) 31 | source_group(TREE "${CMAKE_CURRENT_LIST_DIR}" FILES ${TARGET_SOURCE_FILES}) 32 | endif () 33 | endif () 34 | endfunction () 35 | 36 | function (zyan_maybe_enable_wpo target) 37 | if (ZYAN_WHOLE_PROGRAM_OPTIMIZATION) 38 | set_property(TARGET "${target}" PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE) 39 | endif () 40 | endfunction () 41 | 42 | # deprecated alias for `zyan_maybe_enable_wpo`, for backward compatibility. 43 | function (zyan_maybe_enable_wpo_for_lib target) 44 | zyan_maybe_enable_wpo("${target}") 45 | endfunction () 46 | -------------------------------------------------------------------------------- /cmake/zycore-config.cmake.in: -------------------------------------------------------------------------------- 1 | set(zycore_VERSION @PROJECT_VERSION@) 2 | 3 | @PACKAGE_INIT@ 4 | 5 | include(CMakeFindDependencyMacro) 6 | if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" AND NOT @ZYAN_NO_LIBC@) 7 | find_dependency(Threads) 8 | endif() 9 | 10 | include("${CMAKE_CURRENT_LIST_DIR}/zyan-functions.cmake") 11 | 12 | include("${CMAKE_CURRENT_LIST_DIR}/zycore-targets.cmake") 13 | 14 | set_and_check(zycore_INCLUDE_DIR "${PACKAGE_PREFIX_DIR}/@CMAKE_INSTALL_INCLUDEDIR@") 15 | set_and_check(zycore_LIB_DIR "${PACKAGE_PREFIX_DIR}/@CMAKE_INSTALL_LIBDIR@") 16 | 17 | check_required_components(zycore) 18 | -------------------------------------------------------------------------------- /examples/String.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************************** 2 | 3 | Zyan Core Library (Zycore-C) 4 | 5 | Original Author : Florian Bernd 6 | 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | 25 | ***************************************************************************************************/ 26 | 27 | /** 28 | * @file 29 | * Demonstrates the `String` implementation. 30 | */ 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | /* ============================================================================================== */ 40 | /* Enums and types */ 41 | /* ============================================================================================== */ 42 | 43 | 44 | /* ============================================================================================== */ 45 | /* Helper functions */ 46 | /* ============================================================================================== */ 47 | 48 | static ZyanStatus PrintString(ZyanString* string) { 49 | const char* cstring; 50 | ZYAN_CHECK(ZyanStringGetData(string, &cstring)); 51 | 52 | printf("(*ZyanString)%p = %s\n", (void*)string, cstring); 53 | 54 | return ZYAN_STATUS_SUCCESS; 55 | } 56 | 57 | /* ============================================================================================== */ 58 | /* Tests */ 59 | /* ============================================================================================== */ 60 | 61 | /* ---------------------------------------------------------------------------------------------- */ 62 | /* Basic tests */ 63 | /* ---------------------------------------------------------------------------------------------- */ 64 | 65 | /** 66 | * Performs some basic test on the given `ZyanString` instance. 67 | * 68 | * @param string A pointer to the `ZyanString` instance. 69 | * 70 | * @return A zyan status code. 71 | */ 72 | static ZyanStatus PerformBasicTests(ZyanString* string) { 73 | ZYAN_ASSERT(string); 74 | 75 | ZyanUSize size; 76 | ZYAN_CHECK(ZyanStringGetSize(string, &size)); 77 | 78 | ZyanStringView view1 = ZYAN_DEFINE_STRING_VIEW("The quick brown fox jumps over the lazy dog"); 79 | ZyanStringView view2 = ZYAN_DEFINE_STRING_VIEW("big "); 80 | 81 | ZYAN_CHECK(ZyanStringAppend(string, &view1)); 82 | PrintString(string); 83 | 84 | ZYAN_CHECK(ZyanStringInsert(string, 4, &view2)); 85 | PrintString(string); 86 | 87 | ZYAN_CHECK(ZyanStringSetChar(string, 7, ',')); 88 | PrintString(string); 89 | 90 | return ZYAN_STATUS_SUCCESS; 91 | } 92 | 93 | /** 94 | * Performs basic tests on a string that dynamically manages memory. 95 | * 96 | * @return A zyan status code. 97 | */ 98 | static ZyanStatus TestDynamic(void) { 99 | ZyanString string; 100 | 101 | ZYAN_CHECK(ZyanStringInit(&string, 10)); 102 | 103 | ZYAN_CHECK(PerformBasicTests(&string)); 104 | 105 | return ZyanStringDestroy(&string); 106 | } 107 | 108 | /** 109 | * Performs basic tests on a string that uses a static buffer. 110 | * 111 | * @return A zyan status code. 112 | */ 113 | static ZyanStatus TestStatic(void) { 114 | static char buffer[50]; 115 | ZyanString string; 116 | 117 | ZYAN_CHECK(ZyanStringInitCustomBuffer(&string, buffer, sizeof(buffer))); 118 | 119 | ZYAN_CHECK(PerformBasicTests(&string)); 120 | 121 | return ZyanStringDestroy(&string); 122 | } 123 | 124 | /* ---------------------------------------------------------------------------------------------- */ 125 | /* Custom allocator */ 126 | /* ---------------------------------------------------------------------------------------------- */ 127 | 128 | static ZyanStatus AllocatorAllocate( 129 | ZyanAllocator* allocator, void** p, ZyanUSize element_size, ZyanUSize n) { 130 | ZYAN_ASSERT(allocator); 131 | ZYAN_ASSERT(p); 132 | ZYAN_ASSERT(element_size); 133 | ZYAN_ASSERT(n); 134 | 135 | ZYAN_UNUSED(allocator); 136 | 137 | *p = ZYAN_MALLOC(element_size * n); 138 | if (!*p) { 139 | return ZYAN_STATUS_NOT_ENOUGH_MEMORY; 140 | } 141 | 142 | return ZYAN_STATUS_SUCCESS; 143 | } 144 | 145 | static ZyanStatus AllocatorReallocate( 146 | ZyanAllocator* allocator, void** p, ZyanUSize element_size, ZyanUSize n) { 147 | ZYAN_ASSERT(allocator); 148 | ZYAN_ASSERT(p); 149 | ZYAN_ASSERT(element_size); 150 | ZYAN_ASSERT(n); 151 | 152 | ZYAN_UNUSED(allocator); 153 | 154 | void* const x = ZYAN_REALLOC(*p, element_size * n); 155 | if (!x) { 156 | return ZYAN_STATUS_NOT_ENOUGH_MEMORY; 157 | } 158 | *p = x; 159 | 160 | return ZYAN_STATUS_SUCCESS; 161 | } 162 | 163 | static ZyanStatus AllocatorDeallocate( 164 | ZyanAllocator* allocator, void* p, ZyanUSize element_size, ZyanUSize n) { 165 | ZYAN_ASSERT(allocator); 166 | ZYAN_ASSERT(p); 167 | ZYAN_ASSERT(element_size); 168 | ZYAN_ASSERT(n); 169 | 170 | ZYAN_UNUSED(allocator); 171 | ZYAN_UNUSED(element_size); 172 | ZYAN_UNUSED(n); 173 | 174 | ZYAN_FREE(p); 175 | 176 | return ZYAN_STATUS_SUCCESS; 177 | } 178 | 179 | /* ---------------------------------------------------------------------------------------------- */ 180 | 181 | /** 182 | * Performs basic tests on a vector that dynamically manages memory using a custom 183 | * allocator and modified growth-factor/shrink-threshold. 184 | * 185 | * @return A zyan status code. 186 | */ 187 | static ZyanStatus TestAllocator(void) { 188 | ZyanAllocator allocator; 189 | ZYAN_CHECK( 190 | ZyanAllocatorInit(&allocator, AllocatorAllocate, AllocatorReallocate, AllocatorDeallocate)); 191 | 192 | ZyanString string; 193 | ZYAN_CHECK(ZyanStringInitEx(&string, 20, &allocator, 10, 0)); 194 | 195 | ZYAN_CHECK(PerformBasicTests(&string)); 196 | 197 | return ZyanStringDestroy(&string); 198 | } 199 | 200 | /* ---------------------------------------------------------------------------------------------- */ 201 | 202 | /* ============================================================================================== */ 203 | /* Entry point */ 204 | /* ============================================================================================== */ 205 | 206 | int main(void) { 207 | if (!ZYAN_SUCCESS(TestDynamic())) { 208 | return EXIT_FAILURE; 209 | } 210 | if (!ZYAN_SUCCESS(TestStatic())) { 211 | return EXIT_FAILURE; 212 | } 213 | if (!ZYAN_SUCCESS(TestAllocator())) { 214 | return EXIT_FAILURE; 215 | } 216 | 217 | return EXIT_SUCCESS; 218 | } 219 | 220 | /* ============================================================================================== */ 221 | -------------------------------------------------------------------------------- /examples/meson.build: -------------------------------------------------------------------------------- 1 | examples_req = examples.allowed() 2 | 3 | if examples_req 4 | executable('String', 'String.c', dependencies: [zycore_dep]) 5 | executable('Vector', 'Vector.c', dependencies: [zycore_dep]) 6 | endif 7 | 8 | summary( 9 | {'examples': examples_req}, 10 | section: 'Features', 11 | ) 12 | -------------------------------------------------------------------------------- /include/Zycore/API/Memory.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************************** 2 | 3 | Zyan Core Library (Zycore-C) 4 | 5 | Original Author : Florian Bernd 6 | 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | 25 | ***************************************************************************************************/ 26 | 27 | /** 28 | * @file 29 | * @brief 30 | */ 31 | 32 | #ifndef ZYCORE_API_MEMORY_H 33 | #define ZYCORE_API_MEMORY_H 34 | 35 | #include 36 | #include 37 | #include 38 | 39 | #ifndef ZYAN_NO_LIBC 40 | 41 | #if defined(ZYAN_WINDOWS) 42 | # include 43 | #elif defined(ZYAN_POSIX) 44 | # include 45 | #else 46 | # error "Unsupported platform detected" 47 | #endif 48 | 49 | /* ============================================================================================== */ 50 | /* Enums and types */ 51 | /* ============================================================================================== */ 52 | 53 | /** 54 | * Defines the `ZyanMemoryPageProtection` enum. 55 | */ 56 | typedef enum ZyanMemoryPageProtection_ 57 | { 58 | #if defined(ZYAN_WINDOWS) 59 | 60 | ZYAN_PAGE_READONLY = PAGE_READONLY, 61 | ZYAN_PAGE_READWRITE = PAGE_READWRITE, 62 | ZYAN_PAGE_EXECUTE = PAGE_EXECUTE, 63 | ZYAN_PAGE_EXECUTE_READ = PAGE_EXECUTE_READ, 64 | ZYAN_PAGE_EXECUTE_READWRITE = PAGE_EXECUTE_READWRITE 65 | 66 | #elif defined(ZYAN_POSIX) 67 | 68 | ZYAN_PAGE_READONLY = PROT_READ, 69 | ZYAN_PAGE_READWRITE = PROT_READ | PROT_WRITE, 70 | ZYAN_PAGE_EXECUTE = PROT_EXEC, 71 | ZYAN_PAGE_EXECUTE_READ = PROT_EXEC | PROT_READ, 72 | ZYAN_PAGE_EXECUTE_READWRITE = PROT_EXEC | PROT_READ | PROT_WRITE 73 | 74 | #endif 75 | } ZyanMemoryPageProtection; 76 | 77 | /* ============================================================================================== */ 78 | /* Exported functions */ 79 | /* ============================================================================================== */ 80 | 81 | /* ---------------------------------------------------------------------------------------------- */ 82 | /* General */ 83 | /* ---------------------------------------------------------------------------------------------- */ 84 | 85 | /** 86 | * Returns the system page size. 87 | * 88 | * @return The system page size. 89 | */ 90 | ZYCORE_EXPORT ZyanU32 ZyanMemoryGetSystemPageSize(void); 91 | 92 | /** 93 | * Returns the system allocation granularity. 94 | * 95 | * The system allocation granularity specifies the minimum amount of bytes which can be allocated 96 | * at a specific address by a single call of `ZyanMemoryVirtualAlloc`. 97 | * 98 | * This value is typically 64KiB on Windows systems and equal to the page size on most POSIX 99 | * platforms. 100 | * 101 | * @return The system allocation granularity. 102 | */ 103 | ZYCORE_EXPORT ZyanU32 ZyanMemoryGetSystemAllocationGranularity(void); 104 | 105 | /* ---------------------------------------------------------------------------------------------- */ 106 | /* Memory management */ 107 | /* ---------------------------------------------------------------------------------------------- */ 108 | 109 | /** 110 | * Changes the memory protection value of one or more pages. 111 | * 112 | * @param address The start address aligned to a page boundary. 113 | * @param size The size. 114 | * @param protection The new page protection value. 115 | * 116 | * @return A zyan status code. 117 | */ 118 | ZYCORE_EXPORT ZyanStatus ZyanMemoryVirtualProtect(void* address, ZyanUSize size, 119 | ZyanMemoryPageProtection protection); 120 | 121 | /** 122 | * Releases one or more memory pages starting at the given address. 123 | * 124 | * @param address The start address aligned to a page boundary. 125 | * @param size The size. 126 | * 127 | * @return A zyan status code. 128 | */ 129 | ZYCORE_EXPORT ZyanStatus ZyanMemoryVirtualFree(void* address, ZyanUSize size); 130 | 131 | /* ---------------------------------------------------------------------------------------------- */ 132 | 133 | /* ============================================================================================== */ 134 | 135 | #endif /* ZYAN_NO_LIBC */ 136 | 137 | #endif /* ZYCORE_API_MEMORY_H */ 138 | -------------------------------------------------------------------------------- /include/Zycore/API/Process.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************************** 2 | 3 | Zyan Core Library (Zycore-C) 4 | 5 | Original Author : Florian Bernd 6 | 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | 25 | ***************************************************************************************************/ 26 | 27 | /** 28 | * @file 29 | * @brief 30 | */ 31 | 32 | #ifndef ZYCORE_API_PROCESS_H 33 | #define ZYCORE_API_PROCESS_H 34 | 35 | #include 36 | #include 37 | 38 | #ifndef ZYAN_NO_LIBC 39 | 40 | /* ============================================================================================== */ 41 | /* Enums and types */ 42 | /* ============================================================================================== */ 43 | 44 | 45 | 46 | /* ============================================================================================== */ 47 | /* Exported functions */ 48 | /* ============================================================================================== */ 49 | 50 | /* ---------------------------------------------------------------------------------------------- */ 51 | /* General */ 52 | /* ---------------------------------------------------------------------------------------------- */ 53 | 54 | /** 55 | * @brief Flushes the process instruction cache. 56 | * 57 | * @param address The address. 58 | * @param size The size. 59 | * 60 | * @return A zyan status code. 61 | */ 62 | ZYCORE_EXPORT ZyanStatus ZyanProcessFlushInstructionCache(void* address, ZyanUSize size); 63 | 64 | /* ---------------------------------------------------------------------------------------------- */ 65 | 66 | /* ============================================================================================== */ 67 | 68 | #endif /* ZYAN_NO_LIBC */ 69 | 70 | #endif /* ZYCORE_API_PROCESS_H */ 71 | -------------------------------------------------------------------------------- /include/Zycore/API/Synchronization.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************************** 2 | 3 | Zyan Core Library (Zycore-C) 4 | 5 | Original Author : Florian Bernd 6 | 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | 25 | ***************************************************************************************************/ 26 | 27 | /** 28 | * @file 29 | * @brief 30 | */ 31 | 32 | #ifndef ZYCORE_API_SYNCHRONIZATION_H 33 | #define ZYCORE_API_SYNCHRONIZATION_H 34 | 35 | #include 36 | #include 37 | 38 | #ifndef ZYAN_NO_LIBC 39 | 40 | #ifdef __cplusplus 41 | extern "C" { 42 | #endif 43 | 44 | /* ============================================================================================== */ 45 | /* Enums and types */ 46 | /* ============================================================================================== */ 47 | 48 | #if defined(ZYAN_POSIX) 49 | 50 | #include 51 | 52 | /* ---------------------------------------------------------------------------------------------- */ 53 | /* Critical Section */ 54 | /* ---------------------------------------------------------------------------------------------- */ 55 | 56 | typedef pthread_mutex_t ZyanCriticalSection; 57 | 58 | /* ---------------------------------------------------------------------------------------------- */ 59 | 60 | #elif defined(ZYAN_WINDOWS) 61 | 62 | #include 63 | 64 | /* ---------------------------------------------------------------------------------------------- */ 65 | /* Critical Section */ 66 | /* ---------------------------------------------------------------------------------------------- */ 67 | 68 | typedef CRITICAL_SECTION ZyanCriticalSection; 69 | 70 | /* ---------------------------------------------------------------------------------------------- */ 71 | 72 | #else 73 | # error "Unsupported platform detected" 74 | #endif 75 | 76 | /* ============================================================================================== */ 77 | /* Exported functions */ 78 | /* ============================================================================================== */ 79 | 80 | /* ---------------------------------------------------------------------------------------------- */ 81 | /* Critical Section */ 82 | /* ---------------------------------------------------------------------------------------------- */ 83 | 84 | /** 85 | * Initializes a critical section. 86 | * 87 | * @param critical_section A pointer to the `ZyanCriticalSection` struct. 88 | */ 89 | ZYCORE_EXPORT ZyanStatus ZyanCriticalSectionInitialize(ZyanCriticalSection* critical_section); 90 | 91 | /** 92 | * Enters a critical section. 93 | * 94 | * @param critical_section A pointer to the `ZyanCriticalSection` struct. 95 | */ 96 | ZYCORE_EXPORT ZyanStatus ZyanCriticalSectionEnter(ZyanCriticalSection* critical_section); 97 | 98 | /** 99 | * Tries to enter a critical section. 100 | * 101 | * @param critical_section A pointer to the `ZyanCriticalSection` struct. 102 | * 103 | * @return Returns `ZYAN_TRUE` if the critical section was successfully entered or `ZYAN_FALSE`, 104 | * if not. 105 | */ 106 | ZYCORE_EXPORT ZyanBool ZyanCriticalSectionTryEnter(ZyanCriticalSection* critical_section); 107 | 108 | /** 109 | * Leaves a critical section. 110 | * 111 | * @param critical_section A pointer to the `ZyanCriticalSection` struct. 112 | */ 113 | ZYCORE_EXPORT ZyanStatus ZyanCriticalSectionLeave(ZyanCriticalSection* critical_section); 114 | 115 | /** 116 | * Deletes a critical section. 117 | * 118 | * @param critical_section A pointer to the `ZyanCriticalSection` struct. 119 | */ 120 | ZYCORE_EXPORT ZyanStatus ZyanCriticalSectionDelete(ZyanCriticalSection* critical_section); 121 | 122 | /* ---------------------------------------------------------------------------------------------- */ 123 | 124 | /* ============================================================================================== */ 125 | 126 | #ifdef __cplusplus 127 | } 128 | #endif 129 | 130 | #endif /* ZYAN_NO_LIBC */ 131 | 132 | #endif /* ZYCORE_API_SYNCHRONIZATION_H */ 133 | -------------------------------------------------------------------------------- /include/Zycore/API/Terminal.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************************** 2 | 3 | Zyan Core Library (Zycore-C) 4 | 5 | Original Author : Florian Bernd 6 | 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | 25 | ***************************************************************************************************/ 26 | 27 | /** 28 | * @file Provides cross-platform terminal helper functions. 29 | * @brief 30 | */ 31 | 32 | #ifndef ZYCORE_API_TERMINAL_H 33 | #define ZYCORE_API_TERMINAL_H 34 | 35 | #include 36 | #include 37 | 38 | #ifdef __cplusplus 39 | extern "C" { 40 | #endif 41 | 42 | #ifndef ZYAN_NO_LIBC 43 | 44 | /* ============================================================================================== */ 45 | /* VT100 CSI SGR sequences */ 46 | /* ============================================================================================== */ 47 | 48 | /* ---------------------------------------------------------------------------------------------- */ 49 | /* General */ 50 | /* ---------------------------------------------------------------------------------------------- */ 51 | 52 | #define ZYAN_VT100SGR_RESET "\033[0m" 53 | 54 | /* ---------------------------------------------------------------------------------------------- */ 55 | /* Foreground colors */ 56 | /* ---------------------------------------------------------------------------------------------- */ 57 | 58 | #define ZYAN_VT100SGR_FG_DEFAULT "\033[39m" 59 | 60 | #define ZYAN_VT100SGR_FG_BLACK "\033[30m" 61 | #define ZYAN_VT100SGR_FG_RED "\033[31m" 62 | #define ZYAN_VT100SGR_FG_GREEN "\033[32m" 63 | #define ZYAN_VT100SGR_FG_YELLOW "\033[33m" 64 | #define ZYAN_VT100SGR_FG_BLUE "\033[34m" 65 | #define ZYAN_VT100SGR_FG_MAGENTA "\033[35m" 66 | #define ZYAN_VT100SGR_FG_CYAN "\033[36m" 67 | #define ZYAN_VT100SGR_FG_WHITE "\033[37m" 68 | #define ZYAN_VT100SGR_FG_BRIGHT_BLACK "\033[90m" 69 | #define ZYAN_VT100SGR_FG_BRIGHT_RED "\033[91m" 70 | #define ZYAN_VT100SGR_FG_BRIGHT_GREEN "\033[92m" 71 | #define ZYAN_VT100SGR_FG_BRIGHT_YELLOW "\033[93m" 72 | #define ZYAN_VT100SGR_FG_BRIGHT_BLUE "\033[94m" 73 | #define ZYAN_VT100SGR_FG_BRIGHT_MAGENTA "\033[95m" 74 | #define ZYAN_VT100SGR_FG_BRIGHT_CYAN "\033[96m" 75 | #define ZYAN_VT100SGR_FG_BRIGHT_WHITE "\033[97m" 76 | 77 | /* ---------------------------------------------------------------------------------------------- */ 78 | /* Background color */ 79 | /* ---------------------------------------------------------------------------------------------- */ 80 | 81 | #define ZYAN_VT100SGR_BG_DEFAULT "\033[49m" 82 | 83 | #define ZYAN_VT100SGR_BG_BLACK "\033[40m" 84 | #define ZYAN_VT100SGR_BG_RED "\033[41m" 85 | #define ZYAN_VT100SGR_BG_GREEN "\033[42m" 86 | #define ZYAN_VT100SGR_BG_YELLOW "\033[43m" 87 | #define ZYAN_VT100SGR_BG_BLUE "\033[44m" 88 | #define ZYAN_VT100SGR_BG_MAGENTA "\033[45m" 89 | #define ZYAN_VT100SGR_BG_CYAN "\033[46m" 90 | #define ZYAN_VT100SGR_BG_WHITE "\033[47m" 91 | #define ZYAN_VT100SGR_BG_BRIGHT_BLACK "\033[100m" 92 | #define ZYAN_VT100SGR_BG_BRIGHT_RED "\033[101m" 93 | #define ZYAN_VT100SGR_BG_BRIGHT_GREEN "\033[102m" 94 | #define ZYAN_VT100SGR_BG_BRIGHT_YELLOW "\033[103m" 95 | #define ZYAN_VT100SGR_BG_BRIGHT_BLUE "\033[104m" 96 | #define ZYAN_VT100SGR_BG_BRIGHT_MAGENTA "\033[105m" 97 | #define ZYAN_VT100SGR_BG_BRIGHT_CYAN "\033[106m" 98 | #define ZYAN_VT100SGR_BG_BRIGHT_WHITE "\033[107m" 99 | 100 | /* ---------------------------------------------------------------------------------------------- */ 101 | 102 | /* ============================================================================================== */ 103 | /* Enums and types */ 104 | /* ============================================================================================== */ 105 | 106 | /** 107 | * Declares the `ZyanStandardStream` enum. 108 | */ 109 | typedef enum ZyanStandardStream_ 110 | { 111 | /** 112 | * The default input stream. 113 | */ 114 | ZYAN_STDSTREAM_IN, 115 | /** 116 | * The default output stream. 117 | */ 118 | ZYAN_STDSTREAM_OUT, 119 | /** 120 | * The default error stream. 121 | */ 122 | ZYAN_STDSTREAM_ERR 123 | } ZyanStandardStream; 124 | 125 | /* ============================================================================================== */ 126 | /* Exported functions */ 127 | /* ============================================================================================== */ 128 | 129 | /** 130 | * Enables VT100 ansi escape codes for the given stream. 131 | * 132 | * @param stream Either `ZYAN_STDSTREAM_OUT` or `ZYAN_STDSTREAM_ERR`. 133 | * 134 | * @return A zyan status code. 135 | * 136 | * This functions returns `ZYAN_STATUS_SUCCESS` on all non-Windows systems without performing any 137 | * operations, assuming that VT100 is supported by default. 138 | * 139 | * On Windows systems, VT100 functionality is only supported on Windows 10 build 1607 (anniversary 140 | * update) and later. 141 | */ 142 | ZYCORE_EXPORT ZyanStatus ZyanTerminalEnableVT100(ZyanStandardStream stream); 143 | 144 | /** 145 | * Checks, if the given standard stream reads from or writes to a terminal. 146 | * 147 | * @param stream The standard stream to check. 148 | * 149 | * @return `ZYAN_STATUS_TRUE`, if the stream is bound to a terminal, `ZYAN_STATUS_FALSE` if not, 150 | * or another zyan status code if an error occured. 151 | */ 152 | ZYCORE_EXPORT ZyanStatus ZyanTerminalIsTTY(ZyanStandardStream stream); 153 | 154 | /* ============================================================================================== */ 155 | 156 | #endif // ZYAN_NO_LIBC 157 | 158 | #ifdef __cplusplus 159 | } 160 | #endif 161 | 162 | #endif /* ZYCORE_API_TERMINAL_H */ 163 | -------------------------------------------------------------------------------- /include/Zycore/API/Thread.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************************** 2 | 3 | Zyan Core Library (Zycore-C) 4 | 5 | Original Author : Florian Bernd 6 | 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | 25 | ***************************************************************************************************/ 26 | 27 | /** 28 | * @file 29 | * @brief 30 | */ 31 | 32 | #ifndef ZYCORE_API_THREAD_H 33 | #define ZYCORE_API_THREAD_H 34 | 35 | #include 36 | #include 37 | 38 | #ifndef ZYAN_NO_LIBC 39 | 40 | #ifdef __cplusplus 41 | extern "C" { 42 | #endif 43 | 44 | /* ============================================================================================== */ 45 | /* Enums and types */ 46 | /* ============================================================================================== */ 47 | 48 | #if defined(ZYAN_POSIX) 49 | 50 | #include 51 | 52 | /* ---------------------------------------------------------------------------------------------- */ 53 | /* General */ 54 | /* ---------------------------------------------------------------------------------------------- */ 55 | 56 | /** 57 | * Defines the `ZyanThread` data-type. 58 | */ 59 | typedef pthread_t ZyanThread; 60 | 61 | /** 62 | * Defines the `ZyanThreadId` data-type. 63 | */ 64 | typedef ZyanU64 ZyanThreadId; 65 | 66 | /* ---------------------------------------------------------------------------------------------- */ 67 | /* Thread Local Storage (TLS) */ 68 | /* ---------------------------------------------------------------------------------------------- */ 69 | 70 | /** 71 | * Defines the `ZyanThreadTlsIndex` data-type. 72 | */ 73 | typedef pthread_key_t ZyanThreadTlsIndex; 74 | 75 | /** 76 | * Defines the `ZyanThreadTlsCallback` function prototype. 77 | */ 78 | typedef void(*ZyanThreadTlsCallback)(void* data); 79 | 80 | /** 81 | * Declares a Thread Local Storage (TLS) callback function. 82 | * 83 | * @param name The callback function name. 84 | * @param param_type The callback data parameter type. 85 | * @param param_name The callback data parameter name. 86 | */ 87 | #define ZYAN_THREAD_DECLARE_TLS_CALLBACK(name, param_type, param_name) \ 88 | void name(param_type* param_name) 89 | 90 | /* ---------------------------------------------------------------------------------------------- */ 91 | 92 | #elif defined(ZYAN_WINDOWS) 93 | 94 | #include 95 | 96 | /* ---------------------------------------------------------------------------------------------- */ 97 | /* General */ 98 | /* ---------------------------------------------------------------------------------------------- */ 99 | 100 | /** 101 | * Defines the `ZyanThread` data-type. 102 | */ 103 | typedef HANDLE ZyanThread; 104 | 105 | /** 106 | * Defines the `ZyanThreadId` data-type. 107 | */ 108 | typedef DWORD ZyanThreadId; 109 | 110 | /* ---------------------------------------------------------------------------------------------- */ 111 | /* Thread Local Storage (TLS) */ 112 | /* ---------------------------------------------------------------------------------------------- */ 113 | 114 | /** 115 | * Defines the `ZyanThreadTlsIndex` data-type. 116 | */ 117 | typedef DWORD ZyanThreadTlsIndex; 118 | 119 | /** 120 | * Defines the `ZyanThreadTlsCallback` function prototype. 121 | */ 122 | typedef PFLS_CALLBACK_FUNCTION ZyanThreadTlsCallback; 123 | 124 | /** 125 | * Declares a Thread Local Storage (TLS) callback function. 126 | * 127 | * @param name The callback function name. 128 | * @param param_type The callback data parameter type. 129 | * @param param_name The callback data parameter name. 130 | */ 131 | #define ZYAN_THREAD_DECLARE_TLS_CALLBACK(name, param_type, param_name) \ 132 | VOID NTAPI name(param_type* param_name) 133 | 134 | /* ---------------------------------------------------------------------------------------------- */ 135 | 136 | #else 137 | # error "Unsupported platform detected" 138 | #endif 139 | 140 | /* ============================================================================================== */ 141 | /* Exported functions */ 142 | /* ============================================================================================== */ 143 | 144 | /* ---------------------------------------------------------------------------------------------- */ 145 | /* General */ 146 | /* ---------------------------------------------------------------------------------------------- */ 147 | 148 | /** 149 | * Returns the handle of the current thread. 150 | * 151 | * @param thread Receives the handle of the current thread. 152 | * 153 | * @return A zyan status code. 154 | */ 155 | ZYCORE_EXPORT ZyanStatus ZyanThreadGetCurrentThread(ZyanThread* thread); 156 | 157 | /** 158 | * Returns the unique id of the current thread. 159 | * 160 | * @param thread_id Receives the unique id of the current thread. 161 | * 162 | * @return A zyan status code. 163 | */ 164 | ZYCORE_EXPORT ZyanStatus ZyanThreadGetCurrentThreadId(ZyanThreadId* thread_id); 165 | 166 | /* ---------------------------------------------------------------------------------------------- */ 167 | /* Thread Local Storage (TLS) */ 168 | /* ---------------------------------------------------------------------------------------------- */ 169 | 170 | /** 171 | * Allocates a new Thread Local Storage (TLS) slot. 172 | * 173 | * @param index Receives the TLS slot index. 174 | * @param destructor A pointer to a destructor callback which is invoked to finalize the data 175 | * in the TLS slot or `ZYAN_NULL`, if not needed. 176 | * 177 | * The maximum available number of TLS slots is implementation specific and different on each 178 | * platform: 179 | * - Windows 180 | * - A total amount of 128 slots per process are guaranteed 181 | * - POSIX 182 | * - A total amount of 128 slots per process are guaranteed 183 | * - Some systems guarantee larger amounts like e.g. 1024 slots per process 184 | * 185 | * Note that the invocation rules for the destructor callback are implementation specific and 186 | * different on each platform: 187 | * - Windows 188 | * - The callback is invoked when a thread exits 189 | * - The callback is invoked when the process exits 190 | * - The callback is invoked when the TLS slot is released 191 | * - POSIX 192 | * - The callback is invoked when a thread exits and the stored value is not null 193 | * - The callback is NOT invoked when the process exits 194 | * - The callback is NOT invoked when the TLS slot is released 195 | * 196 | * @return A zyan status code. 197 | */ 198 | ZYCORE_EXPORT ZyanStatus ZyanThreadTlsAlloc(ZyanThreadTlsIndex* index, 199 | ZyanThreadTlsCallback destructor); 200 | 201 | /** 202 | * Releases a Thread Local Storage (TLS) slot. 203 | * 204 | * @param index The TLS slot index. 205 | * 206 | * @return A zyan status code. 207 | */ 208 | ZYCORE_EXPORT ZyanStatus ZyanThreadTlsFree(ZyanThreadTlsIndex index); 209 | 210 | /** 211 | * Returns the value inside the given Thread Local Storage (TLS) slot for the 212 | * calling thread. 213 | * 214 | * @param index The TLS slot index. 215 | * @param data Receives the value inside the given Thread Local Storage 216 | * (TLS) slot for the calling thread. 217 | * 218 | * @return A zyan status code. 219 | */ 220 | ZYCORE_EXPORT ZyanStatus ZyanThreadTlsGetValue(ZyanThreadTlsIndex index, void** data); 221 | 222 | /** 223 | * Set the value of the given Thread Local Storage (TLS) slot for the calling thread. 224 | * 225 | * @param index The TLS slot index. 226 | * @param data The value to store inside the given Thread Local Storage (TLS) slot for the 227 | * calling thread 228 | * 229 | * @return A zyan status code. 230 | */ 231 | ZYCORE_EXPORT ZyanStatus ZyanThreadTlsSetValue(ZyanThreadTlsIndex index, void* data); 232 | 233 | /* ---------------------------------------------------------------------------------------------- */ 234 | 235 | /* ============================================================================================== */ 236 | 237 | #ifdef __cplusplus 238 | } 239 | #endif 240 | 241 | #endif /* ZYAN_NO_LIBC */ 242 | 243 | #endif /* ZYCORE_API_THREAD_H */ 244 | -------------------------------------------------------------------------------- /include/Zycore/Allocator.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************************** 2 | 3 | Zyan Core Library (Zycore-C) 4 | 5 | Original Author : Florian Bernd 6 | 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | 25 | ***************************************************************************************************/ 26 | 27 | /** 28 | * @file 29 | * @brief 30 | */ 31 | 32 | #ifndef ZYCORE_ALLOCATOR_H 33 | #define ZYCORE_ALLOCATOR_H 34 | 35 | #include 36 | #include 37 | 38 | #ifdef __cplusplus 39 | extern "C" { 40 | #endif 41 | 42 | /* ============================================================================================== */ 43 | /* Enums and types */ 44 | /* ============================================================================================== */ 45 | 46 | struct ZyanAllocator_; 47 | 48 | /** 49 | * Defines the `ZyanAllocatorAllocate` function prototype. 50 | * 51 | * @param allocator A pointer to the `ZyanAllocator` instance. 52 | * @param p Receives a pointer to the first memory block sufficient to hold an 53 | * array of `n` elements with a size of `element_size`. 54 | * @param element_size The size of a single element. 55 | * @param n The number of elements to allocate storage for. 56 | * 57 | * @return A zyan status code. 58 | * 59 | * This prototype is used for the `allocate()` and `reallocate()` functions. 60 | * 61 | * The result of the `reallocate()` function is undefined, if `p` does not point to a memory block 62 | * previously obtained by `(re-)allocate()`. 63 | */ 64 | typedef ZyanStatus (*ZyanAllocatorAllocate)(struct ZyanAllocator_* allocator, void** p, 65 | ZyanUSize element_size, ZyanUSize n); 66 | 67 | /** 68 | * Defines the `ZyanAllocatorDeallocate` function prototype. 69 | * 70 | * @param allocator A pointer to the `ZyanAllocator` instance. 71 | * @param p The pointer obtained from `(re-)allocate()`. 72 | * @param element_size The size of a single element. 73 | * @param n The number of elements earlier passed to `(re-)allocate()`. 74 | * 75 | * @return A zyan status code. 76 | */ 77 | typedef ZyanStatus (*ZyanAllocatorDeallocate)(struct ZyanAllocator_* allocator, void* p, 78 | ZyanUSize element_size, ZyanUSize n); 79 | 80 | /** 81 | * Defines the `ZyanAllocator` struct. 82 | * 83 | * This is the base class for all custom allocator implementations. 84 | * 85 | * All fields in this struct should be considered as "private". Any changes may lead to unexpected 86 | * behavior. 87 | */ 88 | typedef struct ZyanAllocator_ 89 | { 90 | /** 91 | * The allocate function. 92 | */ 93 | ZyanAllocatorAllocate allocate; 94 | /** 95 | * The reallocate function. 96 | */ 97 | ZyanAllocatorAllocate reallocate; 98 | /** 99 | * The deallocate function. 100 | */ 101 | ZyanAllocatorDeallocate deallocate; 102 | } ZyanAllocator; 103 | 104 | /* ============================================================================================== */ 105 | /* Exported functions */ 106 | /* ============================================================================================== */ 107 | 108 | /** 109 | * Initializes the given `ZyanAllocator` instance. 110 | * 111 | * @param allocator A pointer to the `ZyanAllocator` instance. 112 | * @param allocate The allocate function. 113 | * @param reallocate The reallocate function. 114 | * @param deallocate The deallocate function. 115 | * 116 | * @return A zyan status code. 117 | */ 118 | ZYCORE_EXPORT ZyanStatus ZyanAllocatorInit(ZyanAllocator* allocator, ZyanAllocatorAllocate allocate, 119 | ZyanAllocatorAllocate reallocate, ZyanAllocatorDeallocate deallocate); 120 | 121 | #ifndef ZYAN_NO_LIBC 122 | 123 | /** 124 | * Returns the default `ZyanAllocator` instance. 125 | * 126 | * @return A pointer to the default `ZyanAllocator` instance. 127 | * 128 | * The default allocator uses the default memory manager to allocate memory on the heap. 129 | * 130 | * You should in no case modify the returned allocator instance to avoid unexpected behavior. 131 | */ 132 | ZYCORE_EXPORT ZYAN_REQUIRES_LIBC ZyanAllocator* ZyanAllocatorDefault(void); 133 | 134 | #endif // ZYAN_NO_LIBC 135 | 136 | /* ============================================================================================== */ 137 | 138 | #ifdef __cplusplus 139 | } 140 | #endif 141 | 142 | #endif /* ZYCORE_ALLOCATOR_H */ 143 | -------------------------------------------------------------------------------- /include/Zycore/ArgParse.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************************** 2 | 3 | Zyan Core Library (Zycore-C) 4 | 5 | Original Author : Joel Hoener 6 | 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | 25 | ***************************************************************************************************/ 26 | 27 | /** 28 | * @file 29 | * Implements command-line argument parsing. 30 | */ 31 | 32 | #ifndef ZYCORE_ARGPARSE_H 33 | #define ZYCORE_ARGPARSE_H 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #ifdef __cplusplus 41 | extern "C" { 42 | #endif 43 | 44 | /* ============================================================================================== */ 45 | /* Structs and other types */ 46 | /* ============================================================================================== */ 47 | 48 | /** 49 | * Definition of a single argument. 50 | */ 51 | typedef struct ZyanArgParseDefinition_ 52 | { 53 | /** 54 | * The argument name, e.g. `--help`. 55 | * 56 | * Must start with either one or two dashes. Single dash arguments must consist of a single 57 | * character, (e.g. `-n`), double-dash arguments can be of arbitrary length. 58 | */ 59 | const char* name; 60 | /** 61 | * Whether the argument is boolean or expects a value. 62 | */ 63 | ZyanBool boolean; 64 | /** 65 | * Whether this argument is required (error if missing). 66 | */ 67 | ZyanBool required; 68 | } ZyanArgParseDefinition; 69 | 70 | /** 71 | * Configuration for argument parsing. 72 | */ 73 | typedef struct ZyanArgParseConfig_ 74 | { 75 | /** 76 | * `argv` argument passed to `main` by LibC. 77 | */ 78 | const char** argv; 79 | /** 80 | * `argc` argument passed to `main` by LibC. 81 | */ 82 | ZyanUSize argc; 83 | /** 84 | * Minimum # of accepted unnamed / anonymous arguments. 85 | */ 86 | ZyanUSize min_unnamed_args; 87 | /** 88 | * Maximum # of accepted unnamed / anonymous arguments. 89 | */ 90 | ZyanUSize max_unnamed_args; 91 | /** 92 | * Argument definition array, or `ZYAN_NULL`. 93 | * 94 | * Expects a pointer to an array of `ZyanArgParseDefinition` instances. The array is 95 | * terminated by setting the `.name` field of the last element to `ZYAN_NULL`. If no named 96 | * arguments should be parsed, you can also set this to `ZYAN_NULL`. 97 | */ 98 | ZyanArgParseDefinition* args; 99 | } ZyanArgParseConfig; 100 | 101 | /** 102 | * Information about a parsed argument. 103 | */ 104 | typedef struct ZyanArgParseArg_ 105 | { 106 | /** 107 | * Corresponding argument definition, or `ZYAN_NULL` for unnamed args. 108 | * 109 | * This pointer is borrowed from the `cfg` pointer passed to `ZyanArgParse`. 110 | */ 111 | const ZyanArgParseDefinition* def; 112 | /** 113 | * Whether the argument has a value (is non-boolean). 114 | */ 115 | ZyanBool has_value; 116 | /** 117 | * If `has_value == true`, then the argument value. 118 | * 119 | * This is a view into the `argv` string array passed to `ZyanArgParse` via the `cfg` argument. 120 | */ 121 | ZyanStringView value; 122 | } ZyanArgParseArg; 123 | 124 | /* ============================================================================================== */ 125 | /* Exported functions */ 126 | /* ============================================================================================== */ 127 | 128 | #ifndef ZYAN_NO_LIBC 129 | 130 | /** 131 | * Parse arguments according to a `ZyanArgParseConfig` definition. 132 | * 133 | * @param cfg Argument parser config to use. 134 | * @param parsed Receives the parsed output. Vector of `ZyanArgParseArg`. Ownership is 135 | * transferred to the user. Input is expected to be uninitialized. On error, 136 | * the vector remains uninitialized. 137 | * @param error_token On error, if it makes sense, receives the argument fragment causing the 138 | * error. Optional, may be `ZYAN_NULL`. The pointer borrows into the `cfg` 139 | * struct and doesn't have to be freed by the user. 140 | * 141 | * @return A `ZyanStatus` status determining whether the parsing succeeded. 142 | */ 143 | ZYCORE_EXPORT ZyanStatus ZyanArgParse(const ZyanArgParseConfig *cfg, ZyanVector* parsed, 144 | const char** error_token); 145 | 146 | #endif 147 | 148 | /** 149 | * Parse arguments according to a `ZyanArgParseConfig` definition. 150 | * 151 | * This version allows specification of a custom memory allocator and thus supports no-libc. 152 | * 153 | * @param cfg Argument parser config to use. 154 | * @param parsed Receives the parsed output. Vector of `ZyanArgParseArg`. Ownership is 155 | * transferred to the user. Input is expected to be uninitialized. On error, 156 | * the vector remains uninitialized. 157 | * @param error_token On error, if it makes sense, receives the argument fragment causing the 158 | * error. Optional, may be `ZYAN_NULL`. The pointer borrows into the `cfg` 159 | * struct and doesn't have to be freed by the user. 160 | * @param allocator The `ZyanAllocator` to be used for allocating the output vector's data. 161 | * 162 | * @return A `ZyanStatus` status determining whether the parsing succeeded. 163 | */ 164 | ZYCORE_EXPORT ZyanStatus ZyanArgParseEx(const ZyanArgParseConfig *cfg, ZyanVector* parsed, 165 | const char** error_token, ZyanAllocator* allocator); 166 | 167 | /* ============================================================================================== */ 168 | 169 | #ifdef __cplusplus 170 | } 171 | #endif 172 | 173 | #endif /* ZYCORE_ARGPARSE_H */ 174 | -------------------------------------------------------------------------------- /include/Zycore/Atomic.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************************** 2 | 3 | Zyan Core Library (Zyan-C) 4 | 5 | Original Author : Florian Bernd 6 | 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | 25 | ***************************************************************************************************/ 26 | 27 | /** 28 | * @file 29 | * Cross compiler atomic intrinsics. 30 | */ 31 | 32 | #ifndef ZYCORE_ATOMIC_H 33 | #define ZYCORE_ATOMIC_H 34 | 35 | #ifdef __cplusplus 36 | extern "C" { 37 | #endif 38 | 39 | #include 40 | #include 41 | 42 | /* ============================================================================================== */ 43 | /* Enums and Types */ 44 | /* ============================================================================================== */ 45 | 46 | /* 47 | * Wraps a 32-bit value to provide atomic access. 48 | */ 49 | typedef struct ZyanAtomic32_ 50 | { 51 | ZyanU32 volatile value; 52 | } ZyanAtomic32; 53 | 54 | /* 55 | * Wraps a 64-bit value to provide atomic access. 56 | */ 57 | typedef struct ZyanAtomic64_ 58 | { 59 | ZyanU64 volatile value; 60 | } ZyanAtomic64; 61 | 62 | /* 63 | * Wraps a pointer-sized value to provide atomic access. 64 | */ 65 | typedef struct ZyanAtomicPointer_ 66 | { 67 | ZyanVoidPointer volatile value; 68 | } ZyanAtomicPointer; 69 | 70 | /* ============================================================================================== */ 71 | /* Macros */ 72 | /* ============================================================================================== */ 73 | 74 | /* ---------------------------------------------------------------------------------------------- */ 75 | /* Pointer sized */ 76 | /* ---------------------------------------------------------------------------------------------- */ 77 | 78 | /** 79 | * @copydoc ZyanAtomicCompareExchange 80 | */ 81 | #define ZYAN_ATOMIC_COMPARE_EXCHANGE(destination, comparand, value) \ 82 | ZyanAtomicCompareExchange((ZyanAtomicPointer*)&(destination), (comparand), (value)) 83 | 84 | /** 85 | * @copydoc ZyanAtomicIncrement 86 | */ 87 | #define ZYAN_ATOMIC_INCREMENT(destination) \ 88 | ZyanAtomicIncrement((ZyanAtomicPointer*)&(destination)); 89 | 90 | /** 91 | * @copydoc ZyanAtomicDecrement 92 | */ 93 | #define ZYAN_ATOMIC_DECREMENT(destination) \ 94 | ZyanAtomicDecrement((ZyanAtomicPointer*)&(destination)); 95 | 96 | /* ---------------------------------------------------------------------------------------------- */ 97 | /* 32-bit */ 98 | /* ---------------------------------------------------------------------------------------------- */ 99 | 100 | /** 101 | * @copydoc ZyanAtomicCompareExchange 102 | */ 103 | #define ZYAN_ATOMIC_COMPARE_EXCHANGE32(destination, comparand, value) \ 104 | ZyanAtomicCompareExchange32((ZyanAtomic32*)&(destination), (comparand), (value)) 105 | 106 | /** 107 | * @copydoc ZyanAtomicIncrement 108 | */ 109 | #define ZYAN_ATOMIC_INCREMENT32(destination) \ 110 | ZyanAtomicIncrement32((ZyanAtomic32*)&(destination)); 111 | 112 | /** 113 | * @copydoc ZyanAtomicDecrement 114 | */ 115 | #define ZYAN_ATOMIC_DECREMENT32(destination) \ 116 | ZyanAtomicDecrement32((ZyanAtomic32*)&(destination)); 117 | 118 | /* ---------------------------------------------------------------------------------------------- */ 119 | /* 64-bit */ 120 | /* ---------------------------------------------------------------------------------------------- */ 121 | 122 | /** 123 | * @copydoc ZyanAtomicCompareExchange 124 | */ 125 | #define ZYAN_ATOMIC_COMPARE_EXCHANGE64(destination, comparand, value) \ 126 | ZyanAtomicCompareExchange64((ZyanAtomic64*)&(destination), (comparand), (value)) 127 | 128 | /** 129 | * @copydoc ZyanAtomicIncrement 130 | */ 131 | #define ZYAN_ATOMIC_INCREMENT64(destination) \ 132 | ZyanAtomicIncrement64((ZyanAtomic64*)&(destination)); 133 | 134 | /** 135 | * @copydoc ZyanAtomicDecrement 136 | */ 137 | #define ZYAN_ATOMIC_DECREMENT64(destination) \ 138 | ZyanAtomicDecrement64((ZyanAtomic64*)&(destination)); 139 | 140 | /* ---------------------------------------------------------------------------------------------- */ 141 | 142 | /* ============================================================================================== */ 143 | /* Functions */ 144 | /* ============================================================================================== */ 145 | 146 | /* ---------------------------------------------------------------------------------------------- */ 147 | /* Pointer sized */ 148 | /* ---------------------------------------------------------------------------------------------- */ 149 | 150 | /** 151 | * Compares two values for equality and, if they are equal, replaces the first value. 152 | * 153 | * @param destination A pointer to the destination value. 154 | * @param comparand The value to compare with. 155 | * @param value The replacement value. 156 | * 157 | * @return The original value. 158 | */ 159 | static ZyanUPointer ZyanAtomicCompareExchange(ZyanAtomicPointer* destination, 160 | ZyanUPointer comparand, ZyanUPointer value); 161 | 162 | /** 163 | * Increments the given value and stores the result, as an atomic operation. 164 | * 165 | * @param destination A pointer to the destination value. 166 | * 167 | * @return The incremented value. 168 | */ 169 | static ZyanUPointer ZyanAtomicIncrement(ZyanAtomicPointer* destination); 170 | 171 | /** 172 | * Decrements the given value and stores the result, as an atomic operation. 173 | * 174 | * @param destination A pointer to the destination value. 175 | * 176 | * @return The decremented value. 177 | */ 178 | static ZyanUPointer ZyanAtomicDecrement(ZyanAtomicPointer* destination); 179 | 180 | /* ---------------------------------------------------------------------------------------------- */ 181 | /* 32-bit */ 182 | /* ---------------------------------------------------------------------------------------------- */ 183 | 184 | /** 185 | * @copydoc ZyanAtomicCompareExchange 186 | */ 187 | static ZyanU32 ZyanAtomicCompareExchange32(ZyanAtomic32* destination, 188 | ZyanU32 comparand, ZyanU32 value); 189 | 190 | /** 191 | * @copydoc ZyanAtomicIncrement 192 | */ 193 | static ZyanU32 ZyanAtomicIncrement32(ZyanAtomic32* destination); 194 | 195 | /** 196 | * @copydoc ZyanAtomicDecrement 197 | */ 198 | static ZyanU32 ZyanAtomicDecrement32(ZyanAtomic32* destination); 199 | 200 | /* ---------------------------------------------------------------------------------------------- */ 201 | /* 64-bit */ 202 | /* ---------------------------------------------------------------------------------------------- */ 203 | 204 | /** 205 | * @copydoc ZyanAtomicCompareExchange 206 | */ 207 | static ZyanU64 ZyanAtomicCompareExchange64(ZyanAtomic64* destination, 208 | ZyanU64 comparand, ZyanU64 value); 209 | 210 | /** 211 | * @copydoc ZyanAtomicIncrement 212 | */ 213 | static ZyanU64 ZyanAtomicIncrement64(ZyanAtomic64* destination); 214 | 215 | /** 216 | * @copydoc ZyanAtomicDecrement 217 | */ 218 | static ZyanU64 ZyanAtomicDecrement64(ZyanAtomic64* destination); 219 | 220 | /* ---------------------------------------------------------------------------------------------- */ 221 | 222 | /* ============================================================================================== */ 223 | 224 | #if defined(ZYAN_CLANG) || defined(ZYAN_GCC) || defined(ZYAN_ICC) 225 | # include 226 | #elif defined(ZYAN_MSVC) 227 | # include 228 | #else 229 | # error "Unsupported compiler detected" 230 | #endif 231 | 232 | #ifdef __cplusplus 233 | } 234 | #endif 235 | 236 | #endif /* ZYCORE_ATOMIC_H */ 237 | -------------------------------------------------------------------------------- /include/Zycore/Comparison.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************************** 2 | 3 | Zyan Core Library (Zycore-C) 4 | 5 | Original Author : Florian Bernd 6 | 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | 25 | ***************************************************************************************************/ 26 | 27 | /** 28 | * @file 29 | * Defines prototypes of general-purpose comparison functions. 30 | */ 31 | 32 | #ifndef ZYCORE_COMPARISON_H 33 | #define ZYCORE_COMPARISON_H 34 | 35 | #include 36 | #include 37 | 38 | #ifdef __cplusplus 39 | extern "C" { 40 | #endif 41 | 42 | /* ============================================================================================== */ 43 | /* Enums and types */ 44 | /* ============================================================================================== */ 45 | 46 | /** 47 | * Defines the `ZyanEqualityComparison` function prototype. 48 | * 49 | * @param left A pointer to the first element. 50 | * @param right A pointer to the second element. 51 | * 52 | * @return This function should return `ZYAN_TRUE` if the `left` element equals the `right` one 53 | * or `ZYAN_FALSE`, if not. 54 | */ 55 | typedef ZyanBool (*ZyanEqualityComparison)(const void* left, const void* right); 56 | 57 | /** 58 | * Defines the `ZyanComparison` function prototype. 59 | * 60 | * @param left A pointer to the first element. 61 | * @param right A pointer to the second element. 62 | * 63 | * @return This function should return values in the following range: 64 | * `left == right -> result == 0` 65 | * `left < right -> result < 0` 66 | * `left > right -> result > 0` 67 | */ 68 | typedef ZyanI32 (*ZyanComparison)(const void* left, const void* right); 69 | 70 | /* ============================================================================================== */ 71 | /* Macros */ 72 | /* ============================================================================================== */ 73 | 74 | /* ---------------------------------------------------------------------------------------------- */ 75 | /* Equality comparison functions */ 76 | /* ---------------------------------------------------------------------------------------------- */ 77 | 78 | /** 79 | * Declares a generic equality comparison function for an integral data-type. 80 | * 81 | * @param name The name of the function. 82 | * @param type The name of the integral data-type. 83 | */ 84 | #define ZYAN_DECLARE_EQUALITY_COMPARISON(name, type) \ 85 | ZyanBool name(const type* left, const type* right) \ 86 | { \ 87 | ZYAN_ASSERT(left); \ 88 | ZYAN_ASSERT(right); \ 89 | \ 90 | return (*left == *right) ? ZYAN_TRUE : ZYAN_FALSE; \ 91 | } 92 | 93 | /** 94 | * Declares a generic equality comparison function that compares a single integral 95 | * data-type field of a struct. 96 | * 97 | * @param name The name of the function. 98 | * @param type The name of the integral data-type. 99 | * @param field_name The name of the struct field. 100 | */ 101 | #define ZYAN_DECLARE_EQUALITY_COMPARISON_FOR_FIELD(name, type, field_name) \ 102 | ZyanBool name(const type* left, const type* right) \ 103 | { \ 104 | ZYAN_ASSERT(left); \ 105 | ZYAN_ASSERT(right); \ 106 | \ 107 | return (left->field_name == right->field_name) ? ZYAN_TRUE : ZYAN_FALSE; \ 108 | } 109 | 110 | /* ---------------------------------------------------------------------------------------------- */ 111 | /* Comparison functions */ 112 | /* ---------------------------------------------------------------------------------------------- */ 113 | 114 | /** 115 | * Declares a generic comparison function for an integral data-type. 116 | * 117 | * @param name The name of the function. 118 | * @param type The name of the integral data-type. 119 | */ 120 | #define ZYAN_DECLARE_COMPARISON(name, type) \ 121 | ZyanI32 name(const type* left, const type* right) \ 122 | { \ 123 | ZYAN_ASSERT(left); \ 124 | ZYAN_ASSERT(right); \ 125 | \ 126 | if (*left < *right) \ 127 | { \ 128 | return -1; \ 129 | } \ 130 | if (*left > *right) \ 131 | { \ 132 | return 1; \ 133 | } \ 134 | return 0; \ 135 | } 136 | 137 | /** 138 | * Declares a generic comparison function that compares a single integral data-type field 139 | * of a struct. 140 | * 141 | * @param name The name of the function. 142 | * @param type The name of the integral data-type. 143 | * @param field_name The name of the struct field. 144 | */ 145 | #define ZYAN_DECLARE_COMPARISON_FOR_FIELD(name, type, field_name) \ 146 | ZyanI32 name(const type* left, const type* right) \ 147 | { \ 148 | ZYAN_ASSERT(left); \ 149 | ZYAN_ASSERT(right); \ 150 | \ 151 | if (left->field_name < right->field_name) \ 152 | { \ 153 | return -1; \ 154 | } \ 155 | if (left->field_name > right->field_name) \ 156 | { \ 157 | return 1; \ 158 | } \ 159 | return 0; \ 160 | } 161 | 162 | /* ---------------------------------------------------------------------------------------------- */ 163 | 164 | /* ============================================================================================== */ 165 | /* Exported functions */ 166 | /* ============================================================================================== */ 167 | 168 | /* ---------------------------------------------------------------------------------------------- */ 169 | /* Default equality comparison functions */ 170 | /* ---------------------------------------------------------------------------------------------- */ 171 | 172 | /** 173 | * Defines a default equality comparison function for pointer values. 174 | * 175 | * @param left A pointer to the first value. 176 | * @param right A pointer to the second value. 177 | * 178 | * @return Returns `ZYAN_TRUE` if the `left` value equals the `right` one or `ZYAN_FALSE`, if 179 | * not. 180 | */ 181 | ZYAN_INLINE ZYAN_DECLARE_EQUALITY_COMPARISON(ZyanEqualsPointer, void* const) 182 | 183 | /** 184 | * Defines a default equality comparison function for `ZyanBool` values. 185 | * 186 | * @param left A pointer to the first value. 187 | * @param right A pointer to the second value. 188 | * 189 | * @return Returns `ZYAN_TRUE` if the `left` value equals the `right` one or `ZYAN_FALSE`, if 190 | * not. 191 | */ 192 | ZYAN_INLINE ZYAN_DECLARE_EQUALITY_COMPARISON(ZyanEqualsBool, ZyanBool) 193 | 194 | /** 195 | * Defines a default equality comparison function for 8-bit numeric values. 196 | * 197 | * @param left A pointer to the first value. 198 | * @param right A pointer to the second value. 199 | * 200 | * @return Returns `ZYAN_TRUE` if the `left` value equals the `right` one or `ZYAN_FALSE`, if 201 | * not. 202 | */ 203 | ZYAN_INLINE ZYAN_DECLARE_EQUALITY_COMPARISON(ZyanEqualsNumeric8, ZyanU8) 204 | 205 | /** 206 | * Defines a default equality comparison function for 16-bit numeric values. 207 | * 208 | * @param left A pointer to the first value. 209 | * @param right A pointer to the second value. 210 | * 211 | * @return Returns `ZYAN_TRUE` if the `left` value equals the `right` one or `ZYAN_FALSE`, if 212 | * not. 213 | */ 214 | ZYAN_INLINE ZYAN_DECLARE_EQUALITY_COMPARISON(ZyanEqualsNumeric16, ZyanU16) 215 | 216 | /** 217 | * Defines a default equality comparison function for 32-bit numeric values. 218 | * 219 | * @param left A pointer to the first value. 220 | * @param right A pointer to the second value. 221 | * 222 | * @return Returns `ZYAN_TRUE` if the `left` value equals the `right` one or `ZYAN_FALSE`, if 223 | * not. 224 | */ 225 | ZYAN_INLINE ZYAN_DECLARE_EQUALITY_COMPARISON(ZyanEqualsNumeric32, ZyanU32) 226 | 227 | /** 228 | * Defines a default equality comparison function for 64-bit numeric values. 229 | * 230 | * @param left A pointer to the first value. 231 | * @param right A pointer to the second value. 232 | * 233 | * @return Returns `ZYAN_TRUE` if the `left` value equals the `right` one or `ZYAN_FALSE`, if 234 | * not. 235 | */ 236 | ZYAN_INLINE ZYAN_DECLARE_EQUALITY_COMPARISON(ZyanEqualsNumeric64, ZyanU64) 237 | 238 | /* ---------------------------------------------------------------------------------------------- */ 239 | /* Default comparison functions */ 240 | /* ---------------------------------------------------------------------------------------------- */ 241 | 242 | /** 243 | * Defines a default comparison function for pointer values. 244 | * 245 | * @param left A pointer to the first value. 246 | * @param right A pointer to the second value. 247 | * 248 | * @return Returns `0` if the `left` value equals the `right` one, `-1` if the `left` value is 249 | * less than the `right` one, or `1` if the `left` value is greater than the `right` one. 250 | */ 251 | ZYAN_INLINE ZYAN_DECLARE_COMPARISON(ZyanComparePointer, void* const) 252 | 253 | /** 254 | * Defines a default comparison function for `ZyanBool` values. 255 | * 256 | * @param left A pointer to the first value. 257 | * @param right A pointer to the second value. 258 | * 259 | * @return Returns `0` if the `left` value equals the `right` one, `-1` if the `left` value is 260 | * less than the `right` one, or `1` if the `left` value is greater than the `right` one. 261 | */ 262 | ZYAN_INLINE ZYAN_DECLARE_COMPARISON(ZyanCompareBool, ZyanBool) 263 | 264 | /** 265 | * Defines a default comparison function for 8-bit numeric values. 266 | * 267 | * @param left A pointer to the first value. 268 | * @param right A pointer to the second value. 269 | * 270 | * @return Returns `0` if the `left` value equals the `right` one, `-1` if the `left` value is 271 | * less than the `right` one, or `1` if the `left` value is greater than the `right` one. 272 | */ 273 | ZYAN_INLINE ZYAN_DECLARE_COMPARISON(ZyanCompareNumeric8, ZyanU8) 274 | 275 | /** 276 | * Defines a default comparison function for 16-bit numeric values. 277 | * 278 | * @param left A pointer to the first value. 279 | * @param right A pointer to the second value. 280 | * 281 | * @return Returns `0` if the `left` value equals the `right` one, `-1` if the `left` value is 282 | * less than the `right` one, or `1` if the `left` value is greater than the `right` one. 283 | */ 284 | ZYAN_INLINE ZYAN_DECLARE_COMPARISON(ZyanCompareNumeric16, ZyanU16) 285 | 286 | /** 287 | * Defines a default comparison function for 32-bit numeric values. 288 | * 289 | * @param left A pointer to the first value. 290 | * @param right A pointer to the second value. 291 | * 292 | * @return Returns `0` if the `left` value equals the `right` one, `-1` if the `left` value is 293 | * less than the `right` one, or `1` if the `left` value is greater than the `right` one. 294 | */ 295 | ZYAN_INLINE ZYAN_DECLARE_COMPARISON(ZyanCompareNumeric32, ZyanU32) 296 | 297 | /** 298 | * Defines a default comparison function for 64-bit numeric values. 299 | * 300 | * @param left A pointer to the first value. 301 | * @param right A pointer to the second value. 302 | * 303 | * @return Returns `0` if the `left` value equals the `right` one, `-1` if the `left` value is 304 | * less than the `right` one, or `1` if the `left` value is greater than the `right` one. 305 | */ 306 | ZYAN_INLINE ZYAN_DECLARE_COMPARISON(ZyanCompareNumeric64, ZyanU64) 307 | 308 | /* ---------------------------------------------------------------------------------------------- */ 309 | 310 | /* ============================================================================================== */ 311 | 312 | #ifdef __cplusplus 313 | } 314 | #endif 315 | 316 | #endif /* ZYCORE_COMPARISON_H */ 317 | -------------------------------------------------------------------------------- /include/Zycore/Format.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************************** 2 | 3 | Zyan Core Library (Zycore-C) 4 | 5 | Original Author : Florian Bernd 6 | 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | 25 | ***************************************************************************************************/ 26 | 27 | /** 28 | * @file 29 | * Provides helper functions for performant number to string conversion. 30 | */ 31 | 32 | #ifndef ZYCORE_FORMAT_H 33 | #define ZYCORE_FORMAT_H 34 | 35 | #include 36 | #include 37 | #include 38 | 39 | #ifdef __cplusplus 40 | extern "C" { 41 | #endif 42 | 43 | /* ============================================================================================== */ 44 | /* Exported functions */ 45 | /* ============================================================================================== */ 46 | 47 | /* ---------------------------------------------------------------------------------------------- */ 48 | /* Helpers */ 49 | /* ---------------------------------------------------------------------------------------------- */ 50 | 51 | /** 52 | * Get the absolute value of a 64 bit int. 53 | * 54 | * @param x The value to process. 55 | * @return The absolute, unsigned value. 56 | * 57 | * This gracefully deals with the special case of `x` being `INT_MAX`. 58 | */ 59 | ZYAN_INLINE ZyanU64 ZyanAbsI64(ZyanI64 x) 60 | { 61 | // INT_MIN special case. Can't use the value directly because GCC thinks 62 | // it's too big for an INT64 literal, however is perfectly happy to accept 63 | // this expression. This is also hit INT64_MIN is defined in `stdint.h`. 64 | if (x == (-0x7fffffffffffffff - 1)) 65 | { 66 | return 0x8000000000000000u; 67 | } 68 | 69 | return (ZyanU64)(x < 0 ? -x : x); 70 | } 71 | 72 | /* ---------------------------------------------------------------------------------------------- */ 73 | /* Insertion */ 74 | /* ---------------------------------------------------------------------------------------------- */ 75 | 76 | /** 77 | * Inserts formatted text in the destination string at the given `index`. 78 | * 79 | * @param string The destination string. 80 | * @param index The insert index. 81 | * @param format The format string. 82 | * @param ... The format arguments. 83 | * 84 | * @return A zyan status code. 85 | * 86 | * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified 87 | * `ZyanString` instance. 88 | */ 89 | ZYAN_PRINTF_ATTR(3, 4) 90 | ZYCORE_EXPORT ZyanStatus ZyanStringInsertFormat(ZyanString* string, ZyanUSize index, 91 | const char* format, ...); 92 | 93 | /* ---------------------------------------------------------------------------------------------- */ 94 | 95 | /** 96 | * Formats the given unsigned ordinal `value` to its decimal text-representation and 97 | * inserts it to the `string`. 98 | * 99 | * @param string A pointer to the `ZyanString` instance. 100 | * @param index The insert index. 101 | * @param value The value. 102 | * @param padding_length Padds the converted value with leading zeros, if the number of chars is 103 | * less than the `padding_length`. 104 | * 105 | * @return A zyan status code. 106 | * 107 | * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified 108 | * `ZyanString` instance. 109 | */ 110 | ZYCORE_EXPORT ZyanStatus ZyanStringInsertDecU(ZyanString* string, ZyanUSize index, ZyanU64 value, 111 | ZyanU8 padding_length); 112 | 113 | /** 114 | * Formats the given signed ordinal `value` to its decimal text-representation and 115 | * inserts it to the `string`. 116 | * 117 | * @param string A pointer to the `ZyanString` instance. 118 | * @param index The insert index. 119 | * @param value The value. 120 | * @param padding_length Padds the converted value with leading zeros, if the number of chars is 121 | * less than the `padding_length`. 122 | * @param force_sign Set `ZYAN_TRUE`, to force printing of the `+` sign for positive numbers. 123 | * @param prefix The string to use as prefix or `ZYAN_NULL`, if not needed. 124 | * 125 | * @return A zyan status code. 126 | * 127 | * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified 128 | * `ZyanString` instance. 129 | */ 130 | ZYCORE_EXPORT ZyanStatus ZyanStringInsertDecS(ZyanString* string, ZyanUSize index, ZyanI64 value, 131 | ZyanU8 padding_length, ZyanBool force_sign, const ZyanString* prefix); 132 | 133 | /** 134 | * Formats the given unsigned ordinal `value` to its hexadecimal text-representation and 135 | * inserts it to the `string`. 136 | * 137 | * @param string A pointer to the `ZyanString` instance. 138 | * @param index The insert index. 139 | * @param value The value. 140 | * @param padding_length Padds the converted value with leading zeros, if the number of chars is 141 | * less than the `padding_length`. 142 | * @param uppercase Set `ZYAN_TRUE` to use uppercase letters ('A'-'F') instead of lowercase 143 | * ones ('a'-'f'). 144 | * 145 | * @return A zyan status code. 146 | * 147 | * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified 148 | * `ZyanString` instance. 149 | */ 150 | ZYCORE_EXPORT ZyanStatus ZyanStringInsertHexU(ZyanString* string, ZyanUSize index, ZyanU64 value, 151 | ZyanU8 padding_length, ZyanBool uppercase); 152 | 153 | /** 154 | * Formats the given signed ordinal `value` to its hexadecimal text-representation and 155 | * inserts it to the `string`. 156 | * 157 | * @param string A pointer to the `ZyanString` instance. 158 | * @param index The insert index. 159 | * @param value The value. 160 | * @param padding_length Padds the converted value with leading zeros, if the number of chars is 161 | * less than the `padding_length`. 162 | * @param uppercase Set `ZYAN_TRUE` to use uppercase letters ('A'-'F') instead of lowercase 163 | * ones ('a'-'f'). 164 | * @param force_sign Set `ZYAN_TRUE`, to force printing of the `+` sign for positive numbers. 165 | * @param prefix The string to use as prefix or `ZYAN_NULL`, if not needed. 166 | * 167 | * @return A zyan status code. 168 | * 169 | * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified 170 | * `ZyanString` instance. 171 | */ 172 | ZYCORE_EXPORT ZyanStatus ZyanStringInsertHexS(ZyanString* string, ZyanUSize index, ZyanI64 value, 173 | ZyanU8 padding_length, ZyanBool uppercase, ZyanBool force_sign, const ZyanString* prefix); 174 | 175 | /* ---------------------------------------------------------------------------------------------- */ 176 | /* Appending */ 177 | /* ---------------------------------------------------------------------------------------------- */ 178 | 179 | #ifndef ZYAN_NO_LIBC 180 | 181 | /** 182 | * Appends formatted text to the destination string. 183 | * 184 | * @param string The destination string. 185 | * @param format The format string. 186 | * @param ... The format arguments. 187 | * 188 | * @return A zyan status code. 189 | * 190 | * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified 191 | * `ZyanString` instance. 192 | */ 193 | ZYAN_PRINTF_ATTR(2, 3) 194 | ZYCORE_EXPORT ZYAN_REQUIRES_LIBC ZyanStatus ZyanStringAppendFormat( 195 | ZyanString* string, const char* format, ...); 196 | 197 | #endif // ZYAN_NO_LIBC 198 | 199 | /* ---------------------------------------------------------------------------------------------- */ 200 | 201 | /** 202 | * Formats the given unsigned ordinal `value` to its decimal text-representation and 203 | * appends it to the `string`. 204 | * 205 | * @param string A pointer to the `ZyanString` instance. 206 | * @param value The value. 207 | * @param padding_length Padds the converted value with leading zeros, if the number of chars is 208 | * less than the `padding_length`. 209 | * 210 | * @return A zyan status code. 211 | * 212 | * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified 213 | * `ZyanString` instance. 214 | */ 215 | ZYCORE_EXPORT ZyanStatus ZyanStringAppendDecU(ZyanString* string, ZyanU64 value, 216 | ZyanU8 padding_length); 217 | 218 | /** 219 | * Formats the given signed ordinal `value` to its decimal text-representation and 220 | * appends it to the `string`. 221 | * 222 | * @param string A pointer to the `ZyanString` instance. 223 | * @param value The value. 224 | * @param padding_length Padds the converted value with leading zeros, if the number of chars is 225 | * less than the `padding_length`. 226 | * @param force_sign Set `ZYAN_TRUE`, to force printing of the `+` sign for positive numbers. 227 | * @param prefix The string to use as prefix or `ZYAN_NULL`, if not needed. 228 | * 229 | * @return A zyan status code. 230 | * 231 | * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified 232 | * `ZyanString` instance. 233 | */ 234 | ZYCORE_EXPORT ZyanStatus ZyanStringAppendDecS(ZyanString* string, ZyanI64 value, 235 | ZyanU8 padding_length, ZyanBool force_sign, const ZyanStringView* prefix); 236 | 237 | /** 238 | * Formats the given unsigned ordinal `value` to its hexadecimal text-representation and 239 | * appends it to the `string`. 240 | * 241 | * @param string A pointer to the `ZyanString` instance. 242 | * @param value The value. 243 | * @param padding_length Padds the converted value with leading zeros, if the number of chars is 244 | * less than the `padding_length`. 245 | * @param uppercase Set `ZYAN_TRUE` to use uppercase letters ('A'-'F') instead of lowercase 246 | * ones ('a'-'f'). 247 | * 248 | * @return A zyan status code. 249 | * 250 | * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified 251 | * `ZyanString` instance. 252 | */ 253 | ZYCORE_EXPORT ZyanStatus ZyanStringAppendHexU(ZyanString* string, ZyanU64 value, 254 | ZyanU8 padding_length, ZyanBool uppercase); 255 | 256 | /** 257 | * Formats the given signed ordinal `value` to its hexadecimal text-representation and 258 | * appends it to the `string`. 259 | * 260 | * @param string A pointer to the `ZyanString` instance. 261 | * @param value The value. 262 | * @param padding_length Padds the converted value with leading zeros, if the number of chars is 263 | * less than the `padding_length`. 264 | * @param uppercase Set `ZYAN_TRUE` to use uppercase letters ('A'-'F') instead of lowercase 265 | * ones ('a'-'f'). 266 | * @param force_sign Set `ZYAN_TRUE`, to force printing of the `+` sign for positive numbers. 267 | * @param prefix The string to use as prefix or `ZYAN_NULL`, if not needed. 268 | * 269 | * @return A zyan status code. 270 | * 271 | * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified 272 | * `ZyanString` instance. 273 | */ 274 | ZYCORE_EXPORT ZyanStatus ZyanStringAppendHexS(ZyanString* string, ZyanI64 value, 275 | ZyanU8 padding_length, ZyanBool uppercase, ZyanBool force_sign, const ZyanStringView* prefix); 276 | 277 | /* ---------------------------------------------------------------------------------------------- */ 278 | 279 | /* ============================================================================================== */ 280 | 281 | #ifdef __cplusplus 282 | } 283 | #endif 284 | 285 | #endif // ZYCORE_FORMAT_H 286 | -------------------------------------------------------------------------------- /include/Zycore/Internal/AtomicGNU.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************************** 2 | 3 | Zyan Core Library (Zyan-C) 4 | 5 | Original Author : Florian Bernd 6 | 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | 25 | ***************************************************************************************************/ 26 | 27 | #ifndef ZYCORE_ATOMIC_GNU_H 28 | #define ZYCORE_ATOMIC_GNU_H 29 | 30 | #ifdef __cplusplus 31 | extern "C" { 32 | #endif 33 | 34 | #include 35 | #include 36 | 37 | /* ============================================================================================== */ 38 | /* Functions */ 39 | /* ============================================================================================== */ 40 | 41 | #if defined(ZYAN_CLANG) || defined(ZYAN_GCC) || defined(ZYAN_ICC) 42 | 43 | /* ---------------------------------------------------------------------------------------------- */ 44 | /* Pointer sized */ 45 | /* ---------------------------------------------------------------------------------------------- */ 46 | 47 | ZYAN_INLINE ZyanUPointer ZyanAtomicCompareExchange(ZyanAtomicPointer* destination, 48 | ZyanUPointer comparand, ZyanUPointer value) 49 | { 50 | return (ZyanUPointer)(__sync_val_compare_and_swap( 51 | &destination->value, (void*)comparand, (void*)value, &destination->value)); 52 | } 53 | 54 | ZYAN_INLINE ZyanUPointer ZyanAtomicIncrement(ZyanAtomicPointer* destination) 55 | { 56 | return (ZyanUPointer)(__sync_fetch_and_add(&destination->value, (void*)1, 57 | &destination->value)) + 1; 58 | } 59 | 60 | ZYAN_INLINE ZyanUPointer ZyanAtomicDecrement(ZyanAtomicPointer* destination) 61 | { 62 | return (ZyanUPointer)(__sync_sub_and_fetch(&destination->value, (void*)1, &destination->value)); 63 | } 64 | 65 | /* ---------------------------------------------------------------------------------------------- */ 66 | /* 32-bit */ 67 | /* ---------------------------------------------------------------------------------------------- */ 68 | 69 | ZYAN_INLINE ZyanU32 ZyanAtomicCompareExchange32(ZyanAtomic32* destination, 70 | ZyanU32 comparand, ZyanU32 value) 71 | { 72 | return (ZyanU32)(__sync_val_compare_and_swap(&destination->value, comparand, value, 73 | &destination->value)); 74 | } 75 | 76 | ZYAN_INLINE ZyanU32 ZyanAtomicIncrement32(ZyanAtomic32* destination) 77 | { 78 | return (ZyanU32)(__sync_fetch_and_add(&destination->value, 1, &destination->value)) + 1; 79 | } 80 | 81 | ZYAN_INLINE ZyanU32 ZyanAtomicDecrement32(ZyanAtomic32* destination) 82 | { 83 | return (ZyanU32)(__sync_sub_and_fetch(&destination->value, 1, &destination->value)); 84 | } 85 | 86 | /* ---------------------------------------------------------------------------------------------- */ 87 | /* 64-bit */ 88 | /* ---------------------------------------------------------------------------------------------- */ 89 | 90 | ZYAN_INLINE ZyanU64 ZyanAtomicCompareExchange64(ZyanAtomic64* destination, 91 | ZyanU64 comparand, ZyanU64 value) 92 | { 93 | return (ZyanU64)(__sync_val_compare_and_swap(&destination->value, comparand, value, 94 | &destination->value)); 95 | } 96 | 97 | ZYAN_INLINE ZyanU64 ZyanAtomicIncrement64(ZyanAtomic64* destination) 98 | { 99 | return (ZyanU64)(__sync_fetch_and_add(&destination->value, 1, &destination->value)) + 1; 100 | } 101 | 102 | ZYAN_INLINE ZyanU64 ZyanAtomicDecrement64(ZyanAtomic64* destination) 103 | { 104 | return (ZyanU64)(__sync_sub_and_fetch(&destination->value, 1, &destination->value)); 105 | } 106 | 107 | /* ---------------------------------------------------------------------------------------------- */ 108 | 109 | #endif 110 | 111 | /* ============================================================================================== */ 112 | 113 | #ifdef __cplusplus 114 | } 115 | #endif 116 | 117 | #endif /* ZYCORE_ATOMIC_GNU_H */ 118 | -------------------------------------------------------------------------------- /include/Zycore/Internal/AtomicMSVC.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************************** 2 | 3 | Zyan Core Library (Zyan-C) 4 | 5 | Original Author : Florian Bernd 6 | 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | 25 | ***************************************************************************************************/ 26 | 27 | #ifndef ZYCORE_ATOMIC_MSVC_H 28 | #define ZYCORE_ATOMIC_MSVC_H 29 | 30 | #ifdef __cplusplus 31 | extern "C" { 32 | #endif 33 | 34 | #include 35 | 36 | #include 37 | #include 38 | 39 | /* ============================================================================================== */ 40 | /* Functions */ 41 | /* ============================================================================================== */ 42 | 43 | #if defined(ZYAN_MSVC) 44 | 45 | /* ---------------------------------------------------------------------------------------------- */ 46 | /* Pointer sized */ 47 | /* ---------------------------------------------------------------------------------------------- */ 48 | 49 | #if defined(ZYAN_X86) 50 | 51 | ZYAN_INLINE ZyanUPointer ZyanAtomicCompareExchange(ZyanAtomicPointer* destination, 52 | ZyanUPointer comparand, ZyanUPointer value) 53 | { 54 | return (ZyanUPointer)ZyanAtomicCompareExchange32((ZyanAtomic32*)destination, comparand, value); 55 | } 56 | 57 | ZYAN_INLINE ZyanUPointer ZyanAtomicIncrement(ZyanAtomicPointer* destination) 58 | { 59 | return (ZyanUPointer)ZyanAtomicIncrement32((ZyanAtomic32*)destination); 60 | } 61 | 62 | ZYAN_INLINE ZyanUPointer ZyanAtomicDecrement(ZyanAtomicPointer* destination) 63 | { 64 | return (ZyanUPointer)ZyanAtomicDecrement32((ZyanAtomic32*)destination); 65 | } 66 | 67 | #elif defined(ZYAN_X64) 68 | 69 | ZYAN_INLINE ZyanUPointer ZyanAtomicCompareExchange(ZyanAtomicPointer* destination, 70 | ZyanUPointer comparand, ZyanUPointer value) 71 | { 72 | return (ZyanUPointer)ZyanAtomicCompareExchange64((ZyanAtomic64*)destination, comparand, value); 73 | } 74 | 75 | ZYAN_INLINE ZyanUPointer ZyanAtomicIncrement(ZyanAtomicPointer* destination) 76 | { 77 | return (ZyanUPointer)ZyanAtomicIncrement64((ZyanAtomic64*)destination); 78 | } 79 | 80 | ZYAN_INLINE ZyanUPointer ZyanAtomicDecrement(ZyanAtomicPointer* destination) 81 | { 82 | return (ZyanUPointer)ZyanAtomicDecrement64((ZyanAtomic64*)destination); 83 | } 84 | 85 | #else 86 | # error "Unsupported architecture detected" 87 | #endif 88 | 89 | /* ---------------------------------------------------------------------------------------------- */ 90 | /* 32-bit */ 91 | /* ---------------------------------------------------------------------------------------------- */ 92 | 93 | ZYAN_INLINE ZyanU32 ZyanAtomicCompareExchange32(ZyanAtomic32* destination, 94 | ZyanU32 comparand, ZyanU32 value) 95 | { 96 | return (ZyanU32)(_InterlockedCompareExchange((volatile LONG*)&(destination->value), 97 | (LONG)value, (LONG)comparand)); 98 | } 99 | 100 | ZYAN_INLINE ZyanU32 ZyanAtomicIncrement32(ZyanAtomic32* destination) 101 | { 102 | return (ZyanU32)(_InterlockedIncrement((volatile LONG*)&(destination->value))); 103 | } 104 | 105 | ZYAN_INLINE ZyanU32 ZyanAtomicDecrement32(ZyanAtomic32* destination) 106 | { 107 | return (ZyanU32)(_InterlockedDecrement((volatile LONG*)&(destination->value))); 108 | } 109 | 110 | /* ---------------------------------------------------------------------------------------------- */ 111 | /* 64-bit */ 112 | /* ---------------------------------------------------------------------------------------------- */ 113 | 114 | ZYAN_INLINE ZyanU64 ZyanAtomicCompareExchange64(ZyanAtomic64* destination, 115 | ZyanU64 comparand, ZyanU64 value) 116 | { 117 | return (ZyanU64)(_InterlockedCompareExchange64((volatile LONG64*)&(destination->value), 118 | (LONG64)value, (LONG64)comparand)); 119 | } 120 | 121 | ZYAN_INLINE ZyanU64 ZyanAtomicIncrement64(ZyanAtomic64* destination) 122 | { 123 | return (ZyanU64)(_InterlockedIncrement64((volatile LONG64*)&(destination->value))); 124 | } 125 | 126 | ZYAN_INLINE ZyanU64 ZyanAtomicDecrement64(ZyanAtomic64* destination) 127 | { 128 | return (ZyanU64)(_InterlockedDecrement64((volatile LONG64*)&(destination->value))); 129 | } 130 | 131 | /* ---------------------------------------------------------------------------------------------- */ 132 | 133 | #endif 134 | 135 | /* ============================================================================================== */ 136 | 137 | #ifdef __cplusplus 138 | } 139 | #endif 140 | 141 | #endif /* ZYCORE_ATOMIC_MSVC_H */ 142 | -------------------------------------------------------------------------------- /include/Zycore/Object.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************************** 2 | 3 | Zyan Core Library (Zycore-C) 4 | 5 | Original Author : Florian Bernd 6 | 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | 25 | ***************************************************************************************************/ 26 | 27 | /** 28 | * @file 29 | * Defines some generic object-related datatypes. 30 | */ 31 | 32 | #ifndef ZYCORE_OBJECT_H 33 | #define ZYCORE_OBJECT_H 34 | 35 | #include 36 | #include 37 | 38 | #ifdef __cplusplus 39 | extern "C" { 40 | #endif 41 | 42 | /* ============================================================================================== */ 43 | /* Enums and types */ 44 | /* ============================================================================================== */ 45 | 46 | /** 47 | * Defines the `ZyanMemberProcedure` function prototype. 48 | * 49 | * @param object A pointer to the object. 50 | */ 51 | typedef void (*ZyanMemberProcedure)(void* object); 52 | 53 | /** 54 | * Defines the `ZyanConstMemberProcedure` function prototype. 55 | * 56 | * @param object A pointer to the object. 57 | */ 58 | typedef void (*ZyanConstMemberProcedure)(const void* object); 59 | 60 | /** 61 | * Defines the `ZyanMemberFunction` function prototype. 62 | * 63 | * @param object A pointer to the object. 64 | * 65 | * @return A zyan status code. 66 | */ 67 | typedef ZyanStatus (*ZyanMemberFunction)(void* object); 68 | 69 | /** 70 | * Defines the `ZyanConstMemberFunction` function prototype. 71 | * 72 | * @param object A pointer to the object. 73 | * 74 | * @return A zyan status code. 75 | */ 76 | typedef ZyanStatus (*ZyanConstMemberFunction)(const void* object); 77 | 78 | /* ============================================================================================== */ 79 | 80 | #ifdef __cplusplus 81 | } 82 | #endif 83 | 84 | #endif /* ZYCORE_OBJECT_H */ 85 | -------------------------------------------------------------------------------- /include/Zycore/Status.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************************** 2 | 3 | Zyan Core Library (Zyan-C) 4 | 5 | Original Author : Florian Bernd, Joel Hoener 6 | 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | 25 | ***************************************************************************************************/ 26 | 27 | /** 28 | * @file 29 | * Status code definitions and check macros. 30 | */ 31 | 32 | #ifndef ZYCORE_STATUS_H 33 | #define ZYCORE_STATUS_H 34 | 35 | #ifdef __cplusplus 36 | extern "C" { 37 | #endif 38 | 39 | #include 40 | 41 | /* ============================================================================================== */ 42 | /* Enums and types */ 43 | /* ============================================================================================== */ 44 | 45 | /** 46 | * Defines the `ZyanStatus` data type. 47 | */ 48 | typedef ZyanU32 ZyanStatus; 49 | 50 | /* ============================================================================================== */ 51 | /* Macros */ 52 | /* ============================================================================================== */ 53 | 54 | /* ---------------------------------------------------------------------------------------------- */ 55 | /* Definition */ 56 | /* ---------------------------------------------------------------------------------------------- */ 57 | 58 | /** 59 | * Defines a zyan status code. 60 | * 61 | * @param error `1`, if the status code signals an error or `0`, if not. 62 | * @param module The module id. 63 | * @param code The actual code. 64 | * 65 | * @return The zyan status code. 66 | */ 67 | #define ZYAN_MAKE_STATUS(error, module, code) \ 68 | (ZyanStatus)((((error) & 0x01u) << 31u) | (((module) & 0x7FFu) << 20u) | ((code) & 0xFFFFFu)) 69 | 70 | /* ---------------------------------------------------------------------------------------------- */ 71 | /* Checks */ 72 | /* ---------------------------------------------------------------------------------------------- */ 73 | 74 | /** 75 | * Checks if a zyan operation was successful. 76 | * 77 | * @param status The zyan status-code to check. 78 | * 79 | * @return `ZYAN_TRUE`, if the operation succeeded or `ZYAN_FALSE`, if not. 80 | */ 81 | #define ZYAN_SUCCESS(status) \ 82 | (!((status) & 0x80000000u)) 83 | 84 | /** 85 | * Checks if a zyan operation failed. 86 | * 87 | * @param status The zyan status-code to check. 88 | * 89 | * @return `ZYAN_TRUE`, if the operation failed or `ZYAN_FALSE`, if not. 90 | */ 91 | #define ZYAN_FAILED(status) \ 92 | ((status) & 0x80000000u) 93 | 94 | /** 95 | * Checks if a zyan operation was successful and returns with the status-code, if not. 96 | * 97 | * @param status The zyan status-code to check. 98 | */ 99 | #define ZYAN_CHECK(status) \ 100 | do \ 101 | { \ 102 | const ZyanStatus status_047620348 = (status); \ 103 | if (!ZYAN_SUCCESS(status_047620348)) \ 104 | { \ 105 | return status_047620348; \ 106 | } \ 107 | } while (0) 108 | 109 | /* ---------------------------------------------------------------------------------------------- */ 110 | /* Information */ 111 | /* ---------------------------------------------------------------------------------------------- */ 112 | 113 | /** 114 | * Returns the module id of a zyan status-code. 115 | * 116 | * @param status The zyan status-code. 117 | * 118 | * @return The module id of the zyan status-code. 119 | */ 120 | #define ZYAN_STATUS_MODULE(status) \ 121 | (((status) >> 20) & 0x7FFu) 122 | 123 | /** 124 | * Returns the code of a zyan status-code. 125 | * 126 | * @param status The zyan status-code. 127 | * 128 | * @return The code of the zyan status-code. 129 | */ 130 | #define ZYAN_STATUS_CODE(status) \ 131 | ((status) & 0xFFFFFu) 132 | 133 | /* ============================================================================================== */ 134 | /* Status codes */ 135 | /* ============================================================================================== */ 136 | 137 | /* ---------------------------------------------------------------------------------------------- */ 138 | /* Module IDs */ 139 | /* ---------------------------------------------------------------------------------------------- */ 140 | 141 | /** 142 | * The zycore generic module id. 143 | */ 144 | #define ZYAN_MODULE_ZYCORE 0x001u 145 | 146 | /** 147 | * The zycore arg-parse submodule id. 148 | */ 149 | #define ZYAN_MODULE_ARGPARSE 0x003u 150 | 151 | /** 152 | * The base module id for user-defined status codes. 153 | */ 154 | #define ZYAN_MODULE_USER 0x3FFu 155 | 156 | /* ---------------------------------------------------------------------------------------------- */ 157 | /* Status codes (general purpose) */ 158 | /* ---------------------------------------------------------------------------------------------- */ 159 | 160 | /** 161 | * The operation completed successfully. 162 | */ 163 | #define ZYAN_STATUS_SUCCESS \ 164 | ZYAN_MAKE_STATUS(0u, ZYAN_MODULE_ZYCORE, 0x00u) 165 | 166 | /** 167 | * The operation failed with an generic error. 168 | */ 169 | #define ZYAN_STATUS_FAILED \ 170 | ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYCORE, 0x01u) 171 | 172 | /** 173 | * The operation completed successfully and returned `ZYAN_TRUE`. 174 | */ 175 | #define ZYAN_STATUS_TRUE \ 176 | ZYAN_MAKE_STATUS(0u, ZYAN_MODULE_ZYCORE, 0x02u) 177 | 178 | /** 179 | * The operation completed successfully and returned `ZYAN_FALSE`. 180 | */ 181 | #define ZYAN_STATUS_FALSE \ 182 | ZYAN_MAKE_STATUS(0u, ZYAN_MODULE_ZYCORE, 0x03u) 183 | 184 | /** 185 | * An invalid argument was passed to a function. 186 | */ 187 | #define ZYAN_STATUS_INVALID_ARGUMENT \ 188 | ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYCORE, 0x04u) 189 | 190 | /** 191 | * An attempt was made to perform an invalid operation. 192 | */ 193 | #define ZYAN_STATUS_INVALID_OPERATION \ 194 | ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYCORE, 0x05u) 195 | 196 | /** 197 | * Insufficient privileges to perform the requested operation. 198 | */ 199 | #define ZYAN_STATUS_ACCESS_DENIED \ 200 | ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYCORE, 0x06u) 201 | 202 | /** 203 | * The requested entity was not found. 204 | */ 205 | #define ZYAN_STATUS_NOT_FOUND \ 206 | ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYCORE, 0x07u) 207 | 208 | /** 209 | * An index passed to a function was out of bounds. 210 | */ 211 | #define ZYAN_STATUS_OUT_OF_RANGE \ 212 | ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYCORE, 0x08u) 213 | 214 | /** 215 | * A buffer passed to a function was too small to complete the requested operation. 216 | */ 217 | #define ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE \ 218 | ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYCORE, 0x09u) 219 | 220 | /** 221 | * Insufficient memory to perform the operation. 222 | */ 223 | #define ZYAN_STATUS_NOT_ENOUGH_MEMORY \ 224 | ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYCORE, 0x0Au) 225 | 226 | /** 227 | * An unknown error occurred during a system function call. 228 | */ 229 | #define ZYAN_STATUS_BAD_SYSTEMCALL \ 230 | ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYCORE, 0x0Bu) 231 | 232 | /** 233 | * The process ran out of resources while performing an operation. 234 | */ 235 | #define ZYAN_STATUS_OUT_OF_RESOURCES \ 236 | ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYCORE, 0x0Cu) 237 | 238 | /** 239 | * A dependency library was not found or does have an unexpected version number or 240 | * feature-set. 241 | */ 242 | #define ZYAN_STATUS_MISSING_DEPENDENCY \ 243 | ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYCORE, 0x0Du) 244 | 245 | /* ---------------------------------------------------------------------------------------------- */ 246 | /* Status codes (arg parse) */ 247 | /* ---------------------------------------------------------------------------------------------- */ 248 | 249 | /** 250 | * Argument was not expected. 251 | */ 252 | #define ZYAN_STATUS_ARG_NOT_UNDERSTOOD \ 253 | ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ARGPARSE, 0x00u) 254 | 255 | /** 256 | * Too few arguments were provided. 257 | */ 258 | #define ZYAN_STATUS_TOO_FEW_ARGS \ 259 | ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ARGPARSE, 0x01u) 260 | 261 | /** 262 | * Too many arguments were provided. 263 | */ 264 | #define ZYAN_STATUS_TOO_MANY_ARGS \ 265 | ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ARGPARSE, 0x02u) 266 | 267 | /** 268 | * An argument that expected a value misses its value. 269 | */ 270 | #define ZYAN_STATUS_ARG_MISSES_VALUE \ 271 | ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ARGPARSE, 0x03u) 272 | 273 | /** 274 | * A required argument is missing. 275 | */ 276 | #define ZYAN_STATUS_REQUIRED_ARG_MISSING \ 277 | ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ARGPARSE, 0x04u) 278 | 279 | /* ---------------------------------------------------------------------------------------------- */ 280 | 281 | /* ============================================================================================== */ 282 | 283 | #ifdef __cplusplus 284 | } 285 | #endif 286 | 287 | #endif /* ZYCORE_STATUS_H */ 288 | -------------------------------------------------------------------------------- /include/Zycore/Zycore.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************************** 2 | 3 | Zyan Core Library (Zycore-C) 4 | 5 | Original Author : Florian Bernd 6 | 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | 25 | ***************************************************************************************************/ 26 | 27 | /** 28 | * @file 29 | * Master include file, including everything else. 30 | */ 31 | 32 | #ifndef ZYCORE_H 33 | #define ZYCORE_H 34 | 35 | #include 36 | 37 | // TODO: 38 | 39 | #ifdef __cplusplus 40 | extern "C" { 41 | #endif 42 | 43 | /* ============================================================================================== */ 44 | /* Macros */ 45 | /* ============================================================================================== */ 46 | 47 | /* ---------------------------------------------------------------------------------------------- */ 48 | /* Constants */ 49 | /* ---------------------------------------------------------------------------------------------- */ 50 | 51 | /** 52 | * A macro that defines the zycore version. 53 | */ 54 | #define ZYCORE_VERSION 0x0001000500020000ULL 55 | 56 | /* ---------------------------------------------------------------------------------------------- */ 57 | /* Helper macros */ 58 | /* ---------------------------------------------------------------------------------------------- */ 59 | 60 | /** 61 | * Extracts the major-part of the zycore version. 62 | * 63 | * @param version The zycore version value 64 | */ 65 | #define ZYCORE_VERSION_MAJOR(version) ((version & 0xFFFF000000000000) >> 48) 66 | 67 | /** 68 | * Extracts the minor-part of the zycore version. 69 | * 70 | * @param version The zycore version value 71 | */ 72 | #define ZYCORE_VERSION_MINOR(version) ((version & 0x0000FFFF00000000) >> 32) 73 | 74 | /** 75 | * Extracts the patch-part of the zycore version. 76 | * 77 | * @param version The zycore version value 78 | */ 79 | #define ZYCORE_VERSION_PATCH(version) ((version & 0x00000000FFFF0000) >> 16) 80 | 81 | /** 82 | * Extracts the build-part of the zycore version. 83 | * 84 | * @param version The zycore version value 85 | */ 86 | #define ZYCORE_VERSION_BUILD(version) (version & 0x000000000000FFFF) 87 | 88 | /* ---------------------------------------------------------------------------------------------- */ 89 | 90 | /* ============================================================================================== */ 91 | /* Exported functions */ 92 | /* ============================================================================================== */ 93 | 94 | /** 95 | * Returns the zycore version. 96 | * 97 | * @return The zycore version. 98 | * 99 | * Use the macros provided in this file to extract the major, minor, patch and build part from the 100 | * returned version value. 101 | */ 102 | ZYCORE_EXPORT ZyanU64 ZycoreGetVersion(void); 103 | 104 | /* ============================================================================================== */ 105 | 106 | #ifdef __cplusplus 107 | } 108 | #endif 109 | 110 | #endif /* ZYCORE_H */ 111 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | project( 2 | 'Zycore', 3 | 'c', 4 | version: '1.5.2', 5 | license: 'MIT', 6 | license_files: 'LICENSE', 7 | meson_version: '>=1.3', 8 | default_options: [ 9 | 'c_std=c11', 10 | 'cpp_std=c++17,vc++17', 11 | 'warning_level=3', 12 | ], 13 | ) 14 | 15 | cc = meson.get_compiler('c') 16 | 17 | if cc.get_argument_syntax() == 'msvc' 18 | if get_option('b_lto') 19 | add_project_arguments( 20 | '/GL', # -flto 21 | language: ['c', 'cpp'], 22 | ) 23 | add_project_link_arguments( 24 | '/LTCG', 25 | language: ['c', 'cpp'], 26 | ) 27 | endif 28 | endif 29 | 30 | inc = include_directories('include') 31 | 32 | dep = [] 33 | 34 | hdrs_api = files( 35 | # API 36 | 'include/Zycore/API/Memory.h', 37 | 'include/Zycore/API/Process.h', 38 | 'include/Zycore/API/Synchronization.h', 39 | 'include/Zycore/API/Terminal.h', 40 | 'include/Zycore/API/Thread.h', 41 | ) 42 | 43 | hdrs_common = files( 44 | # Common 45 | 'include/Zycore/Allocator.h', 46 | 'include/Zycore/ArgParse.h', 47 | 'include/Zycore/Atomic.h', 48 | 'include/Zycore/Bitset.h', 49 | 'include/Zycore/Comparison.h', 50 | 'include/Zycore/Defines.h', 51 | 'include/Zycore/Format.h', 52 | 'include/Zycore/LibC.h', 53 | 'include/Zycore/List.h', 54 | 'include/Zycore/Object.h', 55 | 'include/Zycore/Status.h', 56 | 'include/Zycore/String.h', 57 | 'include/Zycore/Types.h', 58 | 'include/Zycore/Vector.h', 59 | 'include/Zycore/Zycore.h', 60 | ) 61 | 62 | hdrs_internal = files( 63 | 'include/Zycore/Internal/AtomicGNU.h', 64 | 'include/Zycore/Internal/AtomicMSVC.h', 65 | ) 66 | 67 | hdrs = hdrs_api + hdrs_common + hdrs_internal 68 | 69 | src = files( 70 | # API 71 | 'src/API/Memory.c', 72 | 'src/API/Process.c', 73 | 'src/API/Synchronization.c', 74 | 'src/API/Terminal.c', 75 | 'src/API/Thread.c', 76 | # Common 77 | 'src/Allocator.c', 78 | 'src/ArgParse.c', 79 | 'src/Bitset.c', 80 | 'src/Format.c', 81 | 'src/List.c', 82 | 'src/String.c', 83 | 'src/Vector.c', 84 | 'src/Zycore.c', 85 | ) 86 | 87 | if host_machine.system() == 'windows' 88 | windows = import('windows') 89 | src += windows.compile_resources('resources/VersionInfo.rc') 90 | endif 91 | 92 | nolibc = get_option('nolibc') 93 | 94 | examples = get_option('examples') 95 | doc = get_option('doc') 96 | tests = get_option('tests') 97 | 98 | # Extra targets 99 | examples = examples.require(not nolibc) 100 | tests = tests.require(not nolibc) 101 | 102 | doc = doc.disable_auto_if(meson.is_subproject()) 103 | examples = examples.disable_auto_if(meson.is_subproject()) 104 | tests = tests.disable_auto_if(meson.is_subproject()) 105 | 106 | if nolibc 107 | add_project_arguments( 108 | '-DZYAN_NO_LIBC', 109 | '-fno-stack-protector', 110 | language: 'c', 111 | ) 112 | elif host_machine.system() == 'linux' 113 | add_project_arguments( 114 | '-D_GNU_SOURCE', 115 | language: 'c', 116 | ) 117 | dep += dependency('threads') 118 | endif 119 | 120 | zycore_lib = library( 121 | 'Zycore', 122 | src + hdrs, 123 | c_static_args: ['-DZYCORE_STATIC_BUILD'], 124 | c_shared_args: ['-DZYCORE_SHOULD_EXPORT'], 125 | link_args: (nolibc and cc.get_linker_id().startswith('ld.')) ? ['-nostdlib', '-nodefaultlibs'] : [], 126 | gnu_symbol_visibility: 'hidden', 127 | include_directories: inc, 128 | implicit_include_directories: false, 129 | dependencies: dep, 130 | version: meson.project_version(), 131 | install: true, 132 | ) 133 | 134 | install_headers(hdrs_common, subdir: 'Zycore') 135 | install_headers(hdrs_api, subdir: 'Zycore/API') 136 | install_headers(hdrs_internal, subdir: 'Zycore/Internal') 137 | 138 | extra_cflags = nolibc ? ['-DZYAN_NO_LIBC'] : [] 139 | 140 | # Note: on MSVC, define ZYCORE_STATIC_BUILD accordingly in the user project. 141 | zycore_dep = declare_dependency( 142 | include_directories: inc, 143 | link_with: zycore_lib, 144 | compile_args: extra_cflags, 145 | ) 146 | 147 | subdir('examples') 148 | subdir('tests') 149 | 150 | pkg = import('pkgconfig') 151 | pkg.generate( 152 | zycore_lib, 153 | name: 'zycore', 154 | description: 'Zyan Core Library for C', 155 | url: 'https://github.com/zyantific/zycore-c', 156 | extra_cflags: extra_cflags, 157 | ) 158 | 159 | meson.override_dependency('zycore', zycore_dep) 160 | 161 | doxygen_exe = find_program('doxygen', required: doc) 162 | doc_req = doxygen_exe.found() 163 | if doc_req 164 | cdata = configuration_data() 165 | cdata.set('VERSION', meson.project_version()) 166 | cdata.set('TOP_SRCDIR', meson.project_source_root()) 167 | cdata.set('TOP_BUILDDIR', meson.project_build_root()) 168 | 169 | dot_exe = find_program('dot', required: false) 170 | if dot_exe.found() 171 | cdata.set('HAVE_DOT', 'YES') 172 | cdata.set('DOT_PATH', dot_exe.full_path()) 173 | cdata.set( 174 | 'HAVE_DOT_1_8_10', 175 | dot_exe.version().version_compare('>=1.8.10') ? 'YES' : 'NO', 176 | ) 177 | else 178 | cdata.set('HAVE_DOT', 'NO') 179 | endif 180 | 181 | if find_program('pdf2svg', required: false).found() or find_program('inkscape', required: false).found() 182 | cdata.set('HTML_FORMULA_FORMAT', 'svg') 183 | else 184 | cdata.set('HTML_FORMULA_FORMAT', 'png') 185 | endif 186 | 187 | cdata.set('PREDEFINED', nolibc ? 'ZYAN_NO_LIBC' : '') 188 | 189 | doxyfile = configure_file( 190 | input: 'Doxyfile.in', 191 | output: 'Doxyfile', 192 | configuration: cdata, 193 | install: false, 194 | ) 195 | 196 | datadir = join_paths(get_option('datadir'), 'doc', 'Zycore') 197 | custom_target( 198 | 'ZycoreDoc', 199 | input: doxyfile, 200 | output: 'doc', 201 | command: [doxygen_exe, doxyfile], 202 | depend_files: [hdrs], 203 | install: true, 204 | install_dir: datadir, 205 | ) 206 | 207 | summary( 208 | { 209 | 'dot': cdata.get('HAVE_DOT') == 'YES', 210 | 'formula format': cdata.get('HTML_FORMULA_FORMAT'), 211 | }, 212 | section: 'Doxygen', 213 | ) 214 | endif 215 | 216 | summary( 217 | {'doc': doc_req, 'nolibc': nolibc}, 218 | section: 'Features', 219 | ) 220 | -------------------------------------------------------------------------------- /meson_options.txt: -------------------------------------------------------------------------------- 1 | option( 2 | 'nolibc', 3 | type: 'boolean', 4 | value: false, 5 | description: 'Do not use any C standard library functions (for exotic build-envs like kernel drivers)', 6 | yield: true, 7 | ) 8 | option( 9 | 'doc', 10 | type: 'feature', 11 | description: 'Build doxygen documentation (requires Doxygen)', 12 | ) 13 | option( 14 | 'examples', 15 | type: 'feature', 16 | description: 'Build examples', 17 | ) 18 | option( 19 | 'tests', 20 | type: 'feature', 21 | description: 'Build tests', 22 | ) 23 | -------------------------------------------------------------------------------- /resources/VersionInfo.rc: -------------------------------------------------------------------------------- 1 | /*************************************************************************************************** 2 | 3 | Zyan Disassembler Library (Zydis) 4 | 5 | Original Author : Florian Bernd 6 | 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | 25 | ***************************************************************************************************/ 26 | 27 | #include "winres.h" 28 | 29 | VS_VERSION_INFO VERSIONINFO 30 | FILEVERSION 1,5,2,0 31 | PRODUCTVERSION 1,5,2,0 32 | FILEFLAGSMASK 0x3fL 33 | #ifdef _DEBUG 34 | FILEFLAGS 0x1L 35 | #else 36 | FILEFLAGS 0x0L 37 | #endif 38 | FILEOS 0x40000L 39 | FILETYPE 0x2L 40 | FILESUBTYPE 0x0L 41 | BEGIN 42 | BLOCK "StringFileInfo" 43 | BEGIN 44 | BLOCK "040004b0" 45 | BEGIN 46 | VALUE "CompanyName", "zyantific" 47 | VALUE "FileDescription", "Zyan Core Library for C" 48 | VALUE "FileVersion", "1.5.2.0" 49 | VALUE "InternalName", "Zycore" 50 | VALUE "LegalCopyright", "Copyright \xA9 2018-2025 by zyantific.com" 51 | VALUE "OriginalFilename", "Zycore.dll" 52 | VALUE "ProductName", "Zyan Core Library for C" 53 | VALUE "ProductVersion", "1.5.2.0" 54 | END 55 | END 56 | BLOCK "VarFileInfo" 57 | BEGIN 58 | VALUE "Translation", 0x400, 1200 59 | END 60 | END 61 | -------------------------------------------------------------------------------- /src/API/Memory.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************************** 2 | 3 | Zyan Core Library (Zycore-C) 4 | 5 | Original Author : Florian Bernd 6 | 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | 25 | ***************************************************************************************************/ 26 | 27 | #include 28 | 29 | #ifndef ZYAN_NO_LIBC 30 | 31 | #if defined(ZYAN_WINDOWS) 32 | 33 | #elif defined(ZYAN_POSIX) 34 | # include 35 | #else 36 | # error "Unsupported platform detected" 37 | #endif 38 | 39 | /* ============================================================================================== */ 40 | /* Exported functions */ 41 | /* ============================================================================================== */ 42 | 43 | /* ---------------------------------------------------------------------------------------------- */ 44 | /* General */ 45 | /* ---------------------------------------------------------------------------------------------- */ 46 | 47 | ZyanU32 ZyanMemoryGetSystemPageSize(void) 48 | { 49 | #if defined(ZYAN_WINDOWS) 50 | 51 | SYSTEM_INFO system_info; 52 | GetSystemInfo(&system_info); 53 | 54 | return system_info.dwPageSize; 55 | 56 | #elif defined(ZYAN_POSIX) 57 | 58 | return sysconf(_SC_PAGE_SIZE); 59 | 60 | #endif 61 | } 62 | 63 | ZyanU32 ZyanMemoryGetSystemAllocationGranularity(void) 64 | { 65 | #if defined(ZYAN_WINDOWS) 66 | 67 | SYSTEM_INFO system_info; 68 | GetSystemInfo(&system_info); 69 | 70 | return system_info.dwAllocationGranularity; 71 | 72 | #elif defined(ZYAN_POSIX) 73 | 74 | return sysconf(_SC_PAGE_SIZE); 75 | 76 | #endif 77 | } 78 | 79 | /* ---------------------------------------------------------------------------------------------- */ 80 | /* Memory management */ 81 | /* ---------------------------------------------------------------------------------------------- */ 82 | 83 | ZyanStatus ZyanMemoryVirtualProtect(void* address, ZyanUSize size, 84 | ZyanMemoryPageProtection protection) 85 | { 86 | #if defined(ZYAN_WINDOWS) 87 | 88 | DWORD old; 89 | if (!VirtualProtect(address, size, protection, &old)) 90 | { 91 | return ZYAN_STATUS_BAD_SYSTEMCALL; 92 | } 93 | 94 | #elif defined(ZYAN_POSIX) 95 | 96 | if (mprotect(address, size, protection)) 97 | { 98 | return ZYAN_STATUS_BAD_SYSTEMCALL; 99 | } 100 | 101 | #endif 102 | 103 | return ZYAN_STATUS_SUCCESS; 104 | } 105 | 106 | ZyanStatus ZyanMemoryVirtualFree(void* address, ZyanUSize size) 107 | { 108 | #if defined(ZYAN_WINDOWS) 109 | 110 | ZYAN_UNUSED(size); 111 | if (!VirtualFree(address, 0, MEM_RELEASE)) 112 | { 113 | return ZYAN_STATUS_BAD_SYSTEMCALL; 114 | } 115 | 116 | #elif defined(ZYAN_POSIX) 117 | 118 | if (munmap(address, size)) 119 | { 120 | return ZYAN_STATUS_BAD_SYSTEMCALL; 121 | } 122 | 123 | #endif 124 | 125 | return ZYAN_STATUS_SUCCESS; 126 | } 127 | 128 | /* ---------------------------------------------------------------------------------------------- */ 129 | 130 | /* ============================================================================================== */ 131 | 132 | #endif /* ZYAN_NO_LIBC */ 133 | -------------------------------------------------------------------------------- /src/API/Process.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************************** 2 | 3 | Zyan Core Library (Zycore-C) 4 | 5 | Original Author : Florian Bernd 6 | 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | 25 | ***************************************************************************************************/ 26 | 27 | #include 28 | #include 29 | 30 | #ifndef ZYAN_NO_LIBC 31 | 32 | #if defined(ZYAN_WINDOWS) 33 | #if defined(ZYAN_KERNEL) 34 | # include 35 | #else 36 | # include 37 | #endif 38 | #elif defined(ZYAN_POSIX) 39 | # include 40 | #else 41 | # error "Unsupported platform detected" 42 | #endif 43 | 44 | /* ============================================================================================== */ 45 | /* Exported functions */ 46 | /* ============================================================================================== */ 47 | 48 | /* ---------------------------------------------------------------------------------------------- */ 49 | /* General */ 50 | /* ---------------------------------------------------------------------------------------------- */ 51 | 52 | ZyanStatus ZyanProcessFlushInstructionCache(void* address, ZyanUSize size) 53 | { 54 | #if defined(ZYAN_WINDOWS) 55 | 56 | if (!FlushInstructionCache(GetCurrentProcess(), address, size)) 57 | { 58 | return ZYAN_STATUS_BAD_SYSTEMCALL; 59 | } 60 | 61 | #elif defined(ZYAN_POSIX) 62 | 63 | if (msync(address, size, MS_SYNC | MS_INVALIDATE)) 64 | { 65 | return ZYAN_STATUS_BAD_SYSTEMCALL; 66 | } 67 | 68 | #endif 69 | 70 | return ZYAN_STATUS_SUCCESS; 71 | } 72 | 73 | /* ---------------------------------------------------------------------------------------------- */ 74 | 75 | /* ============================================================================================== */ 76 | 77 | #endif /* ZYAN_NO_LIBC */ 78 | -------------------------------------------------------------------------------- /src/API/Synchronization.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************************** 2 | 3 | Zyan Core Library (Zycore-C) 4 | 5 | Original Author : Florian Bernd 6 | 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | 25 | ***************************************************************************************************/ 26 | 27 | #include 28 | 29 | #ifndef ZYAN_NO_LIBC 30 | 31 | /* ============================================================================================== */ 32 | /* Internal functions */ 33 | /* ============================================================================================== */ 34 | 35 | /* ---------------------------------------------------------------------------------------------- */ 36 | /* */ 37 | /* ---------------------------------------------------------------------------------------------- */ 38 | 39 | 40 | 41 | /* ---------------------------------------------------------------------------------------------- */ 42 | 43 | /* ============================================================================================== */ 44 | /* Exported functions */ 45 | /* ============================================================================================== */ 46 | 47 | #if defined(ZYAN_POSIX) 48 | 49 | #include 50 | 51 | /* ---------------------------------------------------------------------------------------------- */ 52 | /* Critical Section */ 53 | /* ---------------------------------------------------------------------------------------------- */ 54 | 55 | ZyanStatus ZyanCriticalSectionInitialize(ZyanCriticalSection* critical_section) 56 | { 57 | pthread_mutexattr_t attribute; 58 | 59 | int error = pthread_mutexattr_init(&attribute); 60 | if (error != 0) 61 | { 62 | if (error == ENOMEM) 63 | { 64 | return ZYAN_STATUS_NOT_ENOUGH_MEMORY; 65 | } 66 | return ZYAN_STATUS_BAD_SYSTEMCALL; 67 | } 68 | pthread_mutexattr_settype(&attribute, PTHREAD_MUTEX_RECURSIVE); 69 | 70 | error = pthread_mutex_init(critical_section, &attribute); 71 | pthread_mutexattr_destroy(&attribute); 72 | if (error != 0) 73 | { 74 | if (error == EAGAIN) 75 | { 76 | return ZYAN_STATUS_OUT_OF_RESOURCES; 77 | } 78 | if (error == ENOMEM) 79 | { 80 | return ZYAN_STATUS_NOT_ENOUGH_MEMORY; 81 | } 82 | if (error == EPERM) 83 | { 84 | return ZYAN_STATUS_ACCESS_DENIED; 85 | } 86 | if ((error == EBUSY) || (error == EINVAL)) 87 | { 88 | return ZYAN_STATUS_INVALID_ARGUMENT; 89 | } 90 | return ZYAN_STATUS_BAD_SYSTEMCALL; 91 | } 92 | 93 | return ZYAN_STATUS_SUCCESS; 94 | } 95 | 96 | ZyanStatus ZyanCriticalSectionEnter(ZyanCriticalSection* critical_section) 97 | { 98 | const int error = pthread_mutex_lock(critical_section); 99 | if (error != 0) 100 | { 101 | if (error == EINVAL) 102 | { 103 | return ZYAN_STATUS_INVALID_ARGUMENT; 104 | } 105 | if (error == EAGAIN) 106 | { 107 | return ZYAN_STATUS_INVALID_OPERATION; 108 | } 109 | return ZYAN_STATUS_BAD_SYSTEMCALL; 110 | } 111 | 112 | return ZYAN_STATUS_SUCCESS; 113 | } 114 | 115 | ZyanBool ZyanCriticalSectionTryEnter(ZyanCriticalSection* critical_section) 116 | { 117 | // No fine grained error handling for this one 118 | return pthread_mutex_trylock(critical_section) ? ZYAN_FALSE : ZYAN_TRUE; 119 | } 120 | 121 | ZyanStatus ZyanCriticalSectionLeave(ZyanCriticalSection* critical_section) 122 | { 123 | const int error = pthread_mutex_unlock(critical_section); 124 | if (error != 0) 125 | { 126 | if (error == EINVAL) 127 | { 128 | return ZYAN_STATUS_INVALID_ARGUMENT; 129 | } 130 | if (error == EPERM) 131 | { 132 | return ZYAN_STATUS_INVALID_OPERATION; 133 | } 134 | return ZYAN_STATUS_BAD_SYSTEMCALL; 135 | } 136 | 137 | return ZYAN_STATUS_SUCCESS; 138 | } 139 | 140 | ZyanStatus ZyanCriticalSectionDelete(ZyanCriticalSection* critical_section) 141 | { 142 | const int error = pthread_mutex_destroy(critical_section); 143 | if (error != 0) 144 | { 145 | if ((error == EBUSY) || (error == EINVAL)) 146 | { 147 | return ZYAN_STATUS_INVALID_ARGUMENT; 148 | } 149 | return ZYAN_STATUS_BAD_SYSTEMCALL; 150 | } 151 | 152 | return ZYAN_STATUS_SUCCESS; 153 | } 154 | 155 | /* ---------------------------------------------------------------------------------------------- */ 156 | 157 | #elif defined(ZYAN_WINDOWS) 158 | 159 | /* ---------------------------------------------------------------------------------------------- */ 160 | /* General */ 161 | /* ---------------------------------------------------------------------------------------------- */ 162 | 163 | ZyanStatus ZyanCriticalSectionInitialize(ZyanCriticalSection* critical_section) 164 | { 165 | InitializeCriticalSection(critical_section); 166 | 167 | return ZYAN_STATUS_SUCCESS; 168 | } 169 | 170 | ZyanStatus ZyanCriticalSectionEnter(ZyanCriticalSection* critical_section) 171 | { 172 | EnterCriticalSection(critical_section); 173 | 174 | return ZYAN_STATUS_SUCCESS; 175 | } 176 | 177 | ZyanBool ZyanCriticalSectionTryEnter(ZyanCriticalSection* critical_section) 178 | { 179 | return TryEnterCriticalSection(critical_section) ? ZYAN_TRUE : ZYAN_FALSE; 180 | } 181 | 182 | ZyanStatus ZyanCriticalSectionLeave(ZyanCriticalSection* critical_section) 183 | { 184 | LeaveCriticalSection(critical_section); 185 | 186 | return ZYAN_STATUS_SUCCESS; 187 | } 188 | 189 | ZyanStatus ZyanCriticalSectionDelete(ZyanCriticalSection* critical_section) 190 | { 191 | DeleteCriticalSection(critical_section); 192 | 193 | return ZYAN_STATUS_SUCCESS; 194 | } 195 | 196 | /* ---------------------------------------------------------------------------------------------- */ 197 | 198 | #else 199 | # error "Unsupported platform detected" 200 | #endif 201 | 202 | /* ============================================================================================== */ 203 | 204 | #endif /* ZYAN_NO_LIBC */ 205 | -------------------------------------------------------------------------------- /src/API/Terminal.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************************** 2 | 3 | Zyan Core Library (Zycore-C) 4 | 5 | Original Author : Florian Bernd 6 | 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | 25 | ***************************************************************************************************/ 26 | 27 | #include 28 | 29 | #ifndef ZYAN_NO_LIBC 30 | 31 | #if defined(ZYAN_POSIX) 32 | # include 33 | #elif defined(ZYAN_WINDOWS) 34 | # include 35 | # include 36 | #else 37 | # error "Unsupported platform detected" 38 | #endif 39 | 40 | // Provide fallback for old SDK versions 41 | #ifdef ZYAN_WINDOWS 42 | # ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING 43 | # define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 44 | # endif 45 | #endif 46 | 47 | /* ============================================================================================== */ 48 | /* Exported functions */ 49 | /* ============================================================================================== */ 50 | 51 | ZyanStatus ZyanTerminalEnableVT100(ZyanStandardStream stream) 52 | { 53 | if ((stream != ZYAN_STDSTREAM_OUT) && (stream != ZYAN_STDSTREAM_ERR)) 54 | { 55 | return ZYAN_STATUS_INVALID_ARGUMENT; 56 | } 57 | 58 | #ifdef ZYAN_WINDOWS 59 | // Get file descriptor 60 | int file; 61 | switch (stream) 62 | { 63 | case ZYAN_STDSTREAM_OUT: 64 | file = _fileno(ZYAN_STDOUT); 65 | break; 66 | case ZYAN_STDSTREAM_ERR: 67 | file = _fileno(ZYAN_STDERR); 68 | break; 69 | default: 70 | ZYAN_UNREACHABLE; 71 | } 72 | if (file < 0) 73 | { 74 | return ZYAN_STATUS_INVALID_ARGUMENT; 75 | } 76 | 77 | HANDLE const handle = (HANDLE)_get_osfhandle(file); 78 | if (handle == INVALID_HANDLE_VALUE) 79 | { 80 | return ZYAN_STATUS_INVALID_ARGUMENT; 81 | } 82 | 83 | DWORD mode; 84 | if (!GetConsoleMode(handle, &mode)) 85 | { 86 | // The given standard stream is not bound to a terminal 87 | return ZYAN_STATUS_INVALID_ARGUMENT; 88 | } 89 | 90 | mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; 91 | if (!SetConsoleMode(handle, mode)) 92 | { 93 | return ZYAN_STATUS_BAD_SYSTEMCALL; 94 | } 95 | #endif 96 | 97 | return ZYAN_STATUS_SUCCESS; 98 | } 99 | 100 | ZyanStatus ZyanTerminalIsTTY(ZyanStandardStream stream) 101 | { 102 | // Get file descriptor 103 | int file; 104 | #ifdef ZYAN_WINDOWS 105 | switch (stream) 106 | { 107 | case ZYAN_STDSTREAM_IN: 108 | file = _fileno(ZYAN_STDIN); 109 | break; 110 | case ZYAN_STDSTREAM_OUT: 111 | file = _fileno(ZYAN_STDOUT); 112 | break; 113 | case ZYAN_STDSTREAM_ERR: 114 | file = _fileno(ZYAN_STDERR); 115 | break; 116 | default: 117 | ZYAN_UNREACHABLE; 118 | } 119 | if (file < 0) 120 | { 121 | return ZYAN_STATUS_INVALID_ARGUMENT; 122 | } 123 | #else 124 | switch (stream) 125 | { 126 | case ZYAN_STDSTREAM_IN: 127 | file = STDIN_FILENO; 128 | break; 129 | case ZYAN_STDSTREAM_OUT: 130 | file = STDOUT_FILENO; 131 | break; 132 | case ZYAN_STDSTREAM_ERR: 133 | file = STDERR_FILENO; 134 | break; 135 | default: 136 | ZYAN_UNREACHABLE; 137 | } 138 | #endif 139 | 140 | #ifdef ZYAN_WINDOWS 141 | if (_isatty(file)) 142 | #else 143 | if ( isatty(file)) 144 | #endif 145 | { 146 | return ZYAN_STATUS_TRUE; 147 | } 148 | if (ZYAN_ERRNO == EBADF) 149 | { 150 | // Invalid file descriptor 151 | return ZYAN_STATUS_INVALID_ARGUMENT; 152 | } 153 | //ZYAN_ASSERT((errno == EINVAL) || (errno == ENOTTY)); 154 | 155 | return ZYAN_STATUS_FALSE; 156 | } 157 | 158 | /* ============================================================================================== */ 159 | 160 | #endif /* ZYAN_NO_LIBC */ 161 | -------------------------------------------------------------------------------- /src/API/Thread.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************************** 2 | 3 | Zyan Core Library (Zycore-C) 4 | 5 | Original Author : Florian Bernd 6 | 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | 25 | ***************************************************************************************************/ 26 | 27 | #include 28 | 29 | #ifndef ZYAN_NO_LIBC 30 | 31 | /* ============================================================================================== */ 32 | /* Internal functions */ 33 | /* ============================================================================================== */ 34 | 35 | /* ---------------------------------------------------------------------------------------------- */ 36 | /* Legacy Windows import declarations */ 37 | /* ---------------------------------------------------------------------------------------------- */ 38 | 39 | #if defined(ZYAN_WINDOWS) && defined(_WIN32_WINNT) && \ 40 | (_WIN32_WINNT >= 0x0501) && (_WIN32_WINNT < 0x0600) 41 | 42 | /** 43 | * The Windows SDK conditionally declares the following prototypes: the target OS must be Vista 44 | * (0x0600) or above. MSDN states the same incorrect minimum requirement for the Fls* functions. 45 | * 46 | * However, these functions exist and work perfectly fine on XP (SP3) and Server 2003. 47 | * Preserve backward compatibility with these OSes by declaring the prototypes here if needed. 48 | */ 49 | 50 | #ifndef FLS_OUT_OF_INDEXES 51 | #define FLS_OUT_OF_INDEXES ((DWORD)0xFFFFFFFF) 52 | #endif 53 | 54 | WINBASEAPI 55 | DWORD 56 | WINAPI 57 | FlsAlloc( 58 | _In_opt_ PFLS_CALLBACK_FUNCTION lpCallback 59 | ); 60 | 61 | WINBASEAPI 62 | PVOID 63 | WINAPI 64 | FlsGetValue( 65 | _In_ DWORD dwFlsIndex 66 | ); 67 | 68 | WINBASEAPI 69 | BOOL 70 | WINAPI 71 | FlsSetValue( 72 | _In_ DWORD dwFlsIndex, 73 | _In_opt_ PVOID lpFlsData 74 | ); 75 | 76 | WINBASEAPI 77 | BOOL 78 | WINAPI 79 | FlsFree( 80 | _In_ DWORD dwFlsIndex 81 | ); 82 | 83 | #endif /* (_WIN32_WINNT >= 0x0501) && (_WIN32_WINNT < 0x0600)*/ 84 | 85 | 86 | 87 | /* ---------------------------------------------------------------------------------------------- */ 88 | 89 | /* ============================================================================================== */ 90 | /* Exported functions */ 91 | /* ============================================================================================== */ 92 | 93 | #if defined(ZYAN_POSIX) 94 | 95 | #include 96 | 97 | /* ---------------------------------------------------------------------------------------------- */ 98 | /* General */ 99 | /* ---------------------------------------------------------------------------------------------- */ 100 | 101 | ZyanStatus ZyanThreadGetCurrentThread(ZyanThread* thread) 102 | { 103 | *thread = pthread_self(); 104 | 105 | return ZYAN_STATUS_SUCCESS; 106 | } 107 | 108 | ZYAN_STATIC_ASSERT(sizeof(ZyanThreadId) <= sizeof(ZyanU64)); 109 | ZyanStatus ZyanThreadGetCurrentThreadId(ZyanThreadId* thread_id) 110 | { 111 | // TODO: Use `pthread_getthreadid_np` on platforms where it is available 112 | 113 | pthread_t ptid = pthread_self(); 114 | *thread_id = *(ZyanThreadId*)ptid; 115 | 116 | return ZYAN_STATUS_SUCCESS; 117 | } 118 | 119 | /* ---------------------------------------------------------------------------------------------- */ 120 | /* Thread Local Storage */ 121 | /* ---------------------------------------------------------------------------------------------- */ 122 | 123 | ZyanStatus ZyanThreadTlsAlloc(ZyanThreadTlsIndex* index, ZyanThreadTlsCallback destructor) 124 | { 125 | ZyanThreadTlsIndex value; 126 | const int error = pthread_key_create(&value, destructor); 127 | if (error != 0) 128 | { 129 | if (error == EAGAIN) 130 | { 131 | return ZYAN_STATUS_OUT_OF_RESOURCES; 132 | } 133 | if (error == ENOMEM) 134 | { 135 | return ZYAN_STATUS_NOT_ENOUGH_MEMORY; 136 | } 137 | return ZYAN_STATUS_BAD_SYSTEMCALL; 138 | } 139 | 140 | *index = value; 141 | return ZYAN_STATUS_SUCCESS; 142 | } 143 | 144 | ZyanStatus ZyanThreadTlsFree(ZyanThreadTlsIndex index) 145 | { 146 | return !pthread_key_delete(index) ? ZYAN_STATUS_SUCCESS : ZYAN_STATUS_BAD_SYSTEMCALL; 147 | } 148 | 149 | ZyanStatus ZyanThreadTlsGetValue(ZyanThreadTlsIndex index, void** data) 150 | { 151 | *data = pthread_getspecific(index); 152 | 153 | return ZYAN_STATUS_SUCCESS; 154 | } 155 | 156 | ZyanStatus ZyanThreadTlsSetValue(ZyanThreadTlsIndex index, void* data) 157 | { 158 | const int error = pthread_setspecific(index, data); 159 | if (error != 0) 160 | { 161 | if (error == EINVAL) 162 | { 163 | return ZYAN_STATUS_INVALID_ARGUMENT; 164 | } 165 | return ZYAN_STATUS_BAD_SYSTEMCALL; 166 | } 167 | 168 | return ZYAN_STATUS_SUCCESS; 169 | } 170 | 171 | /* ---------------------------------------------------------------------------------------------- */ 172 | 173 | #elif defined(ZYAN_WINDOWS) 174 | 175 | /* ---------------------------------------------------------------------------------------------- */ 176 | /* General */ 177 | /* ---------------------------------------------------------------------------------------------- */ 178 | 179 | ZyanStatus ZyanThreadGetCurrentThread(ZyanThread* thread) 180 | { 181 | *thread = GetCurrentThread(); 182 | 183 | return ZYAN_STATUS_SUCCESS; 184 | } 185 | 186 | ZyanStatus ZyanThreadGetCurrentThreadId(ZyanThreadId* thread_id) 187 | { 188 | *thread_id = GetCurrentThreadId(); 189 | 190 | return ZYAN_STATUS_SUCCESS; 191 | } 192 | 193 | /* ---------------------------------------------------------------------------------------------- */ 194 | /* Thread Local Storage (TLS) */ 195 | /* ---------------------------------------------------------------------------------------------- */ 196 | 197 | ZyanStatus ZyanThreadTlsAlloc(ZyanThreadTlsIndex* index, ZyanThreadTlsCallback destructor) 198 | { 199 | const ZyanThreadTlsIndex value = FlsAlloc(destructor); 200 | if (value == FLS_OUT_OF_INDEXES) 201 | { 202 | return ZYAN_STATUS_OUT_OF_RESOURCES; 203 | } 204 | 205 | *index = value; 206 | return ZYAN_STATUS_SUCCESS; 207 | } 208 | 209 | ZyanStatus ZyanThreadTlsFree(ZyanThreadTlsIndex index) 210 | { 211 | return FlsFree(index) ? ZYAN_STATUS_SUCCESS : ZYAN_STATUS_BAD_SYSTEMCALL; 212 | } 213 | 214 | ZyanStatus ZyanThreadTlsGetValue(ZyanThreadTlsIndex index, void** data) 215 | { 216 | *data = FlsGetValue(index); 217 | 218 | return ZYAN_STATUS_SUCCESS; 219 | } 220 | 221 | ZyanStatus ZyanThreadTlsSetValue(ZyanThreadTlsIndex index, void* data) 222 | { 223 | if (!FlsSetValue(index, data)) 224 | { 225 | const DWORD error = GetLastError(); 226 | if (error == ERROR_INVALID_PARAMETER) 227 | { 228 | return ZYAN_STATUS_INVALID_ARGUMENT; 229 | } 230 | return ZYAN_STATUS_BAD_SYSTEMCALL; 231 | } 232 | 233 | return ZYAN_STATUS_SUCCESS; 234 | } 235 | 236 | /* ---------------------------------------------------------------------------------------------- */ 237 | 238 | #else 239 | # error "Unsupported platform detected" 240 | #endif 241 | 242 | /* ============================================================================================== */ 243 | 244 | #endif /* ZYAN_NO_LIBC */ 245 | -------------------------------------------------------------------------------- /src/Allocator.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************************** 2 | 3 | Zyan Core Library (Zycore-C) 4 | 5 | Original Author : Florian Bernd 6 | 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | 25 | ***************************************************************************************************/ 26 | 27 | #include 28 | #include 29 | 30 | /* ============================================================================================== */ 31 | /* Internal functions */ 32 | /* ============================================================================================== */ 33 | 34 | /* ---------------------------------------------------------------------------------------------- */ 35 | /* Default allocator */ 36 | /* ---------------------------------------------------------------------------------------------- */ 37 | 38 | #ifndef ZYAN_NO_LIBC 39 | 40 | static ZyanStatus ZyanAllocatorDefaultAllocate(ZyanAllocator* allocator, void** p, 41 | ZyanUSize element_size, ZyanUSize n) 42 | { 43 | ZYAN_ASSERT(allocator); 44 | ZYAN_ASSERT(p); 45 | ZYAN_ASSERT(element_size); 46 | ZYAN_ASSERT(n); 47 | 48 | ZYAN_UNUSED(allocator); 49 | 50 | *p = ZYAN_MALLOC(element_size * n); 51 | if (!*p) 52 | { 53 | return ZYAN_STATUS_NOT_ENOUGH_MEMORY; 54 | } 55 | 56 | return ZYAN_STATUS_SUCCESS; 57 | } 58 | 59 | static ZyanStatus ZyanAllocatorDefaultReallocate(ZyanAllocator* allocator, void** p, 60 | ZyanUSize element_size, ZyanUSize n) 61 | { 62 | ZYAN_ASSERT(allocator); 63 | ZYAN_ASSERT(p); 64 | ZYAN_ASSERT(element_size); 65 | ZYAN_ASSERT(n); 66 | 67 | ZYAN_UNUSED(allocator); 68 | 69 | void* const x = ZYAN_REALLOC(*p, element_size * n); 70 | if (!x) 71 | { 72 | return ZYAN_STATUS_NOT_ENOUGH_MEMORY; 73 | } 74 | *p = x; 75 | 76 | return ZYAN_STATUS_SUCCESS; 77 | } 78 | 79 | static ZyanStatus ZyanAllocatorDefaultDeallocate(ZyanAllocator* allocator, void* p, 80 | ZyanUSize element_size, ZyanUSize n) 81 | { 82 | ZYAN_ASSERT(allocator); 83 | ZYAN_ASSERT(p); 84 | ZYAN_ASSERT(element_size); 85 | ZYAN_ASSERT(n); 86 | 87 | ZYAN_UNUSED(allocator); 88 | ZYAN_UNUSED(element_size); 89 | ZYAN_UNUSED(n); 90 | 91 | ZYAN_FREE(p); 92 | 93 | return ZYAN_STATUS_SUCCESS; 94 | } 95 | 96 | #endif // ZYAN_NO_LIBC 97 | 98 | /* ---------------------------------------------------------------------------------------------- */ 99 | 100 | /* ============================================================================================== */ 101 | /* Exported functions */ 102 | /* ============================================================================================== */ 103 | 104 | ZyanStatus ZyanAllocatorInit(ZyanAllocator* allocator, ZyanAllocatorAllocate allocate, 105 | ZyanAllocatorAllocate reallocate, ZyanAllocatorDeallocate deallocate) 106 | { 107 | if (!allocator || !allocate || !reallocate || !deallocate) 108 | { 109 | return ZYAN_STATUS_INVALID_ARGUMENT; 110 | } 111 | 112 | allocator->allocate = allocate; 113 | allocator->reallocate = reallocate; 114 | allocator->deallocate = deallocate; 115 | 116 | return ZYAN_STATUS_SUCCESS; 117 | } 118 | 119 | #ifndef ZYAN_NO_LIBC 120 | 121 | ZyanAllocator* ZyanAllocatorDefault(void) 122 | { 123 | static ZyanAllocator allocator = 124 | { 125 | &ZyanAllocatorDefaultAllocate, 126 | &ZyanAllocatorDefaultReallocate, 127 | &ZyanAllocatorDefaultDeallocate 128 | }; 129 | return &allocator; 130 | } 131 | 132 | #endif 133 | 134 | /* ============================================================================================== */ 135 | -------------------------------------------------------------------------------- /src/ArgParse.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************************** 2 | 3 | Zyan Core Library (Zycore-C) 4 | 5 | Original Author : Joel Hoener 6 | 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | 25 | ***************************************************************************************************/ 26 | 27 | #include 28 | #include 29 | 30 | /* ============================================================================================== */ 31 | /* Exported functions */ 32 | /* ============================================================================================== */ 33 | 34 | #ifndef ZYAN_NO_LIBC 35 | 36 | ZyanStatus ZyanArgParse(const ZyanArgParseConfig *cfg, ZyanVector* parsed, 37 | const char** error_token) 38 | { 39 | return ZyanArgParseEx(cfg, parsed, error_token, ZyanAllocatorDefault()); 40 | } 41 | 42 | #endif 43 | 44 | ZyanStatus ZyanArgParseEx(const ZyanArgParseConfig *cfg, ZyanVector* parsed, 45 | const char** error_token, ZyanAllocator* allocator) 46 | { 47 | # define ZYAN_ERR_TOK(tok) if (error_token) { *error_token = tok; } 48 | 49 | ZYAN_ASSERT(cfg); 50 | ZYAN_ASSERT(parsed); 51 | 52 | // TODO: Once we have a decent hash map impl, refactor this to use it. The majority of for 53 | // loops through the argument list could be avoided. 54 | 55 | if (cfg->min_unnamed_args > cfg->max_unnamed_args) 56 | { 57 | return ZYAN_STATUS_INVALID_ARGUMENT; 58 | } 59 | 60 | // Check argument syntax. 61 | for (const ZyanArgParseDefinition* def = cfg->args; def && def->name; ++def) 62 | { 63 | // TODO: Duplicate check 64 | 65 | if (!def->name) 66 | { 67 | return ZYAN_STATUS_INVALID_ARGUMENT; 68 | } 69 | 70 | ZyanUSize arg_len = ZYAN_STRLEN(def->name); 71 | if (arg_len < 2 || def->name[0] != '-') 72 | { 73 | return ZYAN_STATUS_INVALID_ARGUMENT; 74 | } 75 | 76 | // Single dash arguments only accept a single char name. 77 | if (def->name[1] != '-' && arg_len != 2) 78 | { 79 | return ZYAN_STATUS_INVALID_ARGUMENT; 80 | } 81 | } 82 | 83 | // Initialize output vector. 84 | ZYAN_CHECK(ZyanVectorInitEx(parsed, sizeof(ZyanArgParseArg), cfg->argc, ZYAN_NULL, allocator, 85 | ZYAN_VECTOR_DEFAULT_GROWTH_FACTOR, ZYAN_VECTOR_DEFAULT_SHRINK_THRESHOLD)); 86 | 87 | ZyanStatus err; 88 | ZyanBool accept_dash_args = ZYAN_TRUE; 89 | ZyanUSize num_unnamed_args = 0; 90 | for (ZyanUSize i = 1; i < cfg->argc; ++i) 91 | { 92 | const char* cur_arg = cfg->argv[i]; 93 | ZyanUSize arg_len = ZYAN_STRLEN(cfg->argv[i]); 94 | 95 | // Double-dash argument? 96 | if (accept_dash_args && arg_len >= 2 && ZYAN_MEMCMP(cur_arg, "--", 2) == 0) 97 | { 98 | // GNU style end of argument parsing. 99 | if (arg_len == 2) 100 | { 101 | accept_dash_args = ZYAN_FALSE; 102 | } 103 | // Regular double-dash argument. 104 | else 105 | { 106 | // Allocate parsed argument struct. 107 | ZyanArgParseArg* parsed_arg; 108 | ZYAN_CHECK(ZyanVectorEmplace(parsed, (void**)&parsed_arg, ZYAN_NULL)); 109 | ZYAN_MEMSET(parsed_arg, 0, sizeof(*parsed_arg)); 110 | 111 | // Find corresponding argument definition. 112 | for (const ZyanArgParseDefinition* def = cfg->args; def && def->name; ++def) 113 | { 114 | if (ZYAN_STRCMP(def->name, cur_arg) == 0) 115 | { 116 | parsed_arg->def = def; 117 | break; 118 | } 119 | } 120 | 121 | // Search exhausted & argument not found. RIP. 122 | if (!parsed_arg->def) 123 | { 124 | err = ZYAN_STATUS_ARG_NOT_UNDERSTOOD; 125 | ZYAN_ERR_TOK(cur_arg); 126 | goto failure; 127 | } 128 | 129 | // Does the argument expect a value? If yes, consume next token. 130 | if (!parsed_arg->def->boolean) 131 | { 132 | if (i == cfg->argc - 1) 133 | { 134 | err = ZYAN_STATUS_ARG_MISSES_VALUE; 135 | ZYAN_ERR_TOK(cur_arg); 136 | goto failure; 137 | } 138 | parsed_arg->has_value = ZYAN_TRUE; 139 | ZYAN_CHECK(ZyanStringViewInsideBuffer(&parsed_arg->value, cfg->argv[++i])); 140 | } 141 | } 142 | 143 | // Continue parsing at next token. 144 | continue; 145 | } 146 | 147 | // Single-dash argument? 148 | // TODO: How to deal with just dashes? Current code treats it as unnamed arg. 149 | if (accept_dash_args && arg_len > 1 && cur_arg[0] == '-') 150 | { 151 | // Iterate argument token chars until there are either no more chars left 152 | // or we encounter a non-boolean argument, in which case we consume the 153 | // remaining chars as its value. 154 | for (const char* read_ptr = cur_arg + 1; *read_ptr; ++read_ptr) 155 | { 156 | // Allocate parsed argument struct. 157 | ZyanArgParseArg* parsed_arg; 158 | ZYAN_CHECK(ZyanVectorEmplace(parsed, (void**)&parsed_arg, ZYAN_NULL)); 159 | ZYAN_MEMSET(parsed_arg, 0, sizeof(*parsed_arg)); 160 | 161 | // Find corresponding argument definition. 162 | for (const ZyanArgParseDefinition* def = cfg->args; def && def->name; ++def) 163 | { 164 | if (ZYAN_STRLEN(def->name) == 2 && 165 | def->name[0] == '-' && 166 | def->name[1] == *read_ptr) 167 | { 168 | parsed_arg->def = def; 169 | break; 170 | } 171 | } 172 | 173 | // Search exhausted, no match found? 174 | if (!parsed_arg->def) 175 | { 176 | err = ZYAN_STATUS_ARG_NOT_UNDERSTOOD; 177 | ZYAN_ERR_TOK(cur_arg); 178 | goto failure; 179 | } 180 | 181 | // Requires value? 182 | if (!parsed_arg->def->boolean) 183 | { 184 | // If there are chars left, consume them (e.g. `-n1000`). 185 | if (read_ptr[1]) 186 | { 187 | parsed_arg->has_value = ZYAN_TRUE; 188 | ZYAN_CHECK(ZyanStringViewInsideBuffer(&parsed_arg->value, read_ptr + 1)); 189 | } 190 | // If not, consume next token (e.g. `-n 1000`). 191 | else 192 | { 193 | if (i == cfg->argc - 1) 194 | { 195 | err = ZYAN_STATUS_ARG_MISSES_VALUE; 196 | ZYAN_ERR_TOK(cur_arg) 197 | goto failure; 198 | } 199 | 200 | parsed_arg->has_value = ZYAN_TRUE; 201 | ZYAN_CHECK(ZyanStringViewInsideBuffer(&parsed_arg->value, cfg->argv[++i])); 202 | } 203 | 204 | // Either way, continue with next argument. 205 | goto continue_main_loop; 206 | } 207 | } 208 | } 209 | 210 | // Still here? We're looking at an unnamed argument. 211 | ++num_unnamed_args; 212 | if (num_unnamed_args > cfg->max_unnamed_args) 213 | { 214 | err = ZYAN_STATUS_TOO_MANY_ARGS; 215 | ZYAN_ERR_TOK(cur_arg); 216 | goto failure; 217 | } 218 | 219 | // Allocate parsed argument struct. 220 | ZyanArgParseArg* parsed_arg; 221 | ZYAN_CHECK(ZyanVectorEmplace(parsed, (void**)&parsed_arg, ZYAN_NULL)); 222 | ZYAN_MEMSET(parsed_arg, 0, sizeof(*parsed_arg)); 223 | parsed_arg->has_value = ZYAN_TRUE; 224 | ZYAN_CHECK(ZyanStringViewInsideBuffer(&parsed_arg->value, cur_arg)); 225 | 226 | continue_main_loop:; 227 | } 228 | 229 | // All tokens processed. Do we have enough unnamed arguments? 230 | if (num_unnamed_args < cfg->min_unnamed_args) 231 | { 232 | err = ZYAN_STATUS_TOO_FEW_ARGS; 233 | // No sensible error token for this error type. 234 | goto failure; 235 | } 236 | 237 | // Check whether all required arguments are present. 238 | ZyanUSize num_parsed_args; 239 | ZYAN_CHECK(ZyanVectorGetSize(parsed, &num_parsed_args)); 240 | for (const ZyanArgParseDefinition* def = cfg->args; def && def->name; ++def) 241 | { 242 | if (!def->required) continue; 243 | 244 | ZyanBool arg_found = ZYAN_FALSE; 245 | for (ZyanUSize i = 0; i < num_parsed_args; ++i) 246 | { 247 | const ZyanArgParseArg* arg = ZYAN_NULL; 248 | ZYAN_CHECK(ZyanVectorGetPointer(parsed, i, (const void**)&arg)); 249 | 250 | // Skip unnamed args. 251 | if (!arg->def) continue; 252 | 253 | if (arg->def == def) 254 | { 255 | arg_found = ZYAN_TRUE; 256 | break; 257 | } 258 | } 259 | 260 | if (!arg_found) 261 | { 262 | err = ZYAN_STATUS_REQUIRED_ARG_MISSING; 263 | ZYAN_ERR_TOK(def->name); 264 | goto failure; 265 | } 266 | } 267 | 268 | // Yay! 269 | ZYAN_ERR_TOK(ZYAN_NULL); 270 | return ZYAN_STATUS_SUCCESS; 271 | 272 | failure: 273 | ZYAN_CHECK(ZyanVectorDestroy(parsed)); 274 | return err; 275 | 276 | # undef ZYAN_ERR_TOK 277 | } 278 | 279 | /* ============================================================================================== */ 280 | -------------------------------------------------------------------------------- /src/Zycore.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************************** 2 | 3 | Zyan Core Library (Zycore-C) 4 | 5 | Original Author : Florian Bernd 6 | 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | 25 | ***************************************************************************************************/ 26 | 27 | #include 28 | 29 | /* ============================================================================================== */ 30 | /* Exported functions */ 31 | /* ============================================================================================== */ 32 | 33 | ZyanU64 ZycoreGetVersion(void) 34 | { 35 | return ZYCORE_VERSION; 36 | } 37 | 38 | /* ============================================================================================== */ 39 | -------------------------------------------------------------------------------- /subprojects/gtest.wrap: -------------------------------------------------------------------------------- 1 | [wrap-file] 2 | directory = googletest-1.15.0 3 | source_url = https://github.com/google/googletest/archive/refs/tags/v1.15.0.tar.gz 4 | source_filename = gtest-1.15.0.tar.gz 5 | source_hash = 7315acb6bf10e99f332c8a43f00d5fbb1ee6ca48c52f6b936991b216c586aaad 6 | patch_filename = gtest_1.15.0-1_patch.zip 7 | patch_url = https://wrapdb.mesonbuild.com/v2/gtest_1.15.0-1/get_patch 8 | patch_hash = 5f8e484c48fdc1029c7fd08807bd2615f8c9d16f90df6d81984f4f292752c925 9 | source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/gtest_1.15.0-1/gtest-1.15.0.tar.gz 10 | wrapdb_version = 1.15.0-1 11 | 12 | [provide] 13 | gtest = gtest_dep 14 | gtest_main = gtest_main_dep 15 | gmock = gmock_dep 16 | gmock_main = gmock_main_dep 17 | -------------------------------------------------------------------------------- /tests/ArgParse.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************************************** 2 | 3 | Zyan Core Library (Zycore-C) 4 | 5 | Original Author : Joel Hoener 6 | 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | 25 | ***************************************************************************************************/ 26 | 27 | /** 28 | * @file 29 | * @brief Tests the the arg parse implementation. 30 | */ 31 | 32 | #include 33 | 34 | #include 35 | #include 36 | #include 37 | 38 | /* ============================================================================================== */ 39 | /* Helpers */ 40 | /* ============================================================================================== */ 41 | 42 | auto cvt_string_view(const ZyanStringView *sv) 43 | { 44 | const char* buf; 45 | if (ZYAN_FAILED(ZyanStringViewGetData(sv, &buf))) throw std::exception{}; 46 | ZyanUSize len; 47 | if (ZYAN_FAILED(ZyanStringViewGetSize(sv, &len))) throw std::exception{}; 48 | 49 | return std::string_view{buf, len}; 50 | } 51 | 52 | /* ============================================================================================== */ 53 | /* Tests */ 54 | /* ============================================================================================== */ 55 | 56 | /* ---------------------------------------------------------------------------------------------- */ 57 | /* Unnamed args */ 58 | /* ---------------------------------------------------------------------------------------------- */ 59 | 60 | static auto UnnamedArgTest(ZyanUSize min, ZyanUSize max) 61 | { 62 | const char* argv[] 63 | { 64 | "./test", "a", "xxx" 65 | }; 66 | 67 | ZyanArgParseConfig cfg 68 | { 69 | argv, // argv 70 | 3, // argc 71 | min, // min_unnamed_args 72 | max, // max_unnamed_args 73 | nullptr // args 74 | }; 75 | 76 | ZyanVector parsed; 77 | const char* err_tok = nullptr; 78 | ZYAN_MEMSET(&parsed, 0, sizeof(parsed)); 79 | auto status = ZyanArgParse(&cfg, &parsed, &err_tok); 80 | return std::make_tuple(status, parsed, err_tok); 81 | } 82 | 83 | TEST(UnnamedArgs, TooFew) 84 | { 85 | auto [status, parsed, err_tok] = UnnamedArgTest(5, 5); 86 | ASSERT_EQ(status, ZYAN_STATUS_TOO_FEW_ARGS); 87 | ASSERT_STREQ(err_tok, nullptr); 88 | } 89 | 90 | TEST(UnnamedArgs, TooMany) 91 | { 92 | auto [status, parsed, err_tok] = UnnamedArgTest(1, 1); 93 | ASSERT_EQ(status, ZYAN_STATUS_TOO_MANY_ARGS); 94 | ASSERT_STREQ(err_tok, "xxx"); 95 | } 96 | 97 | TEST(UnnamedArgs, PerfectFit) 98 | { 99 | auto [status, parsed, err_tok] = UnnamedArgTest(2, 2); 100 | ASSERT_TRUE(ZYAN_SUCCESS(status)); 101 | 102 | ZyanUSize size; 103 | ASSERT_TRUE(ZYAN_SUCCESS(ZyanVectorGetSize(&parsed, &size))); 104 | ASSERT_EQ(size, 2); 105 | 106 | auto arg = (const ZyanArgParseArg*)ZyanVectorGet(&parsed, 0); 107 | ASSERT_NE(arg, nullptr); 108 | ASSERT_TRUE(arg->has_value); 109 | ASSERT_EQ(cvt_string_view(&arg->value), "a"); 110 | 111 | arg = (const ZyanArgParseArg*)ZyanVectorGet(&parsed, 1); 112 | ASSERT_NE(arg, nullptr); 113 | ASSERT_TRUE(arg->has_value); 114 | ASSERT_EQ(cvt_string_view(&arg->value), "xxx"); 115 | } 116 | 117 | /* ---------------------------------------------------------------------------------------------- */ 118 | /* Dash args */ 119 | /* ---------------------------------------------------------------------------------------------- */ 120 | 121 | TEST(DashArg, MixedBoolAndValueArgs) 122 | { 123 | const char* argv[] 124 | { 125 | "./test", "-aio42", "-n", "xxx" 126 | }; 127 | 128 | ZyanArgParseDefinition args[] 129 | { 130 | {"-o", ZYAN_FALSE, ZYAN_FALSE}, 131 | {"-a", ZYAN_TRUE, ZYAN_FALSE}, 132 | {"-n", ZYAN_FALSE, ZYAN_FALSE}, 133 | {"-i", ZYAN_TRUE, ZYAN_FALSE}, 134 | {nullptr, ZYAN_FALSE, ZYAN_FALSE} 135 | }; 136 | 137 | ZyanArgParseConfig cfg 138 | { 139 | argv, // argv 140 | 4, // argc 141 | 0, // min_unnamed_args 142 | 0, // max_unnamed_args 143 | args // args 144 | }; 145 | 146 | ZyanVector parsed; 147 | ZYAN_MEMSET(&parsed, 0, sizeof(parsed)); 148 | auto status = ZyanArgParse(&cfg, &parsed, nullptr); 149 | ASSERT_TRUE(ZYAN_SUCCESS(status)); 150 | 151 | ZyanUSize size; 152 | ASSERT_TRUE(ZYAN_SUCCESS(ZyanVectorGetSize(&parsed, &size))); 153 | ASSERT_EQ(size, 4); 154 | 155 | const ZyanArgParseArg* arg; 156 | ASSERT_TRUE(ZYAN_SUCCESS(ZyanVectorGetPointer(&parsed, 0, (const void**)&arg))); 157 | ASSERT_STREQ(arg->def->name, "-a"); 158 | ASSERT_FALSE(arg->has_value); 159 | 160 | ASSERT_TRUE(ZYAN_SUCCESS(ZyanVectorGetPointer(&parsed, 1, (const void**)&arg))); 161 | ASSERT_STREQ(arg->def->name, "-i"); 162 | ASSERT_FALSE(arg->has_value); 163 | 164 | ASSERT_TRUE(ZYAN_SUCCESS(ZyanVectorGetPointer(&parsed, 2, (const void**)&arg))); 165 | ASSERT_STREQ(arg->def->name, "-o"); 166 | ASSERT_TRUE(arg->has_value); 167 | ASSERT_EQ(cvt_string_view(&arg->value), "42"); 168 | 169 | ASSERT_TRUE(ZYAN_SUCCESS(ZyanVectorGetPointer(&parsed, 3, (const void**)&arg))); 170 | ASSERT_STREQ(arg->def->name, "-n"); 171 | ASSERT_TRUE(arg->has_value); 172 | ASSERT_EQ(cvt_string_view(&arg->value), "xxx"); 173 | } 174 | 175 | /* ---------------------------------------------------------------------------------------------- */ 176 | /* Double dash args */ 177 | /* ---------------------------------------------------------------------------------------------- */ 178 | 179 | TEST(DoubleDashArg, PerfectFit) 180 | { 181 | const char* argv[] 182 | { 183 | "./test", "--help", "--stuff", "1337" 184 | }; 185 | 186 | ZyanArgParseDefinition args[] 187 | { 188 | {"--help", ZYAN_TRUE, ZYAN_FALSE}, 189 | {"--stuff", ZYAN_FALSE, ZYAN_FALSE}, 190 | {nullptr, ZYAN_FALSE, ZYAN_FALSE} 191 | }; 192 | 193 | ZyanArgParseConfig cfg 194 | { 195 | argv, // argv 196 | 4, // argc 197 | 0, // min_unnamed_args 198 | 0, // max_unnamed_args 199 | args // args 200 | }; 201 | 202 | ZyanVector parsed; 203 | ZYAN_MEMSET(&parsed, 0, sizeof(parsed)); 204 | auto status = ZyanArgParse(&cfg, &parsed, nullptr); 205 | ASSERT_TRUE(ZYAN_SUCCESS(status)); 206 | 207 | ZyanUSize size; 208 | ASSERT_TRUE(ZYAN_SUCCESS(ZyanVectorGetSize(&parsed, &size))); 209 | ASSERT_EQ(size, 2); 210 | 211 | const ZyanArgParseArg* arg; 212 | ASSERT_TRUE(ZYAN_SUCCESS(ZyanVectorGetPointer(&parsed, 0, (const void**)&arg))); 213 | ASSERT_STREQ(arg->def->name, "--help"); 214 | ASSERT_FALSE(arg->has_value); 215 | 216 | ASSERT_TRUE(ZYAN_SUCCESS(ZyanVectorGetPointer(&parsed, 1, (const void**)&arg))); 217 | ASSERT_STREQ(arg->def->name, "--stuff"); 218 | ASSERT_TRUE(arg->has_value); 219 | ASSERT_EQ(cvt_string_view(&arg->value), "1337"); 220 | } 221 | 222 | /* ---------------------------------------------------------------------------------------------- */ 223 | /* Mixed */ 224 | /* ---------------------------------------------------------------------------------------------- */ 225 | 226 | TEST(MixedArgs, MissingRequiredArg) 227 | { 228 | const char* argv[] 229 | { 230 | "./test", "blah.c", "woof.moo" 231 | }; 232 | 233 | ZyanArgParseDefinition args[] 234 | { 235 | {"--feature-xyz", ZYAN_TRUE, ZYAN_FALSE}, 236 | {"-n", ZYAN_FALSE, ZYAN_TRUE}, 237 | {nullptr, ZYAN_FALSE, ZYAN_FALSE} 238 | }; 239 | 240 | ZyanArgParseConfig cfg 241 | { 242 | argv, // argv 243 | 3, // argc 244 | 0, // min_unnamed_args 245 | 100, // max_unnamed_args 246 | args // args 247 | }; 248 | 249 | ZyanVector parsed; 250 | ZYAN_MEMSET(&parsed, 0, sizeof(parsed)); 251 | const char* err_tok = nullptr; 252 | auto status = ZyanArgParse(&cfg, &parsed, &err_tok); 253 | ASSERT_EQ(status, ZYAN_STATUS_REQUIRED_ARG_MISSING); 254 | ASSERT_STREQ(err_tok, "-n"); 255 | } 256 | 257 | TEST(MixedArgs, Stuff) 258 | { 259 | const char* argv[] 260 | { 261 | "./test", "--feature-xyz", "-n5", "blah.c", "woof.moo" 262 | }; 263 | 264 | ZyanArgParseDefinition args[] 265 | { 266 | {"--feature-xyz", ZYAN_TRUE, ZYAN_FALSE}, 267 | {"-n", ZYAN_FALSE, ZYAN_FALSE}, 268 | {nullptr, ZYAN_FALSE, ZYAN_FALSE} 269 | }; 270 | 271 | ZyanArgParseConfig cfg 272 | { 273 | argv, // argv 274 | 5, // argc 275 | 0, // min_unnamed_args 276 | 100, // max_unnamed_args 277 | args // args 278 | }; 279 | 280 | ZyanVector parsed; 281 | ZYAN_MEMSET(&parsed, 0, sizeof(parsed)); 282 | auto status = ZyanArgParse(&cfg, &parsed, nullptr); 283 | ASSERT_TRUE(ZYAN_SUCCESS(status)); 284 | 285 | ZyanUSize size; 286 | ASSERT_TRUE(ZYAN_SUCCESS(ZyanVectorGetSize(&parsed, &size))); 287 | ASSERT_EQ(size, 4); 288 | 289 | const ZyanArgParseArg* arg; 290 | ASSERT_TRUE(ZYAN_SUCCESS(ZyanVectorGetPointer(&parsed, 0, (const void**)&arg))); 291 | ASSERT_STREQ(arg->def->name, "--feature-xyz"); 292 | ASSERT_FALSE(arg->has_value); 293 | 294 | ASSERT_TRUE(ZYAN_SUCCESS(ZyanVectorGetPointer(&parsed, 1, (const void**)&arg))); 295 | ASSERT_STREQ(arg->def->name, "-n"); 296 | ASSERT_TRUE(arg->has_value); 297 | ASSERT_EQ(cvt_string_view(&arg->value), "5"); 298 | 299 | ASSERT_TRUE(ZYAN_SUCCESS(ZyanVectorGetPointer(&parsed, 2, (const void**)&arg))); 300 | ASSERT_EQ(arg->def, nullptr); 301 | ASSERT_TRUE(arg->has_value); 302 | ASSERT_EQ(cvt_string_view(&arg->value), "blah.c"); 303 | 304 | ASSERT_TRUE(ZYAN_SUCCESS(ZyanVectorGetPointer(&parsed, 3, (const void**)&arg))); 305 | ASSERT_EQ(arg->def, nullptr); 306 | ASSERT_TRUE(arg->has_value); 307 | ASSERT_EQ(cvt_string_view(&arg->value), "woof.moo"); 308 | } 309 | 310 | /* ============================================================================================== */ 311 | /* Entry point */ 312 | /* ============================================================================================== */ 313 | 314 | int main(int argc, char **argv) 315 | { 316 | ::testing::InitGoogleTest(&argc, argv); 317 | return RUN_ALL_TESTS(); 318 | } 319 | 320 | /* ============================================================================================== */ 321 | -------------------------------------------------------------------------------- /tests/String.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************************************** 2 | 3 | Zyan Core Library (Zycore-C) 4 | 5 | Original Author : Florian Bernd 6 | 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | 25 | ***************************************************************************************************/ 26 | 27 | /** 28 | * @file 29 | * @brief Tests the `ZyanString` implementation. 30 | */ 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | /* ============================================================================================== */ 40 | /* Enums and types */ 41 | /* ============================================================================================== */ 42 | 43 | 44 | 45 | /* ============================================================================================== */ 46 | /* Helper functions */ 47 | /* ============================================================================================== */ 48 | 49 | /* ---------------------------------------------------------------------------------------------- */ 50 | /* Custom allocator */ 51 | /* ---------------------------------------------------------------------------------------------- */ 52 | 53 | static ZyanStatus AllocatorAllocate( 54 | ZyanAllocator* allocator, void** p, ZyanUSize element_size, ZyanUSize n) { 55 | ZYAN_ASSERT(allocator); 56 | ZYAN_ASSERT(p); 57 | ZYAN_ASSERT(element_size); 58 | ZYAN_ASSERT(n); 59 | 60 | ZYAN_UNUSED(allocator); 61 | 62 | *p = ZYAN_MALLOC(element_size * n); 63 | if (!*p) { 64 | return ZYAN_STATUS_NOT_ENOUGH_MEMORY; 65 | } 66 | 67 | return ZYAN_STATUS_SUCCESS; 68 | } 69 | 70 | static ZyanStatus AllocatorReallocate( 71 | ZyanAllocator* allocator, void** p, ZyanUSize element_size, ZyanUSize n) { 72 | ZYAN_ASSERT(allocator); 73 | ZYAN_ASSERT(p); 74 | ZYAN_ASSERT(element_size); 75 | ZYAN_ASSERT(n); 76 | 77 | ZYAN_UNUSED(allocator); 78 | 79 | void* const x = ZYAN_REALLOC(*p, element_size * n); 80 | if (!x) { 81 | return ZYAN_STATUS_NOT_ENOUGH_MEMORY; 82 | } 83 | *p = x; 84 | 85 | return ZYAN_STATUS_SUCCESS; 86 | } 87 | 88 | static ZyanStatus AllocatorDeallocate( 89 | ZyanAllocator* allocator, void* p, ZyanUSize element_size, ZyanUSize n) { 90 | ZYAN_ASSERT(allocator); 91 | ZYAN_ASSERT(p); 92 | ZYAN_ASSERT(element_size); 93 | ZYAN_ASSERT(n); 94 | 95 | ZYAN_UNUSED(allocator); 96 | ZYAN_UNUSED(element_size); 97 | ZYAN_UNUSED(n); 98 | 99 | ZYAN_FREE(p); 100 | 101 | return ZYAN_STATUS_SUCCESS; 102 | } 103 | 104 | /* ============================================================================================== */ 105 | /* Tests */ 106 | /* ============================================================================================== */ 107 | 108 | TEST(StringTest, InitDynamic) 109 | { 110 | ZyanString string; 111 | 112 | ASSERT_EQ(ZyanStringInit(&string, 0), ZYAN_STATUS_SUCCESS); 113 | EXPECT_EQ(string.vector.allocator, ZyanAllocatorDefault()); 114 | EXPECT_EQ(string.vector.growth_factor, ZYAN_STRING_DEFAULT_GROWTH_FACTOR); 115 | EXPECT_EQ(string.vector.shrink_threshold, ZYAN_STRING_DEFAULT_SHRINK_THRESHOLD); 116 | EXPECT_EQ(string.vector.size, static_cast(1)); 117 | EXPECT_EQ(string.vector.capacity, static_cast(ZYAN_STRING_MIN_CAPACITY + 1)); 118 | EXPECT_EQ(string.vector.element_size, sizeof(char)); 119 | EXPECT_NE(string.vector.data, ZYAN_NULL); 120 | EXPECT_EQ(ZyanStringDestroy(&string), ZYAN_STATUS_SUCCESS); 121 | } 122 | 123 | TEST(StringTest, InitStatic) 124 | { 125 | ZyanString string; 126 | 127 | static char buffer[32]; 128 | EXPECT_EQ(ZyanStringInitCustomBuffer(&string, buffer, 0), ZYAN_STATUS_INVALID_ARGUMENT); 129 | ASSERT_EQ(ZyanStringInitCustomBuffer(&string, buffer, ZYAN_ARRAY_LENGTH(buffer)), 130 | ZYAN_STATUS_SUCCESS); 131 | EXPECT_EQ(string.vector.allocator, ZYAN_NULL); 132 | EXPECT_EQ(string.vector.growth_factor, 1); 133 | EXPECT_EQ(string.vector.shrink_threshold, 0); 134 | EXPECT_EQ(string.vector.size, static_cast(1)); 135 | EXPECT_EQ(string.vector.capacity, ZYAN_ARRAY_LENGTH(buffer)); 136 | EXPECT_EQ(string.vector.element_size, sizeof(char)); 137 | EXPECT_EQ(string.vector.data, &buffer); 138 | EXPECT_EQ(ZyanStringDestroy(&string), ZYAN_STATUS_SUCCESS); 139 | } 140 | 141 | TEST(StringTest, InitAdvanced) 142 | { 143 | ZyanString string; 144 | ZyanAllocator allocator; 145 | 146 | ASSERT_EQ( 147 | ZyanAllocatorInit(&allocator, AllocatorAllocate, AllocatorReallocate, AllocatorDeallocate), 148 | ZYAN_STATUS_SUCCESS); 149 | ASSERT_EQ(ZyanStringInitEx(&string, 0, &allocator, 1, 0), ZYAN_STATUS_SUCCESS); 150 | EXPECT_EQ(string.vector.allocator, &allocator); 151 | EXPECT_EQ(string.vector.growth_factor, 1); 152 | EXPECT_EQ(string.vector.shrink_threshold, 0); 153 | EXPECT_EQ(string.vector.size, static_cast(1)); 154 | EXPECT_EQ(string.vector.capacity, static_cast(ZYAN_STRING_MIN_CAPACITY + 1)); 155 | EXPECT_EQ(string.vector.element_size, sizeof(char)); 156 | EXPECT_NE(string.vector.data, ZYAN_NULL); 157 | EXPECT_EQ(ZyanStringDestroy(&string), ZYAN_STATUS_SUCCESS); 158 | } 159 | 160 | /* ---------------------------------------------------------------------------------------------- */ 161 | 162 | /* ============================================================================================== */ 163 | /* Entry point */ 164 | /* ============================================================================================== */ 165 | 166 | int main(int argc, char **argv) 167 | { 168 | ::testing::InitGoogleTest(&argc, argv); 169 | return RUN_ALL_TESTS(); 170 | } 171 | 172 | /* ============================================================================================== */ 173 | -------------------------------------------------------------------------------- /tests/meson.build: -------------------------------------------------------------------------------- 1 | gtest_dep = dependency('gtest', required: tests) 2 | 3 | tests_req = gtest_dep.found() and add_languages('cpp', native: false, required: tests) 4 | 5 | if tests_req 6 | test( 7 | 'string', 8 | executable( 9 | 'test_string', 10 | 'String.cpp', 11 | dependencies: [gtest_dep, zycore_dep], 12 | ), 13 | protocol: 'gtest', 14 | ) 15 | test( 16 | 'vector', 17 | executable( 18 | 'test_vector', 19 | 'Vector.cpp', 20 | dependencies: [gtest_dep, zycore_dep], 21 | ), 22 | protocol: 'gtest', 23 | ) 24 | test( 25 | 'argparse', 26 | executable( 27 | 'test_argparse', 28 | 'ArgParse.cpp', 29 | dependencies: [gtest_dep, zycore_dep], 30 | ), 31 | protocol: 'gtest', 32 | ) 33 | endif 34 | 35 | summary( 36 | {'tests': tests_req}, 37 | section: 'Features', 38 | ) 39 | --------------------------------------------------------------------------------