From 83eb39e3e87ffd63fdd8d76b64b7a5f5316e6248 Mon Sep 17 00:00:00 2001 From: Aleksei Sidorov <> Date: Thu, 2 Jun 2022 20:19:47 +0300 Subject: [PATCH] Simplify Zydis build --- .gitmodules | 3 - BUILD.gn | 52 + CMakeLists.txt | 292 +---- dependencies/zycore | 1 - include/Zydis/Decoder.h | 6 +- include/Zydis/Formatter.h | 22 +- include/Zydis/FormatterBuffer.h | 15 +- include/Zydis/Internal/DecoderData.h | 4 +- include/Zydis/Internal/SharedData.h | 8 +- include/Zydis/MetaInfo.h | 7 +- include/Zydis/Mnemonic.h | 4 +- include/Zydis/Register.h | 16 +- include/Zydis/ShortString.h | 1 - include/Zydis/Utils.h | 12 +- include/Zydis/Zydis.h | 4 +- zycore/CMakeLists.txt | 90 ++ zycore/LICENSE | 22 + zycore/README.md | 29 + zycore/include/Zycore/API/Memory.h | 137 +++ zycore/include/Zycore/API/Process.h | 70 ++ zycore/include/Zycore/API/Synchronization.h | 132 +++ zycore/include/Zycore/API/Terminal.h | 162 +++ zycore/include/Zycore/API/Thread.h | 243 ++++ zycore/include/Zycore/Allocator.h | 142 +++ zycore/include/Zycore/ArgParse.h | 173 +++ zycore/include/Zycore/Atomic.h | 236 ++++ zycore/include/Zycore/Bitset.h | 483 ++++++++ zycore/include/Zycore/Comparison.h | 316 ++++++ zycore/include/Zycore/Defines.h | 521 +++++++++ zycore/include/Zycore/Format.h | 285 +++++ zycore/include/Zycore/Internal/AtomicGNU.h | 117 ++ zycore/include/Zycore/Internal/AtomicMSVC.h | 141 +++ zycore/include/Zycore/LibC.h | 511 +++++++++ zycore/include/Zycore/List.h | 573 ++++++++++ zycore/include/Zycore/Object.h | 84 ++ zycore/include/Zycore/Status.h | 287 +++++ zycore/include/Zycore/String.h | 1011 +++++++++++++++++ zycore/include/Zycore/Types.h | 236 ++++ zycore/include/Zycore/Vector.h | 722 ++++++++++++ zycore/include/Zycore/Zycore.h | 110 ++ zycore/src/API/Memory.c | 132 +++ zycore/src/API/Process.c | 76 ++ zycore/src/API/Synchronization.c | 204 ++++ zycore/src/API/Terminal.c | 160 +++ zycore/src/API/Thread.c | 244 +++++ zycore/src/Allocator.c | 134 +++ zycore/src/ArgParse.c | 279 +++++ zycore/src/Bitset.c | 670 +++++++++++ zycore/src/Format.c | 507 +++++++++ zycore/src/List.c | 673 ++++++++++++ zycore/src/String.c | 1098 +++++++++++++++++++ zycore/src/Vector.c | 846 ++++++++++++++ zycore/src/Zycore.c | 38 + 53 files changed, 12045 insertions(+), 296 deletions(-) delete mode 100644 .gitmodules create mode 100644 BUILD.gn delete mode 160000 dependencies/zycore create mode 100644 zycore/CMakeLists.txt create mode 100644 zycore/LICENSE create mode 100644 zycore/README.md create mode 100644 zycore/include/Zycore/API/Memory.h create mode 100644 zycore/include/Zycore/API/Process.h create mode 100644 zycore/include/Zycore/API/Synchronization.h create mode 100644 zycore/include/Zycore/API/Terminal.h create mode 100644 zycore/include/Zycore/API/Thread.h create mode 100644 zycore/include/Zycore/Allocator.h create mode 100644 zycore/include/Zycore/ArgParse.h create mode 100644 zycore/include/Zycore/Atomic.h create mode 100644 zycore/include/Zycore/Bitset.h create mode 100644 zycore/include/Zycore/Comparison.h create mode 100644 zycore/include/Zycore/Defines.h create mode 100644 zycore/include/Zycore/Format.h create mode 100644 zycore/include/Zycore/Internal/AtomicGNU.h create mode 100644 zycore/include/Zycore/Internal/AtomicMSVC.h create mode 100644 zycore/include/Zycore/LibC.h create mode 100644 zycore/include/Zycore/List.h create mode 100644 zycore/include/Zycore/Object.h create mode 100644 zycore/include/Zycore/Status.h create mode 100644 zycore/include/Zycore/String.h create mode 100644 zycore/include/Zycore/Types.h create mode 100644 zycore/include/Zycore/Vector.h create mode 100644 zycore/include/Zycore/Zycore.h create mode 100644 zycore/src/API/Memory.c create mode 100644 zycore/src/API/Process.c create mode 100644 zycore/src/API/Synchronization.c create mode 100644 zycore/src/API/Terminal.c create mode 100644 zycore/src/API/Thread.c create mode 100644 zycore/src/Allocator.c create mode 100644 zycore/src/ArgParse.c create mode 100644 zycore/src/Bitset.c create mode 100644 zycore/src/Format.c create mode 100644 zycore/src/List.c create mode 100644 zycore/src/String.c create mode 100644 zycore/src/Vector.c create mode 100644 zycore/src/Zycore.c diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index e0a443d..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "dependencies/zycore"] - path = dependencies/zycore - url = https://github.com/zyantific/zycore-c diff --git a/BUILD.gn b/BUILD.gn new file mode 100644 index 0000000..bc0c3e4 --- /dev/null +++ b/BUILD.gn @@ -0,0 +1,52 @@ +# Copyright (c) Huawei Technologies Co., Ltd. 2021-2021. All rights reserved. + +import("//arkcompiler/runtime_core/static_core/ark_config.gni") +import("//build/config/ohos/rules.gni") +import("//build/ohos.gni") + +config("zydis_public_config") { + include_dirs = [ + "$ark_third_party_root/zydis/include", + "$ark_third_party_root/zydis/zycore/include", + "$ark_third_party_root/zydis/src", + ] +} + +ohos_static_library("libZydis") { + sources = [ + "include/Zydis/Decoder.h", + "include/Zydis/DecoderTypes.h", + "include/Zydis/Formatter.h", + "include/Zydis/FormatterBuffer.h", + "include/Zydis/Internal/DecoderData.h", + "include/Zydis/Internal/FormatterATT.h", + "include/Zydis/Internal/FormatterBase.h", + "include/Zydis/Internal/FormatterIntel.h", + "include/Zydis/Internal/SharedData.h", + "include/Zydis/Internal/String.h", + "include/Zydis/MetaInfo.h", + "include/Zydis/Mnemonic.h", + "include/Zydis/Register.h", + "include/Zydis/SharedTypes.h", + "include/Zydis/ShortString.h", + "include/Zydis/Status.h", + "include/Zydis/Utils.h", + "include/Zydis/Zydis.h", + "src/Decoder.c", + "src/DecoderData.c", + "src/Formatter.c", + "src/FormatterATT.c", + "src/FormatterBase.c", + "src/FormatterBuffer.c", + "src/FormatterIntel.c", + "src/MetaInfo.c", + "src/Mnemonic.c", + "src/Register.c", + "src/SharedData.c", + "src/String.c", + "src/Utils.c", + "src/Zydis.c", + ] + + configs = [ ":zydis_public_config" ] +} diff --git a/CMakeLists.txt b/CMakeLists.txt index 9898f42..a7b6d6c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,6 @@ cmake_minimum_required(VERSION 3.1 FATAL_ERROR) project(Zydis VERSION 3.2.1.0 LANGUAGES C CXX) -include(GenerateExportHeader) include(GNUInstallDirs) include(CMakePackageConfigHelpers) @@ -22,87 +21,80 @@ option(ZYDIS_FEATURE_FORMATTER ON) option(ZYDIS_FEATURE_AVX512 "Enable support for AVX-512 instructions" - ON) + OFF) option(ZYDIS_FEATURE_KNC "Enable support for KNC instructions" - ON) + OFF) # Build configuration -option(ZYDIS_BUILD_SHARED_LIB - "Build shared library" - OFF) -option(ZYDIS_BUILD_EXAMPLES - "Build examples" - ON) -option(ZYDIS_BUILD_TOOLS - "Build tools" - ON) -option(ZYDIS_FUZZ_AFL_FAST - "Enables AFL persistent mode and reduces prints in ZydisFuzzIn" - OFF) -option(ZYDIS_LIBFUZZER - "Enables LLVM libfuzzer mode and reduces prints in ZydisFuzzIn" - OFF) set(ZYDIS_ZYCORE_PATH - "${CMAKE_CURRENT_LIST_DIR}/dependencies/zycore" + "${CMAKE_CURRENT_LIST_DIR}/zycore" CACHE PATH "The path to look for Zycore") -# =============================================================================================== # -# Dependencies # -# =============================================================================================== # - -# Try to initialize the Zycore submodule using Git -if (NOT EXISTS "${ZYDIS_ZYCORE_PATH}/CMakeLists.txt" AND - "${ZYDIS_ZYCORE_PATH}" STREQUAL "${CMAKE_CURRENT_LIST_DIR}/dependencies/zycore") - find_package(Git QUIET) - if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git") - execute_process( - COMMAND ${GIT_EXECUTABLE} submodule update --init --recursive - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - ) - endif() -endif () - -if (NOT EXISTS "${ZYDIS_ZYCORE_PATH}/CMakeLists.txt") - message( - FATAL_ERROR - "Can't find zycore submodule. Please make sure to clone the repo recursively.\n" - "You can fix this by running\n" - " git submodule update --init\n" - "or by cloning using\n" - " git clone --recursive \n" - "Alternatively, you can manually clone zycore to some path and set ZYDIS_ZYCORE_PATH." - ) -endif () - add_subdirectory(${ZYDIS_ZYCORE_PATH} "zycore" EXCLUDE_FROM_ALL) # =============================================================================================== # # Library configuration # # =============================================================================================== # -if (ZYDIS_BUILD_SHARED_LIB) - add_library("Zydis" SHARED) -else () - add_library("Zydis" STATIC) +set(ZYDIS_SOURCES + "${CMAKE_CURRENT_LIST_DIR}/include/Zydis/MetaInfo.h" + "${CMAKE_CURRENT_LIST_DIR}/include/Zydis/Mnemonic.h" + "${CMAKE_CURRENT_LIST_DIR}/include/Zydis/Register.h" + "${CMAKE_CURRENT_LIST_DIR}/include/Zydis/SharedTypes.h" + "${CMAKE_CURRENT_LIST_DIR}/include/Zydis/ShortString.h" + "${CMAKE_CURRENT_LIST_DIR}/include/Zydis/Status.h" + "${CMAKE_CURRENT_LIST_DIR}/include/Zydis/Utils.h" + "${CMAKE_CURRENT_LIST_DIR}/include/Zydis/Zydis.h" + "${CMAKE_CURRENT_LIST_DIR}/include/Zydis/Internal/SharedData.h" + "${CMAKE_CURRENT_LIST_DIR}/include/Zydis/Internal/String.h" + "src/MetaInfo.c" + "src/Mnemonic.c" + "src/Register.c" + "src/SharedData.c" + "src/String.c" + "src/Utils.c" + "src/Zydis.c" +) + +if (ZYDIS_FEATURE_DECODER) + list(APPEND ZYDIS_SOURCES + "${CMAKE_CURRENT_LIST_DIR}/include/Zydis/Decoder.h" + "${CMAKE_CURRENT_LIST_DIR}/include/Zydis/DecoderTypes.h" + "${CMAKE_CURRENT_LIST_DIR}/include/Zydis/Internal/DecoderData.h" + "src/Decoder.c" + "src/DecoderData.c" + ) + + if (ZYDIS_FEATURE_FORMATTER AND (NOT ZYDIS_MINIMAL_MODE)) + list(APPEND ZYDIS_SOURCES + "${CMAKE_CURRENT_LIST_DIR}/include/Zydis/Formatter.h" + "${CMAKE_CURRENT_LIST_DIR}/include/Zydis/FormatterBuffer.h" + "${CMAKE_CURRENT_LIST_DIR}/include/Zydis/Internal/FormatterATT.h" + "${CMAKE_CURRENT_LIST_DIR}/include/Zydis/Internal/FormatterBase.h" + "${CMAKE_CURRENT_LIST_DIR}/include/Zydis/Internal/FormatterIntel.h" + "src/Formatter.c" + "src/FormatterBuffer.c" + "src/FormatterATT.c" + "src/FormatterBase.c" + "src/FormatterIntel.c" + ) + endif () endif () +add_library("Zydis" STATIC "${ZYDIS_SOURCES}") +set_property(TARGET Zydis PROPERTY POSITION_INDEPENDENT_CODE ON) + target_link_libraries("Zydis" PUBLIC "Zycore") target_include_directories("Zydis" PUBLIC $ $ - $ PRIVATE "src") -target_compile_definitions("Zydis" PRIVATE "_CRT_SECURE_NO_WARNINGS" "ZYDIS_EXPORTS") -set_target_properties("Zydis" PROPERTIES - VERSION ${Zydis_VERSION} - SOVERSION ${Zydis_VERSION_MAJOR}.${Zydis_VERSION_MINOR}) -zyan_set_common_flags("Zydis") -zyan_maybe_enable_wpo_for_lib("Zydis") -generate_export_header("Zydis" BASE_NAME "ZYDIS" EXPORT_FILE_NAME "ZydisExportConfig.h") +target_compile_definitions("Zydis" PRIVATE "_CRT_SECURE_NO_WARNINGS") +target_compile_options("Zydis" PRIVATE "-std=c99") if (ZYDIS_FEATURE_FORMATTER AND NOT ZYDIS_FEATURE_DECODER) message( @@ -127,185 +119,3 @@ if (NOT ZYDIS_FEATURE_KNC) target_compile_definitions("Zydis" PUBLIC "ZYDIS_DISABLE_KNC") endif () -target_sources("Zydis" - PRIVATE - "${CMAKE_CURRENT_LIST_DIR}/include/Zydis/MetaInfo.h" - "${CMAKE_CURRENT_LIST_DIR}/include/Zydis/Mnemonic.h" - "${CMAKE_CURRENT_LIST_DIR}/include/Zydis/Register.h" - "${CMAKE_CURRENT_LIST_DIR}/include/Zydis/SharedTypes.h" - "${CMAKE_CURRENT_LIST_DIR}/include/Zydis/ShortString.h" - "${CMAKE_CURRENT_LIST_DIR}/include/Zydis/Status.h" - "${CMAKE_CURRENT_LIST_DIR}/include/Zydis/Utils.h" - "${CMAKE_CURRENT_LIST_DIR}/include/Zydis/Zydis.h" - "${CMAKE_CURRENT_LIST_DIR}/include/Zydis/Internal/SharedData.h" - "${CMAKE_CURRENT_LIST_DIR}/include/Zydis/Internal/String.h" - "src/MetaInfo.c" - "src/Mnemonic.c" - "src/Register.c" - "src/SharedData.c" - "src/String.c" - "src/Utils.c" - "src/Zydis.c") - -if (ZYDIS_FEATURE_DECODER) - target_sources("Zydis" - PRIVATE - "${CMAKE_CURRENT_LIST_DIR}/include/Zydis/Decoder.h" - "${CMAKE_CURRENT_LIST_DIR}/include/Zydis/DecoderTypes.h" - "${CMAKE_CURRENT_LIST_DIR}/include/Zydis/Internal/DecoderData.h" - "src/Decoder.c" - "src/DecoderData.c") - if (ZYDIS_FEATURE_FORMATTER AND (NOT ZYDIS_MINIMAL_MODE)) - target_sources("Zydis" - PRIVATE - "${CMAKE_CURRENT_LIST_DIR}/include/Zydis/Formatter.h" - "${CMAKE_CURRENT_LIST_DIR}/include/Zydis/FormatterBuffer.h" - "${CMAKE_CURRENT_LIST_DIR}/include/Zydis/Internal/FormatterATT.h" - "${CMAKE_CURRENT_LIST_DIR}/include/Zydis/Internal/FormatterBase.h" - "${CMAKE_CURRENT_LIST_DIR}/include/Zydis/Internal/FormatterIntel.h" - "src/Formatter.c" - "src/FormatterBuffer.c" - "src/FormatterATT.c" - "src/FormatterBase.c" - "src/FormatterIntel.c") - endif () -endif () - -if (ZYDIS_BUILD_SHARED_LIB AND WIN32) - target_sources("Zydis" PRIVATE "resources/VersionInfo.rc") -endif () - -zyan_set_source_group("Zydis") - -configure_package_config_file(cmake/zydis-config.cmake.in - "${CMAKE_CURRENT_BINARY_DIR}/zydis-config.cmake" - INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/zydis" -) -write_basic_package_version_file( - "${CMAKE_CURRENT_BINARY_DIR}/zydis-config-version.cmake" - COMPATIBILITY SameMajorVersion -) -install(FILES - "${CMAKE_CURRENT_BINARY_DIR}/zydis-config.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/zydis-config-version.cmake" - DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/zydis" -) - -install(TARGETS "Zydis" - EXPORT "zydis-targets" - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) -install(EXPORT "zydis-targets" - NAMESPACE "Zydis::" - DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/zydis") -install(FILES - "${PROJECT_BINARY_DIR}/ZydisExportConfig.h" - DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}") -install(DIRECTORY "include/" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) - -function (_maybe_set_emscripten_cfg target) - if (EMSCRIPTEN) - # Yep, that madness below is how Emscripten likes its quotes. - set_target_properties("${target}" - PROPERTIES COMPILE_FLAGS - "-s \"EXPORT_NAME='${target}'\" -s MODULARIZE=1") - set_target_properties("${target}" - PROPERTIES LINK_FLAGS_RELEASE - "-s \"EXPORT_NAME='${target}'\" -s MODULARIZE=1") - endif () -endfunction () - -# =============================================================================================== # -# Examples # -# =============================================================================================== # - -if (ZYDIS_BUILD_EXAMPLES AND NOT ZYAN_NO_LIBC) - if (ZYDIS_FEATURE_DECODER AND ZYDIS_FEATURE_FORMATTER AND (NOT ZYDIS_MINIMAL_MODE)) - add_executable("Formatter01" "examples/Formatter01.c") - target_link_libraries("Formatter01" "Zydis") - set_target_properties("Formatter01" PROPERTIES FOLDER "Examples/Formatter") - target_compile_definitions("Formatter01" PRIVATE "_CRT_SECURE_NO_WARNINGS") - zyan_set_common_flags("Formatter01") - zyan_maybe_enable_wpo("Formatter01") - _maybe_set_emscripten_cfg("Formatter01") - - add_executable("Formatter02" "examples/Formatter02.c") - target_link_libraries("Formatter02" "Zydis") - set_target_properties("Formatter02" PROPERTIES FOLDER "Examples/Formatter") - target_compile_definitions("Formatter02" PRIVATE "_CRT_SECURE_NO_WARNINGS") - zyan_set_common_flags("Formatter02") - zyan_maybe_enable_wpo("Formatter02") - _maybe_set_emscripten_cfg("Formatter02") - - add_executable("Formatter03" "examples/Formatter03.c") - target_link_libraries("Formatter03" "Zydis") - set_target_properties("Formatter03" PROPERTIES FOLDER "Examples/Formatter") - target_compile_definitions("Formatter03" PRIVATE "_CRT_SECURE_NO_WARNINGS") - zyan_set_common_flags("Formatter03") - zyan_maybe_enable_wpo("Formatter03") - _maybe_set_emscripten_cfg("Formatter03") - - add_executable("ZydisPerfTest" "examples/ZydisPerfTest.c") - target_link_libraries("ZydisPerfTest" "Zydis") - set_target_properties("ZydisPerfTest" PROPERTIES FOLDER "Examples") - target_compile_definitions("ZydisPerfTest" PRIVATE "_CRT_SECURE_NO_WARNINGS") - zyan_set_common_flags("ZydisPerfTest") - zyan_maybe_enable_wpo("ZydisPerfTest") - _maybe_set_emscripten_cfg("ZydisPerfTest") - if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" - OR ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD") - target_compile_definitions("ZydisPerfTest" PRIVATE "_GNU_SOURCE") - find_package(Threads REQUIRED) - target_link_libraries("ZydisPerfTest" Threads::Threads) - endif () - endif () -endif () - -# =============================================================================================== # -# Tools # -# =============================================================================================== # - -if (ZYDIS_BUILD_TOOLS AND NOT ZYAN_NO_LIBC) - if (ZYDIS_FEATURE_DECODER AND ZYDIS_FEATURE_FORMATTER AND (NOT ZYDIS_MINIMAL_MODE)) - add_executable("ZydisDisasm" "tools/ZydisDisasm.c") - target_link_libraries("ZydisDisasm" "Zydis") - set_target_properties ("ZydisDisasm" PROPERTIES FOLDER "Tools") - target_compile_definitions("ZydisDisasm" PRIVATE "_CRT_SECURE_NO_WARNINGS") - zyan_set_common_flags("ZydisDisasm") - zyan_maybe_enable_wpo("ZydisDisasm") - _maybe_set_emscripten_cfg("ZydisDisasm") - install(TARGETS "ZydisDisasm" RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) - - add_executable("ZydisFuzzIn" "tools/ZydisFuzzIn.c") - target_link_libraries("ZydisFuzzIn" "Zydis") - set_target_properties("ZydisFuzzIn" PROPERTIES FOLDER "Tools") - target_compile_definitions("ZydisFuzzIn" PRIVATE "_CRT_SECURE_NO_WARNINGS") - zyan_set_common_flags("ZydisFuzzIn") - zyan_maybe_enable_wpo("ZydisFuzzIn") - _maybe_set_emscripten_cfg("ZydisFuzzIn") - if (ZYDIS_FUZZ_AFL_FAST) - target_compile_definitions("ZydisFuzzIn" PRIVATE "ZYDIS_FUZZ_AFL_FAST") - endif () - if (ZYDIS_LIBFUZZER) - target_compile_definitions("ZydisFuzzIn" PRIVATE "ZYDIS_LIBFUZZER") - endif () - - add_executable("ZydisInfo" "tools/ZydisInfo.c") - target_link_libraries("ZydisInfo" "Zydis") - set_target_properties ("ZydisInfo" PROPERTIES FOLDER "Tools") - target_compile_definitions("ZydisInfo" PRIVATE "_CRT_SECURE_NO_WARNINGS") - zyan_set_common_flags("ZydisInfo") - zyan_maybe_enable_wpo("ZydisInfo") - _maybe_set_emscripten_cfg("ZydisInfo") - install(TARGETS "ZydisInfo" RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) - - add_executable("ZydisPE" "tools/ZydisPE.c") - target_link_libraries("ZydisPE" "Zydis") - set_target_properties ("ZydisPE" PROPERTIES FOLDER "Tools") - target_compile_definitions("ZydisPE" PRIVATE "_CRT_SECURE_NO_WARNINGS") - zyan_set_common_flags("ZydisPE") - zyan_maybe_enable_wpo("ZydisPE") - _maybe_set_emscripten_cfg("ZydisPE") - endif () -endif () diff --git a/dependencies/zycore b/dependencies/zycore deleted file mode 160000 index 6c93d9a..0000000 --- a/dependencies/zycore +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 6c93d9a38e62d4db82f99bf99159e1ee78341e36 diff --git a/include/Zydis/Decoder.h b/include/Zydis/Decoder.h index 8cfbb0c..560145f 100644 --- a/include/Zydis/Decoder.h +++ b/include/Zydis/Decoder.h @@ -194,7 +194,7 @@ typedef struct ZydisDecoder_ * * @return A zyan status code. */ -ZYDIS_EXPORT ZyanStatus ZydisDecoderInit(ZydisDecoder* decoder, ZydisMachineMode machine_mode, +ZyanStatus ZydisDecoderInit(ZydisDecoder* decoder, ZydisMachineMode machine_mode, ZydisAddressWidth address_width); /** @@ -206,7 +206,7 @@ ZYDIS_EXPORT ZyanStatus ZydisDecoderInit(ZydisDecoder* decoder, ZydisMachineMode * * @return A zyan status code. */ -ZYDIS_EXPORT ZyanStatus ZydisDecoderEnableMode(ZydisDecoder* decoder, ZydisDecoderMode mode, +ZyanStatus ZydisDecoderEnableMode(ZydisDecoder* decoder, ZydisDecoderMode mode, ZyanBool enabled); /** @@ -223,7 +223,7 @@ ZYDIS_EXPORT ZyanStatus ZydisDecoderEnableMode(ZydisDecoder* decoder, ZydisDecod * * @return A zyan status code. */ -ZYDIS_EXPORT ZyanStatus ZydisDecoderDecodeBuffer(const ZydisDecoder* decoder, +ZyanStatus ZydisDecoderDecodeBuffer(const ZydisDecoder* decoder, const void* buffer, ZyanUSize length, ZydisDecodedInstruction* instruction); /** @} */ diff --git a/include/Zydis/Formatter.h b/include/Zydis/Formatter.h index bf1dd30..75cc07d 100644 --- a/include/Zydis/Formatter.h +++ b/include/Zydis/Formatter.h @@ -970,7 +970,7 @@ struct ZydisFormatter_ * * @return A zyan status code. */ -ZYDIS_EXPORT ZyanStatus ZydisFormatterInit(ZydisFormatter* formatter, ZydisFormatterStyle style); +ZyanStatus ZydisFormatterInit(ZydisFormatter* formatter, ZydisFormatterStyle style); /* ---------------------------------------------------------------------------------------------- */ /* Setter */ @@ -988,7 +988,7 @@ ZYDIS_EXPORT ZyanStatus ZydisFormatterInit(ZydisFormatter* formatter, ZydisForma * This function returns `ZYAN_STATUS_INVALID_OPERATION` if a property can't be changed for the * current formatter-style. */ -ZYDIS_EXPORT ZyanStatus ZydisFormatterSetProperty(ZydisFormatter* formatter, +ZyanStatus ZydisFormatterSetProperty(ZydisFormatter* formatter, ZydisFormatterProperty property, ZyanUPointer value); /** @@ -1008,7 +1008,7 @@ ZYDIS_EXPORT ZyanStatus ZydisFormatterSetProperty(ZydisFormatter* formatter, * This function returns `ZYAN_STATUS_INVALID_OPERATION` if a function can't be replaced for the * current formatter-style. */ -ZYDIS_EXPORT ZyanStatus ZydisFormatterSetHook(ZydisFormatter* formatter, +ZyanStatus ZydisFormatterSetHook(ZydisFormatter* formatter, ZydisFormatterFunction type, const void** callback); /* ---------------------------------------------------------------------------------------------- */ @@ -1027,7 +1027,7 @@ ZYDIS_EXPORT ZyanStatus ZydisFormatterSetHook(ZydisFormatter* formatter, * * @return A zyan status code. */ -ZYDIS_EXPORT ZyanStatus ZydisFormatterFormatInstruction(const ZydisFormatter* formatter, +ZyanStatus ZydisFormatterFormatInstruction(const ZydisFormatter* formatter, const ZydisDecodedInstruction* instruction, char* buffer, ZyanUSize length, ZyanU64 runtime_address); @@ -1045,7 +1045,7 @@ ZYDIS_EXPORT ZyanStatus ZydisFormatterFormatInstruction(const ZydisFormatter* fo * * @return A zyan status code. */ -ZYDIS_EXPORT ZyanStatus ZydisFormatterFormatInstructionEx(const ZydisFormatter* formatter, +ZyanStatus ZydisFormatterFormatInstructionEx(const ZydisFormatter* formatter, const ZydisDecodedInstruction* instruction, char* buffer, ZyanUSize length, ZyanU64 runtime_address, void* user_data); @@ -1065,7 +1065,7 @@ ZYDIS_EXPORT ZyanStatus ZydisFormatterFormatInstructionEx(const ZydisFormatter* * Use `ZydisFormatterFormatInstruction` or `ZydisFormatterFormatInstructionEx` to format a * complete instruction. */ -ZYDIS_EXPORT ZyanStatus ZydisFormatterFormatOperand(const ZydisFormatter* formatter, +ZyanStatus ZydisFormatterFormatOperand(const ZydisFormatter* formatter, const ZydisDecodedInstruction* instruction, ZyanU8 index, char* buffer, ZyanUSize length, ZyanU64 runtime_address); @@ -1087,7 +1087,7 @@ ZYDIS_EXPORT ZyanStatus ZydisFormatterFormatOperand(const ZydisFormatter* format * Use `ZydisFormatterFormatInstruction` or `ZydisFormatterFormatInstructionEx` to format a * complete instruction. */ -ZYDIS_EXPORT ZyanStatus ZydisFormatterFormatOperandEx(const ZydisFormatter* formatter, +ZyanStatus ZydisFormatterFormatOperandEx(const ZydisFormatter* formatter, const ZydisDecodedInstruction* instruction, ZyanU8 index, char* buffer, ZyanUSize length, ZyanU64 runtime_address, void* user_data); @@ -1108,7 +1108,7 @@ ZYDIS_EXPORT ZyanStatus ZydisFormatterFormatOperandEx(const ZydisFormatter* form * * @return A zyan status code. */ -ZYDIS_EXPORT ZyanStatus ZydisFormatterTokenizeInstruction(const ZydisFormatter* formatter, +ZyanStatus ZydisFormatterTokenizeInstruction(const ZydisFormatter* formatter, const ZydisDecodedInstruction* instruction, void* buffer, ZyanUSize length, ZyanU64 runtime_address, ZydisFormatterTokenConst** token); @@ -1127,7 +1127,7 @@ ZYDIS_EXPORT ZyanStatus ZydisFormatterTokenizeInstruction(const ZydisFormatter* * * @return A zyan status code. */ -ZYDIS_EXPORT ZyanStatus ZydisFormatterTokenizeInstructionEx(const ZydisFormatter* formatter, +ZyanStatus ZydisFormatterTokenizeInstructionEx(const ZydisFormatter* formatter, const ZydisDecodedInstruction* instruction, void* buffer, ZyanUSize length, ZyanU64 runtime_address, ZydisFormatterTokenConst** token, void* user_data); @@ -1148,7 +1148,7 @@ ZYDIS_EXPORT ZyanStatus ZydisFormatterTokenizeInstructionEx(const ZydisFormatter * Use `ZydisFormatterTokenizeInstruction` or `ZydisFormatterTokenizeInstructionEx` to tokenize a * complete instruction. */ -ZYDIS_EXPORT ZyanStatus ZydisFormatterTokenizeOperand(const ZydisFormatter* formatter, +ZyanStatus ZydisFormatterTokenizeOperand(const ZydisFormatter* formatter, const ZydisDecodedInstruction* instruction, ZyanU8 index, void* buffer, ZyanUSize length, ZyanU64 runtime_address, ZydisFormatterTokenConst** token); @@ -1171,7 +1171,7 @@ ZYDIS_EXPORT ZyanStatus ZydisFormatterTokenizeOperand(const ZydisFormatter* form * Use `ZydisFormatterTokenizeInstruction` or `ZydisFormatterTokenizeInstructionEx` to tokenize a * complete instruction. */ -ZYDIS_EXPORT ZyanStatus ZydisFormatterTokenizeOperandEx(const ZydisFormatter* formatter, +ZyanStatus ZydisFormatterTokenizeOperandEx(const ZydisFormatter* formatter, const ZydisDecodedInstruction* instruction, ZyanU8 index, void* buffer, ZyanUSize length, ZyanU64 runtime_address, ZydisFormatterTokenConst** token, void* user_data); diff --git a/include/Zydis/FormatterBuffer.h b/include/Zydis/FormatterBuffer.h index 2ae2efe..a06e67b 100644 --- a/include/Zydis/FormatterBuffer.h +++ b/include/Zydis/FormatterBuffer.h @@ -32,7 +32,6 @@ #ifndef ZYDIS_FORMATTER_TOKEN_H #define ZYDIS_FORMATTER_TOKEN_H -#include #include #include #include @@ -201,7 +200,7 @@ typedef struct ZydisFormatterBuffer_ * * @return A zyan status code. */ -ZYDIS_EXPORT ZyanStatus ZydisFormatterTokenGetValue(const ZydisFormatterToken* token, +ZyanStatus ZydisFormatterTokenGetValue(const ZydisFormatterToken* token, ZydisTokenType* type, ZyanConstCharPointer* value); /** @@ -212,7 +211,7 @@ ZYDIS_EXPORT ZyanStatus ZydisFormatterTokenGetValue(const ZydisFormatterToken* t * * @return A zyan status code. */ -ZYDIS_EXPORT ZyanStatus ZydisFormatterTokenNext(ZydisFormatterTokenConst** token); +ZyanStatus ZydisFormatterTokenNext(ZydisFormatterTokenConst** token); /* ---------------------------------------------------------------------------------------------- */ /* Buffer */ @@ -229,7 +228,7 @@ ZYDIS_EXPORT ZyanStatus ZydisFormatterTokenNext(ZydisFormatterTokenConst** token * This function returns `ZYAN_STATUS_INVALID_OPERATION`, if the buffer does not contain at least * one token. */ -ZYDIS_EXPORT ZyanStatus ZydisFormatterBufferGetToken(const ZydisFormatterBuffer* buffer, +ZyanStatus ZydisFormatterBufferGetToken(const ZydisFormatterBuffer* buffer, ZydisFormatterTokenConst** token); /** @@ -247,7 +246,7 @@ ZYDIS_EXPORT ZyanStatus ZydisFormatterBufferGetToken(const ZydisFormatterBuffer* * The returned string always refers to the literal value of the current (most recently added) * token and will remain valid until the buffer is destroyed. */ -ZYDIS_EXPORT ZyanStatus ZydisFormatterBufferGetString(ZydisFormatterBuffer* buffer, +ZyanStatus ZydisFormatterBufferGetString(ZydisFormatterBuffer* buffer, ZyanString** string); /** @@ -261,7 +260,7 @@ ZYDIS_EXPORT ZyanStatus ZydisFormatterBufferGetString(ZydisFormatterBuffer* buff * Note that the `ZyanString` instance returned by `ZydisFormatterBufferGetString` will * automatically be updated by calling this function. */ -ZYDIS_EXPORT ZyanStatus ZydisFormatterBufferAppend(ZydisFormatterBuffer* buffer, +ZyanStatus ZydisFormatterBufferAppend(ZydisFormatterBuffer* buffer, ZydisTokenType type); /** @@ -275,7 +274,7 @@ ZYDIS_EXPORT ZyanStatus ZydisFormatterBufferAppend(ZydisFormatterBuffer* buffer, * Note that the buffer-state is saved inside the buffer itself and thus becomes invalid as soon * as the buffer gets overwritten or destroyed. */ -ZYDIS_EXPORT ZyanStatus ZydisFormatterBufferRemember(const ZydisFormatterBuffer* buffer, +ZyanStatus ZydisFormatterBufferRemember(const ZydisFormatterBuffer* buffer, ZyanUPointer* state); /** @@ -292,7 +291,7 @@ ZYDIS_EXPORT ZyanStatus ZydisFormatterBufferRemember(const ZydisFormatterBuffer* * Note that the `ZyanString` instance returned by `ZydisFormatterBufferGetString` will * automatically be updated by calling this function. */ -ZYDIS_EXPORT ZyanStatus ZydisFormatterBufferRestore(ZydisFormatterBuffer* buffer, +ZyanStatus ZydisFormatterBufferRestore(ZydisFormatterBuffer* buffer, ZyanUPointer state); /* ---------------------------------------------------------------------------------------------- */ diff --git a/include/Zydis/Internal/DecoderData.h b/include/Zydis/Internal/DecoderData.h index db6cf53..011d56f 100644 --- a/include/Zydis/Internal/DecoderData.h +++ b/include/Zydis/Internal/DecoderData.h @@ -307,7 +307,7 @@ ZYAN_INLINE const ZydisDecoderTreeNode* ZydisDecoderTreeGetRootNode(void) * * @return The specified child node. */ -ZYDIS_NO_EXPORT const ZydisDecoderTreeNode* ZydisDecoderTreeGetChildNode( +const ZydisDecoderTreeNode* ZydisDecoderTreeGetChildNode( const ZydisDecoderTreeNode* parent, ZyanU16 index); /** @@ -317,7 +317,7 @@ ZYDIS_NO_EXPORT const ZydisDecoderTreeNode* ZydisDecoderTreeGetChildNode( * @param node The instruction definition node. * @param info A pointer to the `ZydisInstructionParts` struct. */ -ZYDIS_NO_EXPORT void ZydisGetInstructionEncodingInfo(const ZydisDecoderTreeNode* node, +void ZydisGetInstructionEncodingInfo(const ZydisDecoderTreeNode* node, const ZydisInstructionEncodingInfo** info); /* ---------------------------------------------------------------------------------------------- */ diff --git a/include/Zydis/Internal/SharedData.h b/include/Zydis/Internal/SharedData.h index 5289a3c..fd7bfd3 100644 --- a/include/Zydis/Internal/SharedData.h +++ b/include/Zydis/Internal/SharedData.h @@ -919,7 +919,7 @@ typedef struct ZydisAccessedFlags_ * @param definition A pointer to the variable that receives a pointer to the instruction- * definition. */ -ZYDIS_NO_EXPORT void ZydisGetInstructionDefinition(ZydisInstructionEncoding encoding, +void ZydisGetInstructionDefinition(ZydisInstructionEncoding encoding, ZyanU16 id, const ZydisInstructionDefinition** definition); /* ---------------------------------------------------------------------------------------------- */ @@ -936,7 +936,7 @@ ZYDIS_NO_EXPORT void ZydisGetInstructionDefinition(ZydisInstructionEncoding enco * * @return The number of operands for the given instruction-definition. */ -ZYDIS_NO_EXPORT ZyanU8 ZydisGetOperandDefinitions(const ZydisInstructionDefinition* definition, +ZyanU8 ZydisGetOperandDefinitions(const ZydisInstructionDefinition* definition, const ZydisOperandDefinition** operand); #endif @@ -952,7 +952,7 @@ ZYDIS_NO_EXPORT ZyanU8 ZydisGetOperandDefinitions(const ZydisInstructionDefiniti * @param type The actual element type. * @param size The element size. */ -ZYDIS_NO_EXPORT void ZydisGetElementInfo(ZydisInternalElementType element, ZydisElementType* type, +void ZydisGetElementInfo(ZydisInternalElementType element, ZydisElementType* type, ZydisElementSize* size); #endif @@ -969,7 +969,7 @@ ZYDIS_NO_EXPORT void ZydisGetElementInfo(ZydisInternalElementType element, Zydis * * @return `ZYAN_TRUE`, if the instruction accesses any flags, or `ZYAN_FALSE`, if not. */ -ZYDIS_NO_EXPORT ZyanBool ZydisGetAccessedFlags(const ZydisInstructionDefinition* definition, +ZyanBool ZydisGetAccessedFlags(const ZydisInstructionDefinition* definition, const ZydisAccessedFlags** flags); #endif diff --git a/include/Zydis/MetaInfo.h b/include/Zydis/MetaInfo.h index 6867d32..400dc09 100644 --- a/include/Zydis/MetaInfo.h +++ b/include/Zydis/MetaInfo.h @@ -32,7 +32,6 @@ #ifndef ZYDIS_METAINFO_H #define ZYDIS_METAINFO_H -#include #include #include @@ -59,7 +58,7 @@ extern "C" { * * @return The instruction category string or `ZYAN_NULL`, if an invalid category was passed. */ -ZYDIS_EXPORT const char* ZydisCategoryGetString(ZydisInstructionCategory category); +const char* ZydisCategoryGetString(ZydisInstructionCategory category); /** * Returns the specified isa-set string. @@ -68,7 +67,7 @@ ZYDIS_EXPORT const char* ZydisCategoryGetString(ZydisInstructionCategory categor * * @return The isa-set string or `ZYAN_NULL`, if an invalid isa-set was passed. */ -ZYDIS_EXPORT const char* ZydisISASetGetString(ZydisISASet isa_set); +const char* ZydisISASetGetString(ZydisISASet isa_set); /** * Returns the specified isa-extension string. @@ -77,7 +76,7 @@ ZYDIS_EXPORT const char* ZydisISASetGetString(ZydisISASet isa_set); * * @return The isa-extension string or `ZYAN_NULL`, if an invalid isa-extension was passed. */ -ZYDIS_EXPORT const char* ZydisISAExtGetString(ZydisISAExt isa_ext); +const char* ZydisISAExtGetString(ZydisISAExt isa_ext); /* ============================================================================================== */ diff --git a/include/Zydis/Mnemonic.h b/include/Zydis/Mnemonic.h index dd8fec8..132d6f6 100644 --- a/include/Zydis/Mnemonic.h +++ b/include/Zydis/Mnemonic.h @@ -62,7 +62,7 @@ extern "C" { * * @return The instruction mnemonic string or `ZYAN_NULL`, if an invalid mnemonic was passed. */ -ZYDIS_EXPORT const char* ZydisMnemonicGetString(ZydisMnemonic mnemonic); +const char* ZydisMnemonicGetString(ZydisMnemonic mnemonic); /** * Returns the specified instruction mnemonic as `ZydisShortString`. @@ -73,7 +73,7 @@ ZYDIS_EXPORT const char* ZydisMnemonicGetString(ZydisMnemonic mnemonic); * * The `buffer` of the returned struct is guaranteed to be zero-terminated in this special case. */ -ZYDIS_EXPORT const ZydisShortString* ZydisMnemonicGetStringWrapped(ZydisMnemonic mnemonic); +const ZydisShortString* ZydisMnemonicGetStringWrapped(ZydisMnemonic mnemonic); /** * @} diff --git a/include/Zydis/Register.h b/include/Zydis/Register.h index 0ff955f..a59a597 100644 --- a/include/Zydis/Register.h +++ b/include/Zydis/Register.h @@ -200,7 +200,7 @@ typedef struct ZydisRegisterContext_ * @return The register specified by the `register_class` and `id` tuple or `ZYDIS_REGISTER_NONE`, * if an invalid parameter was passed. */ -ZYDIS_EXPORT ZydisRegister ZydisRegisterEncode(ZydisRegisterClass register_class, ZyanU8 id); +ZydisRegister ZydisRegisterEncode(ZydisRegisterClass register_class, ZyanU8 id); /** * Returns the id of the specified register. @@ -209,7 +209,7 @@ ZYDIS_EXPORT ZydisRegister ZydisRegisterEncode(ZydisRegisterClass register_class * * @return The id of the specified register, or -1 if an invalid parameter was passed. */ -ZYDIS_EXPORT ZyanI8 ZydisRegisterGetId(ZydisRegister reg); +ZyanI8 ZydisRegisterGetId(ZydisRegister reg); /** * Returns the register-class of the specified register. @@ -218,7 +218,7 @@ ZYDIS_EXPORT ZyanI8 ZydisRegisterGetId(ZydisRegister reg); * * @return The register-class of the specified register. */ -ZYDIS_EXPORT ZydisRegisterClass ZydisRegisterGetClass(ZydisRegister reg); +ZydisRegisterClass ZydisRegisterGetClass(ZydisRegister reg); /** * Returns the width of the specified register. @@ -229,7 +229,7 @@ ZYDIS_EXPORT ZydisRegisterClass ZydisRegisterGetClass(ZydisRegister reg); * @return The width of the specified register, or `ZYDIS_REGISTER_NONE` if the register is * invalid for the active machine-mode. */ -ZYDIS_EXPORT ZydisRegisterWidth ZydisRegisterGetWidth(ZydisMachineMode mode, ZydisRegister reg); +ZydisRegisterWidth ZydisRegisterGetWidth(ZydisMachineMode mode, ZydisRegister reg); /** * Returns the largest enclosing register of the given register. @@ -240,7 +240,7 @@ ZYDIS_EXPORT ZydisRegisterWidth ZydisRegisterGetWidth(ZydisMachineMode mode, Zyd * @return The largest enclosing register of the given register, or `ZYDIS_REGISTER_NONE` if the * register is invalid for the active machine-mode or does not have an enclosing-register. */ -ZYDIS_EXPORT ZydisRegister ZydisRegisterGetLargestEnclosing(ZydisMachineMode mode, +ZydisRegister ZydisRegisterGetLargestEnclosing(ZydisMachineMode mode, ZydisRegister reg); /** @@ -250,7 +250,7 @@ ZYDIS_EXPORT ZydisRegister ZydisRegisterGetLargestEnclosing(ZydisMachineMode mod * * @return The register string or `ZYAN_NULL`, if an invalid register was passed. */ -ZYDIS_EXPORT const char* ZydisRegisterGetString(ZydisRegister reg); +const char* ZydisRegisterGetString(ZydisRegister reg); /** * Returns the specified register string as `ZydisShortString`. @@ -261,7 +261,7 @@ ZYDIS_EXPORT const char* ZydisRegisterGetString(ZydisRegister reg); * * The `buffer` of the returned struct is guaranteed to be zero-terminated in this special case. */ -ZYDIS_EXPORT const ZydisShortString* ZydisRegisterGetStringWrapped(ZydisRegister reg); +const ZydisShortString* ZydisRegisterGetStringWrapped(ZydisRegister reg); /* ---------------------------------------------------------------------------------------------- */ /* Register class */ @@ -275,7 +275,7 @@ ZYDIS_EXPORT const ZydisShortString* ZydisRegisterGetStringWrapped(ZydisRegister * * @return The width of the specified register. */ -ZYDIS_EXPORT ZydisRegisterWidth ZydisRegisterClassGetWidth(ZydisMachineMode mode, +ZydisRegisterWidth ZydisRegisterClassGetWidth(ZydisMachineMode mode, ZydisRegisterClass register_class); /* ---------------------------------------------------------------------------------------------- */ diff --git a/include/Zydis/ShortString.h b/include/Zydis/ShortString.h index bed45af..f55330a 100644 --- a/include/Zydis/ShortString.h +++ b/include/Zydis/ShortString.h @@ -33,7 +33,6 @@ #ifndef ZYDIS_SHORTSTRING_H #define ZYDIS_SHORTSTRING_H -#include #include #include diff --git a/include/Zydis/Utils.h b/include/Zydis/Utils.h index aef9e96..5e3e3ad 100644 --- a/include/Zydis/Utils.h +++ b/include/Zydis/Utils.h @@ -175,7 +175,7 @@ typedef struct ZydisInstructionSegments_ * - `MEM` operands with absolute address (e.g. `MOV RAX, [0x12345678]`) * - The displacement needs to get truncated and zero extended */ -ZYDIS_EXPORT ZyanStatus ZydisCalcAbsoluteAddress(const ZydisDecodedInstruction* instruction, +ZyanStatus ZydisCalcAbsoluteAddress(const ZydisDecodedInstruction* instruction, const ZydisDecodedOperand* operand, ZyanU64 runtime_address, ZyanU64* result_address); /** @@ -195,7 +195,7 @@ ZYDIS_EXPORT ZyanStatus ZydisCalcAbsoluteAddress(const ZydisDecodedInstruction* * Note that `IP/EIP/RIP` from the register-context will be ignored in favor of the passed * runtime-address. */ -ZYDIS_EXPORT ZyanStatus ZydisCalcAbsoluteAddressEx(const ZydisDecodedInstruction* instruction, +ZyanStatus ZydisCalcAbsoluteAddressEx(const ZydisDecodedInstruction* instruction, const ZydisDecodedOperand* operand, ZyanU64 runtime_address, const ZydisRegisterContext* register_context, ZyanU64* result_address); @@ -212,7 +212,7 @@ ZYDIS_EXPORT ZyanStatus ZydisCalcAbsoluteAddressEx(const ZydisDecodedInstruction * * @return A zyan status code. */ -ZYDIS_EXPORT ZyanStatus ZydisGetAccessedFlagsByAction(const ZydisDecodedInstruction* instruction, +ZyanStatus ZydisGetAccessedFlagsByAction(const ZydisDecodedInstruction* instruction, ZydisCPUFlagAction action, ZydisCPUFlags* flags); /** @@ -226,7 +226,7 @@ ZYDIS_EXPORT ZyanStatus ZydisGetAccessedFlagsByAction(const ZydisDecodedInstruct * * @return A zyan status code. */ -ZYDIS_DEPRECATED_EXPORT ZyanStatus ZydisGetAccessedFlagsRead( +ZyanStatus ZydisGetAccessedFlagsRead( const ZydisDecodedInstruction* instruction, ZydisCPUFlags* flags); /** @@ -241,7 +241,7 @@ ZYDIS_DEPRECATED_EXPORT ZyanStatus ZydisGetAccessedFlagsRead( * * @return A zyan status code. */ -ZYDIS_DEPRECATED_EXPORT ZyanStatus ZydisGetAccessedFlagsWritten( +ZyanStatus ZydisGetAccessedFlagsWritten( const ZydisDecodedInstruction* instruction, ZydisCPUFlags* flags); /* ---------------------------------------------------------------------------------------------- */ @@ -257,7 +257,7 @@ ZYDIS_DEPRECATED_EXPORT ZyanStatus ZydisGetAccessedFlagsWritten( * * @return A zyan status code. */ -ZYDIS_EXPORT ZyanStatus ZydisGetInstructionSegments(const ZydisDecodedInstruction* instruction, +ZyanStatus ZydisGetInstructionSegments(const ZydisDecodedInstruction* instruction, ZydisInstructionSegments* segments); /* ---------------------------------------------------------------------------------------------- */ diff --git a/include/Zydis/Zydis.h b/include/Zydis/Zydis.h index 9578fa5..64d1889 100644 --- a/include/Zydis/Zydis.h +++ b/include/Zydis/Zydis.h @@ -144,7 +144,7 @@ typedef enum ZydisFeature_ * Use the macros provided in this file to extract the major, minor, patch and build part from the * returned version value. */ -ZYDIS_EXPORT ZyanU64 ZydisGetVersion(void); +ZyanU64 ZydisGetVersion(void); /** * Checks, if the specified feature is enabled in the current zydis library instance. @@ -154,7 +154,7 @@ ZYDIS_EXPORT ZyanU64 ZydisGetVersion(void); * @return `ZYAN_STATUS_TRUE` if the feature is enabled, `ZYAN_STATUS_FALSE` if not. Another * zyan status code, if an error occured. */ -ZYDIS_EXPORT ZyanStatus ZydisIsFeatureEnabled(ZydisFeature feature); +ZyanStatus ZydisIsFeatureEnabled(ZydisFeature feature); /** * @} diff --git a/zycore/CMakeLists.txt b/zycore/CMakeLists.txt new file mode 100644 index 0000000..7037ebf --- /dev/null +++ b/zycore/CMakeLists.txt @@ -0,0 +1,90 @@ +if (TARGET Zycore) + return() +endif () + +cmake_minimum_required(VERSION 3.9 FATAL_ERROR) + +project(Zycore VERSION 1.1.0.0 LANGUAGES C CXX) + +include(GNUInstallDirs) +include(CMakePackageConfigHelpers) + +# =============================================================================================== # +# Overridable options # +# =============================================================================================== # + +# Global configuration +option(ZYAN_NO_LIBC + "Don't use any C standard library functions (for exotic build-envs like kernel drivers)" + OFF) + +# =============================================================================================== # +# Library configuration # +# =============================================================================================== # + +set(ZYCORE_SOURCES + # API + "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/API/Memory.h" + "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/API/Process.h" + "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/API/Synchronization.h" + "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/API/Terminal.h" + "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/API/Thread.h" + # Common + "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/Allocator.h" + "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/ArgParse.h" + "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/Atomic.h" + "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/Bitset.h" + "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/Comparison.h" + "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/Defines.h" + "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/Format.h" + "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/LibC.h" + "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/List.h" + "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/Object.h" + "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/Status.h" + "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/String.h" + "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/Types.h" + "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/Vector.h" + "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/Zycore.h" + "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/Internal/AtomicGNU.h" + "${CMAKE_CURRENT_LIST_DIR}/include/Zycore/Internal/AtomicMSVC.h" + # API + "src/API/Memory.c" + "src/API/Process.c" + "src/API/Synchronization.c" + "src/API/Terminal.c" + "src/API/Thread.c" + # Common + "src/Allocator.c" + "src/ArgParse.c" + "src/Bitset.c" + "src/Format.c" + "src/List.c" + "src/String.c" + "src/Vector.c" + "src/Zycore.c" +) + +add_library("Zycore" STATIC "${ZYCORE_SOURCES}") + +set_target_properties("Zycore" PROPERTIES LINKER_LANGUAGE C) +target_include_directories("Zycore" + PUBLIC + $ + $ + PRIVATE "src") +target_compile_definitions("Zycore" PRIVATE "_CRT_SECURE_NO_WARNINGS") +target_compile_options("Zycore" PRIVATE "-std=c99") + +if (ZYAN_NO_LIBC) + target_compile_definitions("Zycore" PUBLIC "ZYAN_NO_LIBC") + if (UNIX) + set_target_properties("Zycore" PROPERTIES LINK_FLAGS "-nostdlib -nodefaultlibs") + endif () +endif () + +if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" AND NOT ZYAN_NO_LIBC) + target_compile_definitions("Zycore" PRIVATE "_GNU_SOURCE") + set(THREADS_PREFER_PTHREAD_FLAG ON) + find_package(Threads REQUIRED) + target_link_libraries("Zycore" Threads::Threads) +endif () diff --git a/zycore/LICENSE b/zycore/LICENSE new file mode 100644 index 0000000..a7fd67c --- /dev/null +++ b/zycore/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2018-2020 Florian Bernd +Copyright (c) 2018-2020 Joel Höner + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/zycore/README.md b/zycore/README.md new file mode 100644 index 0000000..ff2fc41 --- /dev/null +++ b/zycore/README.md @@ -0,0 +1,29 @@ +# Zyan Core Library for C + +License: MIT +GitHub Actions +Discord + +Internal library providing platform independent types, macros and a fallback for environments without LibC. + +## Features + +- Platform independent types + - Integer types (`ZyanU8`, `ZyanI32`, `ZyanUSize`, ...) + - `ZyanBool` (+ `ZYAN_FALSE`, `ZYAN_TRUE`) + - `ZYAN_NULL` +- Macros + - Compiler/Platform/Architecture detection + - Asserts and static asserts + - Utils (`ARRAY_LENGTH`, `FALLTHROUGH`, `UNUSED`, ...) +- Common types + - `ZyanBitset` + - `ZyanString`/`ZyanStringView` +- Container types + - `ZyanVector` + - `ZyanList` +- LibC abstraction (WiP) + +## License + +Zycore is licensed under the MIT license. diff --git a/zycore/include/Zycore/API/Memory.h b/zycore/include/Zycore/API/Memory.h new file mode 100644 index 0000000..1030e83 --- /dev/null +++ b/zycore/include/Zycore/API/Memory.h @@ -0,0 +1,137 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * @brief + */ + +#ifndef ZYCORE_API_MEMORY_H +#define ZYCORE_API_MEMORY_H + +#include +#include +#include + +#ifndef ZYAN_NO_LIBC + +#if defined(ZYAN_WINDOWS) +# include +#elif defined(ZYAN_POSIX) +# include +#else +# error "Unsupported platform detected" +#endif + +/* ============================================================================================== */ +/* Enums and types */ +/* ============================================================================================== */ + +/** + * Defines the `ZyanMemoryPageProtection` enum. + */ +typedef enum ZyanMemoryPageProtection_ +{ +#if defined(ZYAN_WINDOWS) + + ZYAN_PAGE_READONLY = PAGE_READONLY, + ZYAN_PAGE_READWRITE = PAGE_READWRITE, + ZYAN_PAGE_EXECUTE = PAGE_EXECUTE, + ZYAN_PAGE_EXECUTE_READ = PAGE_EXECUTE_READ, + ZYAN_PAGE_EXECUTE_READWRITE = PAGE_EXECUTE_READWRITE + +#elif defined(ZYAN_POSIX) + + ZYAN_PAGE_READONLY = PROT_READ, + ZYAN_PAGE_READWRITE = PROT_READ | PROT_WRITE, + ZYAN_PAGE_EXECUTE = PROT_EXEC, + ZYAN_PAGE_EXECUTE_READ = PROT_EXEC | PROT_READ, + ZYAN_PAGE_EXECUTE_READWRITE = PROT_EXEC | PROT_READ | PROT_WRITE + +#endif +} ZyanMemoryPageProtection; + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* General */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Returns the system page size. + * + * @return The system page size. + */ +ZYCORE_EXPORT ZyanU32 ZyanMemoryGetSystemPageSize(); + +/** + * Returns the system allocation granularity. + * + * The system allocation granularity specifies the minimum amount of bytes which can be allocated + * at a specific address by a single call of `ZyanMemoryVirtualAlloc`. + * + * This value is typically 64KiB on Windows systems and equal to the page size on most POSIX + * platforms. + * + * @return The system allocation granularity. + */ +ZYCORE_EXPORT ZyanU32 ZyanMemoryGetSystemAllocationGranularity(); + +/* ---------------------------------------------------------------------------------------------- */ +/* Memory management */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Changes the memory protection value of one or more pages. + * + * @param address The start address aligned to a page boundary. + * @param size The size. + * @param protection The new page protection value. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanMemoryVirtualProtect(void* address, ZyanUSize size, + ZyanMemoryPageProtection protection); + +/** + * Releases one or more memory pages starting at the given address. + * + * @param address The start address aligned to a page boundary. + * @param size The size. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanMemoryVirtualFree(void* address, ZyanUSize size); + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ + +#endif /* ZYAN_NO_LIBC */ + +#endif /* ZYCORE_API_MEMORY_H */ diff --git a/zycore/include/Zycore/API/Process.h b/zycore/include/Zycore/API/Process.h new file mode 100644 index 0000000..f8e1e4f --- /dev/null +++ b/zycore/include/Zycore/API/Process.h @@ -0,0 +1,70 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * @brief + */ + +#ifndef ZYCORE_API_PROCESS_H +#define ZYCORE_API_PROCESS_H + +#include +#include + +#ifndef ZYAN_NO_LIBC + +/* ============================================================================================== */ +/* Enums and types */ +/* ============================================================================================== */ + + + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* General */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * @brief Flushes the process instruction cache. + * + * @param address The address. + * @param size The size. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanProcessFlushInstructionCache(void* address, ZyanUSize size); + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ + +#endif /* ZYAN_NO_LIBC */ + +#endif /* ZYCORE_API_PROCESS_H */ diff --git a/zycore/include/Zycore/API/Synchronization.h b/zycore/include/Zycore/API/Synchronization.h new file mode 100644 index 0000000..ec32f06 --- /dev/null +++ b/zycore/include/Zycore/API/Synchronization.h @@ -0,0 +1,132 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * @brief + */ + +#ifndef ZYCORE_API_SYNCHRONIZATION_H +#define ZYCORE_API_SYNCHRONIZATION_H + +#include +#include + +#ifndef ZYAN_NO_LIBC + +#ifdef __cplusplus +extern "C" { +#endif + +/* ============================================================================================== */ +/* Enums and types */ +/* ============================================================================================== */ + +#if defined(ZYAN_POSIX) + +#include + +/* ---------------------------------------------------------------------------------------------- */ +/* Critical Section */ +/* ---------------------------------------------------------------------------------------------- */ + +typedef pthread_mutex_t ZyanCriticalSection; + +/* ---------------------------------------------------------------------------------------------- */ + +#elif defined(ZYAN_WINDOWS) + +#include + +/* ---------------------------------------------------------------------------------------------- */ +/* Critical Section */ +/* ---------------------------------------------------------------------------------------------- */ + +typedef CRITICAL_SECTION ZyanCriticalSection; + +/* ---------------------------------------------------------------------------------------------- */ + +#else +# error "Unsupported platform detected" +#endif + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Critical Section */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Initializes a critical section. + * + * @param critical_section A pointer to the `ZyanCriticalSection` struct. + */ +ZYCORE_EXPORT ZyanStatus ZyanCriticalSectionInitialize(ZyanCriticalSection* critical_section); + +/** + * Enters a critical section. + * + * @param critical_section A pointer to the `ZyanCriticalSection` struct. + */ +ZYCORE_EXPORT ZyanStatus ZyanCriticalSectionEnter(ZyanCriticalSection* critical_section); + +/** + * Tries to enter a critical section. + * + * @param critical_section A pointer to the `ZyanCriticalSection` struct. + * + * @return Returns `ZYAN_TRUE` if the critical section was successfully entered or `ZYAN_FALSE`, + * if not. + */ +ZYCORE_EXPORT ZyanBool ZyanCriticalSectionTryEnter(ZyanCriticalSection* critical_section); + +/** + * Leaves a critical section. + * + * @param critical_section A pointer to the `ZyanCriticalSection` struct. + */ +ZYCORE_EXPORT ZyanStatus ZyanCriticalSectionLeave(ZyanCriticalSection* critical_section); + +/** + * Deletes a critical section. + * + * @param critical_section A pointer to the `ZyanCriticalSection` struct. + */ +ZYCORE_EXPORT ZyanStatus ZyanCriticalSectionDelete(ZyanCriticalSection* critical_section); + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZYAN_NO_LIBC */ + +#endif /* ZYCORE_API_SYNCHRONIZATION_H */ diff --git a/zycore/include/Zycore/API/Terminal.h b/zycore/include/Zycore/API/Terminal.h new file mode 100644 index 0000000..3bff8c1 --- /dev/null +++ b/zycore/include/Zycore/API/Terminal.h @@ -0,0 +1,162 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file Provides cross-platform terminal helper functions. + * @brief + */ + +#ifndef ZYCORE_API_TERMINAL_H +#define ZYCORE_API_TERMINAL_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef ZYAN_NO_LIBC + +/* ============================================================================================== */ +/* VT100 CSI SGR sequences */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* General */ +/* ---------------------------------------------------------------------------------------------- */ + +#define ZYAN_VT100SGR_RESET "\033[0m" + +/* ---------------------------------------------------------------------------------------------- */ +/* Foreground colors */ +/* ---------------------------------------------------------------------------------------------- */ + +#define ZYAN_VT100SGR_FG_DEFAULT "\033[39m" + +#define ZYAN_VT100SGR_FG_BLACK "\033[30m" +#define ZYAN_VT100SGR_FG_RED "\033[31m" +#define ZYAN_VT100SGR_FG_GREEN "\033[32m" +#define ZYAN_VT100SGR_FG_YELLOW "\033[33m" +#define ZYAN_VT100SGR_FG_BLUE "\033[34m" +#define ZYAN_VT100SGR_FG_MAGENTA "\033[35m" +#define ZYAN_VT100SGR_FG_CYAN "\033[36m" +#define ZYAN_VT100SGR_FG_WHITE "\033[37m" +#define ZYAN_VT100SGR_FG_BRIGHT_BLACK "\033[90m" +#define ZYAN_VT100SGR_FG_BRIGHT_RED "\033[91m" +#define ZYAN_VT100SGR_FG_BRIGHT_GREEN "\033[92m" +#define ZYAN_VT100SGR_FG_BRIGHT_YELLOW "\033[93m" +#define ZYAN_VT100SGR_FG_BRIGHT_BLUE "\033[94m" +#define ZYAN_VT100SGR_FG_BRIGHT_MAGENTA "\033[95m" +#define ZYAN_VT100SGR_FG_BRIGHT_CYAN "\033[96m" +#define ZYAN_VT100SGR_FG_BRIGHT_WHITE "\033[97m" + +/* ---------------------------------------------------------------------------------------------- */ +/* Background color */ +/* ---------------------------------------------------------------------------------------------- */ + +#define ZYAN_VT100SGR_BG_DEFAULT "\033[49m" + +#define ZYAN_VT100SGR_BG_BLACK "\033[40m" +#define ZYAN_VT100SGR_BG_RED "\033[41m" +#define ZYAN_VT100SGR_BG_GREEN "\033[42m" +#define ZYAN_VT100SGR_BG_YELLOW "\033[43m" +#define ZYAN_VT100SGR_BG_BLUE "\033[44m" +#define ZYAN_VT100SGR_BG_MAGENTA "\033[45m" +#define ZYAN_VT100SGR_BG_CYAN "\033[46m" +#define ZYAN_VT100SGR_BG_WHITE "\033[47m" +#define ZYAN_VT100SGR_BG_BRIGHT_BLACK "\033[100m" +#define ZYAN_VT100SGR_BG_BRIGHT_RED "\033[101m" +#define ZYAN_VT100SGR_BG_BRIGHT_GREEN "\033[102m" +#define ZYAN_VT100SGR_BG_BRIGHT_YELLOW "\033[103m" +#define ZYAN_VT100SGR_BG_BRIGHT_BLUE "\033[104m" +#define ZYAN_VT100SGR_BG_BRIGHT_MAGENTA "\033[105m" +#define ZYAN_VT100SGR_BG_BRIGHT_CYAN "\033[106m" +#define ZYAN_VT100SGR_BG_BRIGHT_WHITE "\033[107m" + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ +/* Enums and types */ +/* ============================================================================================== */ + +/** + * Declares the `ZyanStandardStream` enum. + */ +typedef enum ZyanStandardStream_ +{ + /** + * The default input stream. + */ + ZYAN_STDSTREAM_IN, + /** + * The default output stream. + */ + ZYAN_STDSTREAM_OUT, + /** + * The default error stream. + */ + ZYAN_STDSTREAM_ERR +} ZyanStandardStream; + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +/** + * Enables VT100 ansi escape codes for the given stream. + * + * @param stream Either `ZYAN_STDSTREAM_OUT` or `ZYAN_STDSTREAM_ERR`. + * + * @return A zyan status code. + * + * This functions returns `ZYAN_STATUS_SUCCESS` on all non-Windows systems without performing any + * operations, assuming that VT100 is supported by default. + * + * On Windows systems, VT100 functionality is only supported on Windows 10 build 1607 (anniversary + * update) and later. + */ +ZYCORE_EXPORT ZyanStatus ZyanTerminalEnableVT100(ZyanStandardStream stream); + +/** + * Checks, if the given standard stream reads from or writes to a terminal. + * + * @param stream The standard stream to check. + * + * @return `ZYAN_STATUS_TRUE`, if the stream is bound to a terminal, `ZYAN_STATUS_FALSE` if not, + * or another zyan status code if an error occured. + */ +ZYCORE_EXPORT ZyanStatus ZyanTerminalIsTTY(ZyanStandardStream stream); + +/* ============================================================================================== */ + +#endif // ZYAN_NO_LIBC + +#ifdef __cplusplus +} +#endif + +#endif /* ZYCORE_API_TERMINAL_H */ diff --git a/zycore/include/Zycore/API/Thread.h b/zycore/include/Zycore/API/Thread.h new file mode 100644 index 0000000..402a2da --- /dev/null +++ b/zycore/include/Zycore/API/Thread.h @@ -0,0 +1,243 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * @brief + */ + +#ifndef ZYCORE_API_THREAD_H +#define ZYCORE_API_THREAD_H + +#include +#include + +#ifndef ZYAN_NO_LIBC + +#ifdef __cplusplus +extern "C" { +#endif + +/* ============================================================================================== */ +/* Enums and types */ +/* ============================================================================================== */ + +#if defined(ZYAN_POSIX) + +#include + +/* ---------------------------------------------------------------------------------------------- */ +/* General */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZyanThread` data-type. + */ +typedef pthread_t ZyanThread; + +/** + * Defines the `ZyanThreadId` data-type. + */ +typedef ZyanU64 ZyanThreadId; + +/* ---------------------------------------------------------------------------------------------- */ +/* Thread Local Storage (TLS) */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZyanThreadTlsIndex` data-type. + */ +typedef pthread_key_t ZyanThreadTlsIndex; + +/** + * Defines the `ZyanThreadTlsCallback` function prototype. + */ +typedef void(*ZyanThreadTlsCallback)(void* data); + +/** + * Declares a Thread Local Storage (TLS) callback function. + * + * @param name The callback function name. + * @param param_type The callback data parameter type. + * @param param_name The callback data parameter name. + */ +#define ZYAN_THREAD_DECLARE_TLS_CALLBACK(name, param_type, param_name) \ + void name(param_type* param_name) + +/* ---------------------------------------------------------------------------------------------- */ + +#elif defined(ZYAN_WINDOWS) + +#include + +/* ---------------------------------------------------------------------------------------------- */ +/* General */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZyanThread` data-type. + */ +typedef HANDLE ZyanThread; + +/** + * Defines the `ZyanThreadId` data-type. + */ +typedef DWORD ZyanThreadId; + +/* ---------------------------------------------------------------------------------------------- */ +/* Thread Local Storage (TLS) */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZyanThreadTlsIndex` data-type. + */ +typedef DWORD ZyanThreadTlsIndex; + +/** + * Defines the `ZyanThreadTlsCallback` function prototype. + */ +typedef PFLS_CALLBACK_FUNCTION ZyanThreadTlsCallback; + +/** + * Declares a Thread Local Storage (TLS) callback function. + * + * @param name The callback function name. + * @param param_type The callback data parameter type. + * @param param_name The callback data parameter name. + */ +#define ZYAN_THREAD_DECLARE_TLS_CALLBACK(name, param_type, param_name) \ + VOID NTAPI name(param_type* param_name) + +/* ---------------------------------------------------------------------------------------------- */ + +#else +# error "Unsupported platform detected" +#endif + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* General */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Returns the handle of the current thread. + * + * @param thread Receives the handle of the current thread. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanThreadGetCurrentThread(ZyanThread* thread); + +/** + * Returns the unique id of the current thread. + * + * @param thread_id Receives the unique id of the current thread. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanThreadGetCurrentThreadId(ZyanThreadId* thread_id); + +/* ---------------------------------------------------------------------------------------------- */ +/* Thread Local Storage (TLS) */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Allocates a new Thread Local Storage (TLS) slot. + * + * @param index Receives the TLS slot index. + * @param destructor A pointer to a destructor callback which is invoked to finalize the data + * in the TLS slot or `ZYAN_NULL`, if not needed. + * + * The maximum available number of TLS slots is implementation specific and different on each + * platform: + * - Windows + * - A total amount of 128 slots per process are guaranteed + * - POSIX + * - A total amount of 128 slots per process are guaranteed + * - Some systems guarantee larger amounts like e.g. 1024 slots per process + * + * Note that the invocation rules for the destructor callback are implementation specific and + * different on each platform: + * - Windows + * - The callback is invoked when a thread exits + * - The callback is invoked when the process exits + * - The callback is invoked when the TLS slot is released + * - POSIX + * - The callback is invoked when a thread exits and the stored value is not null + * - The callback is NOT invoked when the process exits + * - The callback is NOT invoked when the TLS slot is released + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanThreadTlsAlloc(ZyanThreadTlsIndex* index, + ZyanThreadTlsCallback destructor); + +/** + * Releases a Thread Local Storage (TLS) slot. + * + * @param index The TLS slot index. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanThreadTlsFree(ZyanThreadTlsIndex index); + +/** + * Returns the value inside the given Thread Local Storage (TLS) slot for the + * calling thread. + * + * @param index The TLS slot index. + * @param data Receives the value inside the given Thread Local Storage + * (TLS) slot for the calling thread. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanThreadTlsGetValue(ZyanThreadTlsIndex index, void** data); + +/** + * Set the value of the given Thread Local Storage (TLS) slot for the calling thread. + * + * @param index The TLS slot index. + * @param data The value to store inside the given Thread Local Storage (TLS) slot for the + * calling thread + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanThreadTlsSetValue(ZyanThreadTlsIndex index, void* data); + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZYAN_NO_LIBC */ + +#endif /* ZYCORE_API_THREAD_H */ diff --git a/zycore/include/Zycore/Allocator.h b/zycore/include/Zycore/Allocator.h new file mode 100644 index 0000000..ff80a2c --- /dev/null +++ b/zycore/include/Zycore/Allocator.h @@ -0,0 +1,142 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * @brief + */ + +#ifndef ZYCORE_ALLOCATOR_H +#define ZYCORE_ALLOCATOR_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ============================================================================================== */ +/* Enums and types */ +/* ============================================================================================== */ + +struct ZyanAllocator_; + +/** + * Defines the `ZyanAllocatorAllocate` function prototype. + * + * @param allocator A pointer to the `ZyanAllocator` instance. + * @param p Receives a pointer to the first memory block sufficient to hold an + * array of `n` elements with a size of `element_size`. + * @param element_size The size of a single element. + * @param n The number of elements to allocate storage for. + * + * @return A zyan status code. + * + * This prototype is used for the `allocate()` and `reallocate()` functions. + * + * The result of the `reallocate()` function is undefined, if `p` does not point to a memory block + * previously obtained by `(re-)allocate()`. + */ +typedef ZyanStatus (*ZyanAllocatorAllocate)(struct ZyanAllocator_* allocator, void** p, + ZyanUSize element_size, ZyanUSize n); + +/** + * Defines the `ZyanAllocatorDeallocate` function prototype. + * + * @param allocator A pointer to the `ZyanAllocator` instance. + * @param p The pointer obtained from `(re-)allocate()`. + * @param element_size The size of a single element. + * @param n The number of elements earlier passed to `(re-)allocate()`. + * + * @return A zyan status code. + */ +typedef ZyanStatus (*ZyanAllocatorDeallocate)(struct ZyanAllocator_* allocator, void* p, + ZyanUSize element_size, ZyanUSize n); + +/** + * Defines the `ZyanAllocator` struct. + * + * This is the base class for all custom allocator implementations. + * + * All fields in this struct should be considered as "private". Any changes may lead to unexpected + * behavior. + */ +typedef struct ZyanAllocator_ +{ + /** + * The allocate function. + */ + ZyanAllocatorAllocate allocate; + /** + * The reallocate function. + */ + ZyanAllocatorAllocate reallocate; + /** + * The deallocate function. + */ + ZyanAllocatorDeallocate deallocate; +} ZyanAllocator; + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +/** + * Initializes the given `ZyanAllocator` instance. + * + * @param allocator A pointer to the `ZyanAllocator` instance. + * @param allocate The allocate function. + * @param reallocate The reallocate function. + * @param deallocate The deallocate function. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanAllocatorInit(ZyanAllocator* allocator, ZyanAllocatorAllocate allocate, + ZyanAllocatorAllocate reallocate, ZyanAllocatorDeallocate deallocate); + +#ifndef ZYAN_NO_LIBC + +/** + * Returns the default `ZyanAllocator` instance. + * + * @return A pointer to the default `ZyanAllocator` instance. + * + * The default allocator uses the default memory manager to allocate memory on the heap. + * + * You should in no case modify the returned allocator instance to avoid unexpected behavior. + */ +ZYCORE_EXPORT ZYAN_REQUIRES_LIBC ZyanAllocator* ZyanAllocatorDefault(void); + +#endif // ZYAN_NO_LIBC + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZYCORE_ALLOCATOR_H */ diff --git a/zycore/include/Zycore/ArgParse.h b/zycore/include/Zycore/ArgParse.h new file mode 100644 index 0000000..5d389cb --- /dev/null +++ b/zycore/include/Zycore/ArgParse.h @@ -0,0 +1,173 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Joel Hoener + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * Implements command-line argument parsing. + */ + +#ifndef ZYCORE_ARGPARSE_H +#define ZYCORE_ARGPARSE_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ============================================================================================== */ +/* Structs and other types */ +/* ============================================================================================== */ + +/** + * Definition of a single argument. + */ +typedef struct ZyanArgParseDefinition_ +{ + /** + * The argument name, e.g. `--help`. + * + * Must start with either one or two dashes. Single dash arguments must consist of a single + * character, (e.g. `-n`), double-dash arguments can be of arbitrary length. + */ + const char* name; + /** + * Whether the argument is boolean or expects a value. + */ + ZyanBool boolean; + /** + * Whether this argument is required (error if missing). + */ + ZyanBool required; +} ZyanArgParseDefinition; + +/** + * Configuration for argument parsing. + */ +typedef struct ZyanArgParseConfig_ +{ + /** + * `argv` argument passed to `main` by LibC. + */ + const char** argv; + /** + * `argc` argument passed to `main` by LibC. + */ + ZyanUSize argc; + /** + * Minimum # of accepted unnamed / anonymous arguments. + */ + ZyanUSize min_unnamed_args; + /** + * Maximum # of accepted unnamed / anonymous arguments. + */ + ZyanUSize max_unnamed_args; + /** + * Argument definition array, or `ZYAN_NULL`. + * + * Expects a pointer to an array of `ZyanArgParseDefinition` instances. The array is + * terminated by setting the `.name` field of the last element to `ZYAN_NULL`. If no named + * arguments should be parsed, you can also set this to `ZYAN_NULL`. + */ + ZyanArgParseDefinition* args; +} ZyanArgParseConfig; + +/** + * Information about a parsed argument. + */ +typedef struct ZyanArgParseArg_ +{ + /** + * Corresponding argument definition, or `ZYAN_NULL` for unnamed args. + * + * This pointer is borrowed from the `cfg` pointer passed to `ZyanArgParse`. + */ + const ZyanArgParseDefinition* def; + /** + * Whether the argument has a value (is non-boolean). + */ + ZyanBool has_value; + /** + * If `has_value == true`, then the argument value. + * + * This is a view into the `argv` string array passed to `ZyanArgParse` via the `cfg` argument. + */ + ZyanStringView value; +} ZyanArgParseArg; + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +#ifndef ZYAN_NO_LIBC + +/** + * Parse arguments according to a `ZyanArgParseConfig` definition. + * + * @param cfg Argument parser config to use. + * @param parsed Receives the parsed output. Vector of `ZyanArgParseArg`. Ownership is + * transferred to the user. Input is expected to be uninitialized. On error, + * the vector remains uninitialized. + * @param error_token On error, if it makes sense, receives the argument fragment causing the + * error. Optional, may be `ZYAN_NULL`. The pointer borrows into the `cfg` + * struct and doesn't have to be freed by the user. + * + * @return A `ZyanStatus` status determining whether the parsing succeeded. + */ +ZYCORE_EXPORT ZyanStatus ZyanArgParse(const ZyanArgParseConfig *cfg, ZyanVector* parsed, + const char** error_token); + +#endif + +/** + * Parse arguments according to a `ZyanArgParseConfig` definition. + * + * This version allows specification of a custom memory allocator and thus supports no-libc. + * + * @param cfg Argument parser config to use. + * @param parsed Receives the parsed output. Vector of `ZyanArgParseArg`. Ownership is + * transferred to the user. Input is expected to be uninitialized. On error, + * the vector remains uninitialized. + * @param error_token On error, if it makes sense, receives the argument fragment causing the + * error. Optional, may be `ZYAN_NULL`. The pointer borrows into the `cfg` + * struct and doesn't have to be freed by the user. + * @param allocator The `ZyanAllocator` to be used for allocating the output vector's data. + * + * @return A `ZyanStatus` status determining whether the parsing succeeded. + */ +ZYCORE_EXPORT ZyanStatus ZyanArgParseEx(const ZyanArgParseConfig *cfg, ZyanVector* parsed, + const char** error_token, ZyanAllocator* allocator); + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZYCORE_ARGPARSE_H */ diff --git a/zycore/include/Zycore/Atomic.h b/zycore/include/Zycore/Atomic.h new file mode 100644 index 0000000..f5dcf27 --- /dev/null +++ b/zycore/include/Zycore/Atomic.h @@ -0,0 +1,236 @@ +/*************************************************************************************************** + + Zyan Core Library (Zyan-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * Cross compiler atomic intrinsics. + */ + +#ifndef ZYCORE_ATOMIC_H +#define ZYCORE_ATOMIC_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +/* ============================================================================================== */ +/* Enums and Types */ +/* ============================================================================================== */ + +/* + * Wraps a 32-bit value to provide atomic access. + */ +typedef struct ZyanAtomic32_ +{ + ZyanU32 volatile value; +} ZyanAtomic32; + +/* + * Wraps a 64-bit value to provide atomic access. + */ +typedef struct ZyanAtomic64_ +{ + ZyanU64 volatile value; +} ZyanAtomic64; + +/* + * Wraps a pointer-sized value to provide atomic access. + */ +typedef struct ZyanAtomicPointer_ +{ + ZyanVoidPointer volatile value; +} ZyanAtomicPointer; + +/* ============================================================================================== */ +/* Macros */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Pointer sized */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * @copydoc ZyanAtomicCompareExchange + */ +#define ZYAN_ATOMIC_COMPARE_EXCHANGE(destination, comparand, value) \ + ZyanAtomicCompareExchange((ZyanAtomicPointer*)&(destination), (comparand), (value)) + +/** + * @copydoc ZyanAtomicIncrement + */ +#define ZYAN_ATOMIC_INCREMENT(destination) \ + ZyanAtomicIncrement((ZyanAtomicPointer*)&(destination)); + +/** + * @copydoc ZyanAtomicDecrement + */ +#define ZYAN_ATOMIC_DECREMENT(destination) \ + ZyanAtomicDecrement((ZyanAtomicPointer*)&(destination)); + +/* ---------------------------------------------------------------------------------------------- */ +/* 32-bit */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * @copydoc ZyanAtomicCompareExchange + */ +#define ZYAN_ATOMIC_COMPARE_EXCHANGE32(destination, comparand, value) \ + ZyanAtomicCompareExchange32((ZyanAtomic32*)&(destination), (comparand), (value)) + +/** + * @copydoc ZyanAtomicIncrement + */ +#define ZYAN_ATOMIC_INCREMENT32(destination) \ + ZyanAtomicIncrement32((ZyanAtomic32*)&(destination)); + +/** + * @copydoc ZyanAtomicDecrement + */ +#define ZYAN_ATOMIC_DECREMENT32(destination) \ + ZyanAtomicDecrement32((ZyanAtomic32*)&(destination)); + +/* ---------------------------------------------------------------------------------------------- */ +/* 64-bit */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * @copydoc ZyanAtomicCompareExchange + */ +#define ZYAN_ATOMIC_COMPARE_EXCHANGE64(destination, comparand, value) \ + ZyanAtomicCompareExchange64((ZyanAtomic64*)&(destination), (comparand), (value)) + +/** + * @copydoc ZyanAtomicIncrement + */ +#define ZYAN_ATOMIC_INCREMENT64(destination) \ + ZyanAtomicIncrement64((ZyanAtomic64*)&(destination)); + +/** + * @copydoc ZyanAtomicDecrement + */ +#define ZYAN_ATOMIC_DECREMENT64(destination) \ + ZyanAtomicDecrement64((ZyanAtomic64*)&(destination)); + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ +/* Functions */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Pointer sized */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Compares two values for equality and, if they are equal, replaces the first value. + * + * @param destination A pointer to the destination value. + * @param comparand The value to compare with. + * @param value The replacement value. + * + * @return The original value. + */ +static ZyanUPointer ZyanAtomicCompareExchange(ZyanAtomicPointer* destination, + ZyanUPointer comparand, ZyanUPointer value); + +/** + * Increments the given value and stores the result, as an atomic operation. + * + * @param destination A pointer to the destination value. + * + * @return The incremented value. +*/ +static ZyanUPointer ZyanAtomicIncrement(ZyanAtomicPointer* destination); + +/** + * Decrements the given value and stores the result, as an atomic operation. + * + * @param destination A pointer to the destination value. + * + * @return The decremented value. +*/ +static ZyanUPointer ZyanAtomicDecrement(ZyanAtomicPointer* destination); + +/* ---------------------------------------------------------------------------------------------- */ +/* 32-bit */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * @copydoc ZyanAtomicCompareExchange + */ +static ZyanU32 ZyanAtomicCompareExchange32(ZyanAtomic32* destination, + ZyanU32 comparand, ZyanU32 value); + +/** + * @copydoc ZyanAtomicIncrement + */ +static ZyanU32 ZyanAtomicIncrement32(ZyanAtomic32* destination); + +/** + * @copydoc ZyanAtomicDecrement + */ +static ZyanU32 ZyanAtomicDecrement32(ZyanAtomic32* destination); + +/* ---------------------------------------------------------------------------------------------- */ +/* 64-bit */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * @copydoc ZyanAtomicCompareExchange + */ +static ZyanU64 ZyanAtomicCompareExchange64(ZyanAtomic64* destination, + ZyanU64 comparand, ZyanU64 value); + +/** + * @copydoc ZyanAtomicIncrement + */ +static ZyanU64 ZyanAtomicIncrement64(ZyanAtomic64* destination); + +/** + * @copydoc ZyanAtomicDecrement + */ +static ZyanU64 ZyanAtomicDecrement64(ZyanAtomic64* destination); + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ + +#if defined(ZYAN_CLANG) || defined(ZYAN_GCC) || defined(ZYAN_ICC) +# include +#elif defined(ZYAN_MSVC) +# include +#else +# error "Unsupported compiler detected" +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* ZYCORE_ATOMIC_H */ diff --git a/zycore/include/Zycore/Bitset.h b/zycore/include/Zycore/Bitset.h new file mode 100644 index 0000000..0404f87 --- /dev/null +++ b/zycore/include/Zycore/Bitset.h @@ -0,0 +1,483 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * Implements the bitset class. + */ + +#ifndef ZYCORE_BITSET_H +#define ZYCORE_BITSET_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ============================================================================================== */ +/* Enums and types */ +/* ============================================================================================== */ + +/** + * Defines the `ZyanVector` struct. + * + * All fields in this struct should be considered as "private". Any changes may lead to unexpected + * behavior. + */ +typedef struct ZyanBitset_ +{ + /** + * The bitset size. + */ + ZyanUSize size; + /** + * The bitset data. + */ + ZyanVector bits; +} ZyanBitset; + +/** + * Defines the `ZyanBitsetByteOperation` function prototype. + * + * @param v1 A pointer to the first byte. This value receives the result after performing the + * desired operation. + * @param v2 A pointer to the second byte. + * + * @return A zyan status code. + * + * This function is used to perform byte-wise operations on two `ZyanBitset` instances. + */ +typedef ZyanStatus (*ZyanBitsetByteOperation)(ZyanU8* v1, const ZyanU8* v2); + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Constructor and destructor */ +/* ---------------------------------------------------------------------------------------------- */ + +#ifndef ZYAN_NO_LIBC + +/** + * Initializes the given `ZyanBitset` instance. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * @param count The initial amount of bits. + * + * @return A zyan status code. + * + * The space for the bitset is dynamically allocated by the default allocator using the default + * growth factor and the default shrink threshold. + */ +ZYCORE_EXPORT ZYAN_REQUIRES_LIBC ZyanStatus ZyanBitsetInit(ZyanBitset* bitset, ZyanUSize count); + +#endif // ZYAN_NO_LIBC + +/** + * Initializes the given `ZyanBitset` instance and sets a custom `allocator` and memory + * allocation/deallocation parameters. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * @param count The initial amount of bits. + * @param allocator A pointer to a `ZyanAllocator` instance. + * @param growth_factor The growth factor. + * @param shrink_threshold The shrink threshold. + * + * @return A zyan status code. + * + * A growth factor of `1` disables overallocation and a shrink threshold of `0` disables + * dynamic shrinking. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetInitEx(ZyanBitset* bitset, ZyanUSize count, + ZyanAllocator* allocator, ZyanU8 growth_factor, ZyanU8 shrink_threshold); + +/** + * Initializes the given `ZyanBitset` instance and configures it to use a custom user + * defined buffer with a fixed size. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * @param count The initial amount of bits. + * @param buffer A pointer to the buffer that is used as storage for the bits. + * @param capacity The maximum capacity (number of bytes) of the buffer. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetInitBuffer(ZyanBitset* bitset, ZyanUSize count, void* buffer, + ZyanUSize capacity); + +/** + * Destroys the given `ZyanBitset` instance. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetDestroy(ZyanBitset* bitset); + +/* ---------------------------------------------------------------------------------------------- */ +/* Logical operations */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Performs a byte-wise `operation` for every byte in the given `ZyanBitset` instances. + * + * @param destination A pointer to the `ZyanBitset` instance that is used as the first input and + * as the destination. + * @param source A pointer to the `ZyanBitset` instance that is used as the second input. + * @param operation A pointer to the function that performs the desired operation. + * + * @return A zyan status code. + * + * The `operation` callback is invoked once for every byte in the smallest of the `ZyanBitset` + * instances. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetPerformByteOperation(ZyanBitset* destination, + const ZyanBitset* source, ZyanBitsetByteOperation operation); + +/** + * Performs a logical `AND` operation on the given `ZyanBitset` instances. + * + * @param destination A pointer to the `ZyanBitset` instance that is used as the first input and + * as the destination. + * @param source A pointer to the `ZyanBitset` instance that is used as the second input. + * + * @return A zyan status code. + * + * If the destination bitmask contains more bits than the source one, the state of the remaining + * bits will be undefined. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetAND(ZyanBitset* destination, const ZyanBitset* source); + +/** + * Performs a logical `OR` operation on the given `ZyanBitset` instances. + * + * @param destination A pointer to the `ZyanBitset` instance that is used as the first input and + * as the destination. + * @param source A pointer to the `ZyanBitset` instance that is used as the second input. + * + * @return A zyan status code. + * + * If the destination bitmask contains more bits than the source one, the state of the remaining + * bits will be undefined. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetOR (ZyanBitset* destination, const ZyanBitset* source); + +/** + * Performs a logical `XOR` operation on the given `ZyanBitset` instances. + * + * @param destination A pointer to the `ZyanBitset` instance that is used as the first input and + * as the destination. + * @param source A pointer to the `ZyanBitset` instance that is used as the second input. + * + * @return A zyan status code. + * + * If the destination bitmask contains more bits than the source one, the state of the remaining + * bits will be undefined. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetXOR(ZyanBitset* destination, const ZyanBitset* source); + +/** + * Flips all bits of the given `ZyanBitset` instance. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetFlip(ZyanBitset* bitset); + +/* ---------------------------------------------------------------------------------------------- */ +/* Bit access */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Sets the bit at `index` of the given `ZyanBitset` instance to `1`. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * @param index The bit index. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetSet(ZyanBitset* bitset, ZyanUSize index); + +/** + * Sets the bit at `index` of the given `ZyanBitset` instance to `0`. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * @param index The bit index. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetReset(ZyanBitset* bitset, ZyanUSize index); + +/** + * Sets the bit at `index` of the given `ZyanBitset` instance to the specified `value`. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * @param index The bit index. + * @param value The new value. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetAssign(ZyanBitset* bitset, ZyanUSize index, ZyanBool value); + +/** + * Toggles the bit at `index` of the given `ZyanBitset` instance. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * @param index The bit index. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetToggle(ZyanBitset* bitset, ZyanUSize index); + +/** + * Returns the value of the bit at `index`. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * @param index The bit index. + * + * @return `ZYAN_STATUS_TRUE`, if the bit is set or `ZYAN_STATUS_FALSE`, if not, Another zyan + * status code, if an error occurred. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetTest(ZyanBitset* bitset, ZyanUSize index); + +/** + * Returns the value of the most significant bit. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * + * @return `ZYAN_STATUS_TRUE`, if the bit is set or `ZYAN_STATUS_FALSE`, if not. Another zyan + * status code, if an error occurred. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetTestMSB(ZyanBitset* bitset); + +/** + * Returns the value of the least significant bit. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * + * @return `ZYAN_STATUS_TRUE`, if the bit is set or `ZYAN_STATUS_FALSE`, if not. Another zyan + * status code, if an error occurred. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetTestLSB(ZyanBitset* bitset); + +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Sets all bits of the given `ZyanBitset` instance to `1`. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetSetAll(ZyanBitset* bitset); + +/** + * Sets all bits of the given `ZyanBitset` instance to `0`. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetResetAll(ZyanBitset* bitset); + +/* ---------------------------------------------------------------------------------------------- */ +/* Size management */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Adds a new bit at the end of the bitset. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * @param value The value of the new bit. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetPush(ZyanBitset* bitset, ZyanBool value); + +/** + * Removes the last bit of the bitset. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetPop(ZyanBitset* bitset); + +/** + * Deletes all bits of the given `ZyanBitset` instance. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetClear(ZyanBitset* bitset); + +/* ---------------------------------------------------------------------------------------------- */ +/* Memory management */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Changes the capacity of the given `ZyanBitset` instance. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * @param count The new capacity (number of bits). + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetReserve(ZyanBitset* bitset, ZyanUSize count); + +/** + * Shrinks the capacity of the given bitset to match it's size. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetShrinkToFit(ZyanBitset* bitset); + +/* ---------------------------------------------------------------------------------------------- */ +/* Information */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Returns the current size of the bitset in bits. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * @param size Receives the size of the bitset in bits. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetGetSize(const ZyanBitset* bitset, ZyanUSize* size); + +/** + * Returns the current capacity of the bitset in bits. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * @param capacity Receives the size of the bitset in bits. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetGetCapacity(const ZyanBitset* bitset, ZyanUSize* capacity); + +/** + * Returns the current size of the bitset in bytes. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * @param size Receives the size of the bitset in bytes. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetGetSizeBytes(const ZyanBitset* bitset, ZyanUSize* size); + +/** + * Returns the current capacity of the bitset in bytes. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * @param capacity Receives the size of the bitset in bytes. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetGetCapacityBytes(const ZyanBitset* bitset, ZyanUSize* capacity); + +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Returns the amount of bits set in the given bitset. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * @param count Receives the amount of bits set in the given bitset. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetCount(const ZyanBitset* bitset, ZyanUSize* count); + +/** + * Checks, if all bits of the given bitset are set. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * + * @return `ZYAN_STATUS_TRUE`, if all bits are set, `ZYAN_STATUS_FALSE`, if not. Another zyan + * status code, if an error occurred. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetAll(const ZyanBitset* bitset); + +/** + * Checks, if at least one bit of the given bitset is set. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * + * @return `ZYAN_STATUS_TRUE`, if at least one bit is set, `ZYAN_STATUS_FALSE`, if not. Another + * zyan status code, if an error occurred. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetAny(const ZyanBitset* bitset); + +/** + * Checks, if none bits of the given bitset are set. + * + * @param bitset A pointer to the `ZyanBitset` instance. + * + * @return `ZYAN_STATUS_TRUE`, if none bits are set, `ZYAN_STATUS_FALSE`, if not. Another zyan + * status code, if an error occurred. + */ +ZYCORE_EXPORT ZyanStatus ZyanBitsetNone(const ZyanBitset* bitset); + +///* ---------------------------------------------------------------------------------------------- */ +// +///** +// * Returns a 32-bit unsigned integer representation of the data. +// * +// * @param bitset A pointer to the `ZyanBitset` instance. +// * @param value Receives the 32-bit unsigned integer representation of the data. +// * +// * @return A zyan status code. +// */ +//ZYCORE_EXPORT ZyanStatus ZyanBitsetToU32(const ZyanBitset* bitset, ZyanU32* value); +// +///** +// * Returns a 64-bit unsigned integer representation of the data. +// * +// * @param bitset A pointer to the `ZyanBitset` instance. +// * @param value Receives the 64-bit unsigned integer representation of the data. +// * +// * @return A zyan status code. +// */ +//ZYCORE_EXPORT ZyanStatus ZyanBitsetToU64(const ZyanBitset* bitset, ZyanU64* value); + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZYCORE_BITSET_H */ diff --git a/zycore/include/Zycore/Comparison.h b/zycore/include/Zycore/Comparison.h new file mode 100644 index 0000000..6d8b518 --- /dev/null +++ b/zycore/include/Zycore/Comparison.h @@ -0,0 +1,316 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * Defines prototypes of general-purpose comparison functions. + */ + +#ifndef ZYCORE_COMPARISON_H +#define ZYCORE_COMPARISON_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ============================================================================================== */ +/* Enums and types */ +/* ============================================================================================== */ + +/** + * Defines the `ZyanEqualityComparison` function prototype. + * + * @param left A pointer to the first element. + * @param right A pointer to the second element. + * + * @return This function should return `ZYAN_TRUE` if the `left` element equals the `right` one + * or `ZYAN_FALSE`, if not. + */ +typedef ZyanBool (*ZyanEqualityComparison)(const void* left, const void* right); + +/** + * Defines the `ZyanComparison` function prototype. + * + * @param left A pointer to the first element. + * @param right A pointer to the second element. + * + * @return This function should return values in the following range: + * `left == right -> result == 0` + * `left < right -> result < 0` + * `left > right -> result > 0` + */ +typedef ZyanI32 (*ZyanComparison)(const void* left, const void* right); + +/* ============================================================================================== */ +/* Macros */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Equality comparison functions */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Declares a generic equality comparison function for an integral data-type. + * + * @param name The name of the function. + * @param type The name of the integral data-type. + */ +#define ZYAN_DECLARE_EQUALITY_COMPARISON(name, type) \ + ZyanBool name(const type* left, const type* right) \ + { \ + ZYAN_ASSERT(left); \ + ZYAN_ASSERT(right); \ + \ + return (*left == *right) ? ZYAN_TRUE : ZYAN_FALSE; \ + } + +/** + * Declares a generic equality comparison function that compares a single integral + * data-type field of a struct. + * + * @param name The name of the function. + * @param type The name of the integral data-type. + * @param field_name The name of the struct field. + */ +#define ZYAN_DECLARE_EQUALITY_COMPARISON_FOR_FIELD(name, type, field_name) \ + ZyanBool name(const type* left, const type* right) \ + { \ + ZYAN_ASSERT(left); \ + ZYAN_ASSERT(right); \ + \ + return (left->field_name == right->field_name) ? ZYAN_TRUE : ZYAN_FALSE; \ + } + +/* ---------------------------------------------------------------------------------------------- */ +/* Comparison functions */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Declares a generic comparison function for an integral data-type. + * + * @param name The name of the function. + * @param type The name of the integral data-type. + */ +#define ZYAN_DECLARE_COMPARISON(name, type) \ + ZyanI32 name(const type* left, const type* right) \ + { \ + ZYAN_ASSERT(left); \ + ZYAN_ASSERT(right); \ + \ + if (*left < *right) \ + { \ + return -1; \ + } \ + if (*left > *right) \ + { \ + return 1; \ + } \ + return 0; \ + } + +/** + * Declares a generic comparison function that compares a single integral data-type field + * of a struct. + * + * @param name The name of the function. + * @param type The name of the integral data-type. + * @param field_name The name of the struct field. + */ +#define ZYAN_DECLARE_COMPARISON_FOR_FIELD(name, type, field_name) \ + ZyanI32 name(const type* left, const type* right) \ + { \ + ZYAN_ASSERT(left); \ + ZYAN_ASSERT(right); \ + \ + if (left->field_name < right->field_name) \ + { \ + return -1; \ + } \ + if (left->field_name > right->field_name) \ + { \ + return 1; \ + } \ + return 0; \ + } + + /* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Default equality comparison functions */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines a default equality comparison function for pointer values. + * + * @param left A pointer to the first value. + * @param right A pointer to the second value. + * + * @return Returns `ZYAN_TRUE` if the `left` value equals the `right` one or `ZYAN_FALSE`, if + * not. + */ +ZYAN_INLINE ZYAN_DECLARE_EQUALITY_COMPARISON(ZyanEqualsPointer, void* const) + +/** + * Defines a default equality comparison function for `ZyanBool` values. + * + * @param left A pointer to the first value. + * @param right A pointer to the second value. + * + * @return Returns `ZYAN_TRUE` if the `left` value equals the `right` one or `ZYAN_FALSE`, if + * not. + */ +ZYAN_INLINE ZYAN_DECLARE_EQUALITY_COMPARISON(ZyanEqualsBool, ZyanBool) + +/** + * Defines a default equality comparison function for 8-bit numeric values. + * + * @param left A pointer to the first value. + * @param right A pointer to the second value. + * + * @return Returns `ZYAN_TRUE` if the `left` value equals the `right` one or `ZYAN_FALSE`, if + * not. + */ +ZYAN_INLINE ZYAN_DECLARE_EQUALITY_COMPARISON(ZyanEqualsNumeric8, ZyanU8) + +/** + * Defines a default equality comparison function for 16-bit numeric values. + * + * @param left A pointer to the first value. + * @param right A pointer to the second value. + * + * @return Returns `ZYAN_TRUE` if the `left` value equals the `right` one or `ZYAN_FALSE`, if + * not. + */ +ZYAN_INLINE ZYAN_DECLARE_EQUALITY_COMPARISON(ZyanEqualsNumeric16, ZyanU16) + +/** + * Defines a default equality comparison function for 32-bit numeric values. + * + * @param left A pointer to the first value. + * @param right A pointer to the second value. + * + * @return Returns `ZYAN_TRUE` if the `left` value equals the `right` one or `ZYAN_FALSE`, if + * not. + */ +ZYAN_INLINE ZYAN_DECLARE_EQUALITY_COMPARISON(ZyanEqualsNumeric32, ZyanU32) + +/** + * Defines a default equality comparison function for 64-bit numeric values. + * + * @param left A pointer to the first value. + * @param right A pointer to the second value. + * + * @return Returns `ZYAN_TRUE` if the `left` value equals the `right` one or `ZYAN_FALSE`, if + * not. + */ +ZYAN_INLINE ZYAN_DECLARE_EQUALITY_COMPARISON(ZyanEqualsNumeric64, ZyanU64) + +/* ---------------------------------------------------------------------------------------------- */ +/* Default comparison functions */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines a default comparison function for pointer values. + * + * @param left A pointer to the first value. + * @param right A pointer to the second value. + * + * @return Returns `0` if the `left` value equals the `right` one, `-1` if the `left` value is + * less than the `right` one, or `1` if the `left` value is greater than the `right` one. + */ +ZYAN_INLINE ZYAN_DECLARE_COMPARISON(ZyanComparePointer, void* const) + +/** + * Defines a default comparison function for `ZyanBool` values. + * + * @param left A pointer to the first value. + * @param right A pointer to the second value. + * + * @return Returns `0` if the `left` value equals the `right` one, `-1` if the `left` value is + * less than the `right` one, or `1` if the `left` value is greater than the `right` one. + */ +ZYAN_INLINE ZYAN_DECLARE_COMPARISON(ZyanCompareBool, ZyanBool) + +/** + * Defines a default comparison function for 8-bit numeric values. + * + * @param left A pointer to the first value. + * @param right A pointer to the second value. + * + * @return Returns `0` if the `left` value equals the `right` one, `-1` if the `left` value is + * less than the `right` one, or `1` if the `left` value is greater than the `right` one. + */ +ZYAN_INLINE ZYAN_DECLARE_COMPARISON(ZyanCompareNumeric8, ZyanU8) + +/** + * Defines a default comparison function for 16-bit numeric values. + * + * @param left A pointer to the first value. + * @param right A pointer to the second value. + * + * @return Returns `0` if the `left` value equals the `right` one, `-1` if the `left` value is + * less than the `right` one, or `1` if the `left` value is greater than the `right` one. + */ +ZYAN_INLINE ZYAN_DECLARE_COMPARISON(ZyanCompareNumeric16, ZyanU16) + +/** + * Defines a default comparison function for 32-bit numeric values. + * + * @param left A pointer to the first value. + * @param right A pointer to the second value. + * + * @return Returns `0` if the `left` value equals the `right` one, `-1` if the `left` value is + * less than the `right` one, or `1` if the `left` value is greater than the `right` one. + */ +ZYAN_INLINE ZYAN_DECLARE_COMPARISON(ZyanCompareNumeric32, ZyanU32) + +/** + * Defines a default comparison function for 64-bit numeric values. + * + * @param left A pointer to the first value. + * @param right A pointer to the second value. + * + * @return Returns `0` if the `left` value equals the `right` one, `-1` if the `left` value is + * less than the `right` one, or `1` if the `left` value is greater than the `right` one. + */ +ZYAN_INLINE ZYAN_DECLARE_COMPARISON(ZyanCompareNumeric64, ZyanU64) + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZYCORE_COMPARISON_H */ diff --git a/zycore/include/Zycore/Defines.h b/zycore/include/Zycore/Defines.h new file mode 100644 index 0000000..d823d34 --- /dev/null +++ b/zycore/include/Zycore/Defines.h @@ -0,0 +1,521 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Florian Bernd, Joel Hoener + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * General helper and platform detection macros. + */ + +#ifndef ZYCORE_DEFINES_H +#define ZYCORE_DEFINES_H + +/* ============================================================================================== */ +/* Meta macros */ +/* ============================================================================================== */ + +/** + * Concatenates two values using the stringify operator (`##`). + * + * @param x The first value. + * @param y The second value. + * + * @return The combined string of the given values. + */ +#define ZYAN_MACRO_CONCAT(x, y) x ## y + +/** + * Concatenates two values using the stringify operator (`##`) and expands the value to + * be used in another macro. + * + * @param x The first value. + * @param y The second value. + * + * @return The combined string of the given values. + */ +#define ZYAN_MACRO_CONCAT_EXPAND(x, y) ZYAN_MACRO_CONCAT(x, y) + +/* ============================================================================================== */ +/* Compiler detection */ +/* ============================================================================================== */ + +#if defined(__clang__) +# define ZYAN_CLANG +# define ZYAN_GNUC +#elif defined(__ICC) || defined(__INTEL_COMPILER) +# define ZYAN_ICC +#elif defined(__GNUC__) || defined(__GNUG__) +# define ZYAN_GCC +# define ZYAN_GNUC +#elif defined(_MSC_VER) +# define ZYAN_MSVC +#elif defined(__BORLANDC__) +# define ZYAN_BORLAND +#else +# define ZYAN_UNKNOWN_COMPILER +#endif + +/* ============================================================================================== */ +/* Platform detection */ +/* ============================================================================================== */ + +#if defined(_WIN32) +# define ZYAN_WINDOWS +#elif defined(__EMSCRIPTEN__) +# define ZYAN_EMSCRIPTEN +#elif defined(__wasi__) || defined(__WASI__) +// via: https://reviews.llvm.org/D57155 +# define ZYAN_WASI +#elif defined(__APPLE__) +# define ZYAN_APPLE +# define ZYAN_POSIX +#elif defined(__linux) +# define ZYAN_LINUX +# define ZYAN_POSIX +#elif defined(__FreeBSD__) +# define ZYAN_FREEBSD +# define ZYAN_POSIX +#elif defined(sun) || defined(__sun) +# define ZYAN_SOLARIS +# define ZYAN_POSIX +#elif defined(__unix) +# define ZYAN_UNIX +# define ZYAN_POSIX +#elif defined(__posix) +# define ZYAN_POSIX +#else +# define ZYAN_UNKNOWN_PLATFORM +#endif + +/* ============================================================================================== */ +/* Kernel mode detection */ +/* ============================================================================================== */ + +#if (defined(ZYAN_WINDOWS) && defined(_KERNEL_MODE)) || \ + (defined(ZYAN_APPLE) && defined(KERNEL)) || \ + (defined(ZYAN_LINUX) && defined(__KERNEL__)) || \ + (defined(__FreeBSD_kernel__)) +# define ZYAN_KERNEL +#else +# define ZYAN_USER +#endif + +/* ============================================================================================== */ +/* Architecture detection */ +/* ============================================================================================== */ + +#if defined(_M_AMD64) || defined(__x86_64__) +# define ZYAN_X64 +#elif defined(_M_IX86) || defined(__i386__) +# define ZYAN_X86 +#elif defined(_M_ARM64) || defined(__aarch64__) +# define ZYAN_AARCH64 +#elif defined(_M_ARM) || defined(_M_ARMT) || defined(__arm__) || defined(__thumb__) +# define ZYAN_ARM +#elif defined(__EMSCRIPTEN__) || defined(__wasm__) || defined(__WASM__) +# define ZYAN_WASM +#else +# error "Unsupported architecture detected" +#endif + +/* ============================================================================================== */ +/* Debug/Release detection */ +/* ============================================================================================== */ + +#if defined(ZYAN_MSVC) || defined(ZYAN_BORLAND) +# ifdef _DEBUG +# define ZYAN_DEBUG +# else +# define ZYAN_RELEASE +# endif +#elif defined(ZYAN_GNUC) || defined(ZYAN_ICC) +# ifdef NDEBUG +# define ZYAN_RELEASE +# else +# define ZYAN_DEBUG +# endif +#else +# define ZYAN_RELEASE +#endif + +/* ============================================================================================== */ +/* Deprecation hint */ +/* ============================================================================================== */ + +#if defined(ZYAN_GCC) || defined(ZYAN_CLANG) +# define ZYAN_DEPRECATED __attribute__((__deprecated__)) +#elif defined(ZYAN_MSVC) +# define ZYAN_DEPRECATED __declspec(deprecated) +#else +# define ZYAN_DEPRECATED +#endif + +/* ============================================================================================== */ +/* Generic DLL import/export helpers */ +/* ============================================================================================== */ + +#if defined(ZYAN_MSVC) +# define ZYAN_DLLEXPORT __declspec(dllexport) +# define ZYAN_DLLIMPORT __declspec(dllimport) +#else +# define ZYAN_DLLEXPORT +# define ZYAN_DLLIMPORT +#endif + +/* ============================================================================================== */ +/* Zycore dll{export,import} */ +/* ============================================================================================== */ + +// This is a cut-down version of what CMake's `GenerateExportHeader` would usually generate. To +// simplify builds without CMake, we define these things manually instead of relying on CMake +// to generate the header. +// +// For static builds, our CMakeList will define `ZYCORE_STATIC_BUILD`. For shared library builds, +// our CMake will define `ZYCORE_SHOULD_EXPORT` depending on whether the target is being imported or +// exported. If CMake isn't used, users can manually define these to fit their use-case. + +// Backward compatibility: CMake would previously generate these variables names. However, because +// they have pretty cryptic names, we renamed them when we got rid of `GenerateExportHeader`. For +// backward compatibility for users that don't use CMake and previously manually defined these, we +// translate the old defines here and print a warning. +#if defined(ZYCORE_STATIC_DEFINE) +# pragma message("ZYCORE_STATIC_DEFINE was renamed to ZYCORE_STATIC_BUILD.") +# define ZYCORE_STATIC_BUILD +#endif +#if defined(Zycore_EXPORTS) +# pragma message("Zycore_EXPORTS was renamed to ZYCORE_SHOULD_EXPORT.") +# define ZYCORE_SHOULD_EXPORT +#endif + +/** + * Symbol is exported in shared library builds. + */ +#if defined(ZYCORE_STATIC_BUILD) +# define ZYCORE_EXPORT +#else +# if defined(ZYCORE_SHOULD_EXPORT) +# define ZYCORE_EXPORT ZYAN_DLLEXPORT +# else +# define ZYCORE_EXPORT ZYAN_DLLIMPORT +# endif +#endif + +/** + * Symbol is not exported and for internal use only. + */ +#define ZYCORE_NO_EXPORT + +/* ============================================================================================== */ +/* Misc compatibility macros */ +/* ============================================================================================== */ + +#if defined(ZYAN_CLANG) +# define ZYAN_NO_SANITIZE(what) __attribute__((no_sanitize(what))) +#else +# define ZYAN_NO_SANITIZE(what) +#endif + +#if defined(ZYAN_MSVC) || defined(ZYAN_BORLAND) +# define ZYAN_INLINE __inline +#else +# define ZYAN_INLINE static inline +#endif + +#if defined(ZYAN_MSVC) +# define ZYAN_NOINLINE __declspec(noinline) +#elif defined(ZYAN_GCC) || defined(ZYAN_CLANG) +# define ZYAN_NOINLINE __attribute__((noinline)) +#else +# define ZYAN_NOINLINE +#endif + +/* ============================================================================================== */ +/* Debugging and optimization macros */ +/* ============================================================================================== */ + +/** + * Runtime debug assertion. + */ +#if defined(ZYAN_NO_LIBC) +# define ZYAN_ASSERT(condition) (void)(condition) +#elif defined(ZYAN_WINDOWS) && defined(ZYAN_KERNEL) +# include +# define ZYAN_ASSERT(condition) NT_ASSERT(condition) +#else +# include +# define ZYAN_ASSERT(condition) assert(condition) +#endif + +/** + * Compiler-time assertion. + */ +#if __STDC_VERSION__ >= 201112L && !defined(__cplusplus) +# define ZYAN_STATIC_ASSERT(x) _Static_assert(x, #x) +#elif (defined(__cplusplus) && __cplusplus >= 201103L) || \ + (defined(__cplusplus) && defined (_MSC_VER) && (_MSC_VER >= 1600)) || \ + (defined (_MSC_VER) && (_MSC_VER >= 1800)) +# define ZYAN_STATIC_ASSERT(x) static_assert(x, #x) +#else +# define ZYAN_STATIC_ASSERT(x) \ + typedef int ZYAN_MACRO_CONCAT_EXPAND(ZYAN_SASSERT_, __COUNTER__) [(x) ? 1 : -1] +#endif + +/** + * Marks the current code path as unreachable. + */ +#if defined(ZYAN_RELEASE) +# if defined(ZYAN_CLANG) // GCC eagerly evals && RHS, we have to use nested ifs. +# if __has_builtin(__builtin_unreachable) +# define ZYAN_UNREACHABLE __builtin_unreachable() +# else +# define ZYAN_UNREACHABLE for(;;) +# endif +# elif defined(ZYAN_GCC) && ((__GNUC__ == 4 && __GNUC_MINOR__ > 4) || __GNUC__ > 4) +# define ZYAN_UNREACHABLE __builtin_unreachable() +# elif defined(ZYAN_ICC) +# ifdef ZYAN_WINDOWS +# include // "missing return statement" workaround +# define ZYAN_UNREACHABLE __assume(0); (void)abort() +# else +# define ZYAN_UNREACHABLE __builtin_unreachable() +# endif +# elif defined(ZYAN_MSVC) +# define ZYAN_UNREACHABLE __assume(0) +# else +# define ZYAN_UNREACHABLE for(;;) +# endif +#elif defined(ZYAN_NO_LIBC) +# define ZYAN_UNREACHABLE for(;;) +#elif defined(ZYAN_WINDOWS) && defined(ZYAN_KERNEL) +# define ZYAN_UNREACHABLE { __fastfail(0); for(;;){} } +#else +# include +# define ZYAN_UNREACHABLE { assert(0); abort(); } +#endif + +/* ============================================================================================== */ +/* Utils */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* General purpose */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Marks the specified parameter as unused. + * + * @param x The name of the unused parameter. + */ +#define ZYAN_UNUSED(x) (void)(x) + +/** + * Intentional fallthrough. + */ +#if defined(ZYAN_GCC) && __GNUC__ >= 7 +# define ZYAN_FALLTHROUGH __attribute__((__fallthrough__)) +#else +# define ZYAN_FALLTHROUGH +#endif + +/** + * Declares a bitfield. + * + * @param x The size (in bits) of the bitfield. + */ +#define ZYAN_BITFIELD(x) : x + +/** + * Marks functions that require libc (cannot be used with `ZYAN_NO_LIBC`). + */ +#define ZYAN_REQUIRES_LIBC + +/** + * Decorator for `printf`-style functions. + * + * @param format_index The 1-based index of the format string parameter. + * @param first_to_check The 1-based index of the format arguments parameter. + */ +#if defined(__RESHARPER__) +# define ZYAN_PRINTF_ATTR(format_index, first_to_check) \ + [[gnu::format(printf, format_index, first_to_check)]] +#elif defined(ZYAN_GCC) +# define ZYAN_PRINTF_ATTR(format_index, first_to_check) \ + __attribute__((format(printf, format_index, first_to_check))) +#else +# define ZYAN_PRINTF_ATTR(format_index, first_to_check) +#endif + +/** + * Decorator for `wprintf`-style functions. + * + * @param format_index The 1-based index of the format string parameter. + * @param first_to_check The 1-based index of the format arguments parameter. + */ +#if defined(__RESHARPER__) +# define ZYAN_WPRINTF_ATTR(format_index, first_to_check) \ + [[rscpp::format(wprintf, format_index, first_to_check)]] +#else +# define ZYAN_WPRINTF_ATTR(format_index, first_to_check) +#endif + +/* ---------------------------------------------------------------------------------------------- */ +/* Arrays */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Returns the length (number of elements) of an array. + * + * @param a The name of the array. + * + * @return The number of elements of the given array. + */ +#define ZYAN_ARRAY_LENGTH(a) (sizeof(a) / sizeof((a)[0])) + +/* ---------------------------------------------------------------------------------------------- */ +/* Arithmetic */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Returns the smaller value of `a` or `b`. + * + * @param a The first value. + * @param b The second value. + * + * @return The smaller value of `a` or `b`. + */ +#define ZYAN_MIN(a, b) (((a) < (b)) ? (a) : (b)) + +/** + * Returns the bigger value of `a` or `b`. + * + * @param a The first value. + * @param b The second value. + * + * @return The bigger value of `a` or `b`. + */ +#define ZYAN_MAX(a, b) (((a) > (b)) ? (a) : (b)) + +/** + * Returns the absolute value of `a`. + * + * @param a The value. + * + * @return The absolute value of `a`. + */ +#define ZYAN_ABS(a) (((a) < 0) ? -(a) : (a)) + +/** + * Checks, if the given value is a power of 2. + * + * @param x The value. + * + * @return `ZYAN_TRUE`, if the given value is a power of 2 or `ZYAN_FALSE`, if not. + * + * Note that this macro always returns `ZYAN_TRUE` for `x == 0`. + */ +#define ZYAN_IS_POWER_OF_2(x) (((x) & ((x) - 1)) == 0) + +/** + * Checks, if the given value is properly aligned. + * + * Note that this macro only works for powers of 2. + */ +#define ZYAN_IS_ALIGNED_TO(x, align) (((x) & ((align) - 1)) == 0) + +/** + * Aligns the value to the nearest given alignment boundary (by rounding it up). + * + * @param x The value. + * @param align The desired alignment. + * + * @return The aligned value. + * + * Note that this macro only works for powers of 2. + */ +#define ZYAN_ALIGN_UP(x, align) (((x) + (align) - 1) & ~((align) - 1)) + +/** + * Aligns the value to the nearest given alignment boundary (by rounding it down). + * + * @param x The value. + * @param align The desired alignment. + * + * @return The aligned value. + * + * Note that this macro only works for powers of 2. + */ +#define ZYAN_ALIGN_DOWN(x, align) (((x) - 1) & ~((align) - 1)) + +/* ---------------------------------------------------------------------------------------------- */ +/* Bit operations */ +/* ---------------------------------------------------------------------------------------------- */ + +/* + * Checks, if the bit at index `b` is required to present the ordinal value `n`. + * + * @param n The ordinal value. + * @param b The bit index. + * + * @return `ZYAN_TRUE`, if the bit at index `b` is required to present the ordinal value `n` or + * `ZYAN_FALSE`, if not. + * + * Note that this macro always returns `ZYAN_FALSE` for `n == 0`. + */ +#define ZYAN_NEEDS_BIT(n, b) (((unsigned long)(n) >> (b)) > 0) + +/* + * Returns the number of bits required to represent the ordinal value `n`. + * + * @param n The ordinal value. + * + * @return The number of bits required to represent the ordinal value `n`. + * + * Note that this macro returns `0` for `n == 0`. + */ +#define ZYAN_BITS_TO_REPRESENT(n) \ + ( \ + ZYAN_NEEDS_BIT(n, 0) + ZYAN_NEEDS_BIT(n, 1) + \ + ZYAN_NEEDS_BIT(n, 2) + ZYAN_NEEDS_BIT(n, 3) + \ + ZYAN_NEEDS_BIT(n, 4) + ZYAN_NEEDS_BIT(n, 5) + \ + ZYAN_NEEDS_BIT(n, 6) + ZYAN_NEEDS_BIT(n, 7) + \ + ZYAN_NEEDS_BIT(n, 8) + ZYAN_NEEDS_BIT(n, 9) + \ + ZYAN_NEEDS_BIT(n, 10) + ZYAN_NEEDS_BIT(n, 11) + \ + ZYAN_NEEDS_BIT(n, 12) + ZYAN_NEEDS_BIT(n, 13) + \ + ZYAN_NEEDS_BIT(n, 14) + ZYAN_NEEDS_BIT(n, 15) + \ + ZYAN_NEEDS_BIT(n, 16) + ZYAN_NEEDS_BIT(n, 17) + \ + ZYAN_NEEDS_BIT(n, 18) + ZYAN_NEEDS_BIT(n, 19) + \ + ZYAN_NEEDS_BIT(n, 20) + ZYAN_NEEDS_BIT(n, 21) + \ + ZYAN_NEEDS_BIT(n, 22) + ZYAN_NEEDS_BIT(n, 23) + \ + ZYAN_NEEDS_BIT(n, 24) + ZYAN_NEEDS_BIT(n, 25) + \ + ZYAN_NEEDS_BIT(n, 26) + ZYAN_NEEDS_BIT(n, 27) + \ + ZYAN_NEEDS_BIT(n, 28) + ZYAN_NEEDS_BIT(n, 29) + \ + ZYAN_NEEDS_BIT(n, 30) + ZYAN_NEEDS_BIT(n, 31) \ + ) + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ + +#endif /* ZYCORE_DEFINES_H */ diff --git a/zycore/include/Zycore/Format.h b/zycore/include/Zycore/Format.h new file mode 100644 index 0000000..006ca31 --- /dev/null +++ b/zycore/include/Zycore/Format.h @@ -0,0 +1,285 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * Provides helper functions for performant number to string conversion. + */ + +#ifndef ZYCORE_FORMAT_H +#define ZYCORE_FORMAT_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Helpers */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Get the absolute value of a 64 bit int. + * + * @param x The value to process. + * @return The absolute, unsigned value. + * + * This gracefully deals with the special case of `x` being `INT_MAX`. + */ +ZYAN_INLINE ZyanU64 ZyanAbsI64(ZyanI64 x) +{ + // INT_MIN special case. Can't use the value directly because GCC thinks + // it's too big for an INT64 literal, however is perfectly happy to accept + // this expression. This is also hit INT64_MIN is defined in `stdint.h`. + if (x == (-0x7fffffffffffffff - 1)) + { + return 0x8000000000000000u; + } + + return (ZyanU64)(x < 0 ? -x : x); +} + +/* ---------------------------------------------------------------------------------------------- */ +/* Insertion */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Inserts formatted text in the destination string at the given `index`. + * + * @param string The destination string. + * @param index The insert index. + * @param format The format string. + * @param ... The format arguments. + * + * @return A zyan status code. + * + * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified + * `ZyanString` instance. + */ +ZYAN_PRINTF_ATTR(3, 4) +ZYCORE_EXPORT ZyanStatus ZyanStringInsertFormat(ZyanString* string, ZyanUSize index, + const char* format, ...); + +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Formats the given unsigned ordinal `value` to its decimal text-representation and + * inserts it to the `string`. + * + * @param string A pointer to the `ZyanString` instance. + * @param index The insert index. + * @param value The value. + * @param padding_length Padds the converted value with leading zeros, if the number of chars is + * less than the `padding_length`. + * + * @return A zyan status code. + * + * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified + * `ZyanString` instance. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringInsertDecU(ZyanString* string, ZyanUSize index, ZyanU64 value, + ZyanU8 padding_length); + +/** + * Formats the given signed ordinal `value` to its decimal text-representation and + * inserts it to the `string`. + * + * @param string A pointer to the `ZyanString` instance. + * @param index The insert index. + * @param value The value. + * @param padding_length Padds the converted value with leading zeros, if the number of chars is + * less than the `padding_length`. + * @param force_sign Set `ZYAN_TRUE`, to force printing of the `+` sign for positive numbers. + * @param prefix The string to use as prefix or `ZYAN_NULL`, if not needed. + * + * @return A zyan status code. + * + * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified + * `ZyanString` instance. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringInsertDecS(ZyanString* string, ZyanUSize index, ZyanI64 value, + ZyanU8 padding_length, ZyanBool force_sign, const ZyanString* prefix); + +/** + * Formats the given unsigned ordinal `value` to its hexadecimal text-representation and + * inserts it to the `string`. + * + * @param string A pointer to the `ZyanString` instance. + * @param index The insert index. + * @param value The value. + * @param padding_length Padds the converted value with leading zeros, if the number of chars is + * less than the `padding_length`. + * @param uppercase Set `ZYAN_TRUE` to use uppercase letters ('A'-'F') instead of lowercase + * ones ('a'-'f'). + * + * @return A zyan status code. + * + * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified + * `ZyanString` instance. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringInsertHexU(ZyanString* string, ZyanUSize index, ZyanU64 value, + ZyanU8 padding_length, ZyanBool uppercase); + +/** + * Formats the given signed ordinal `value` to its hexadecimal text-representation and + * inserts it to the `string`. + * + * @param string A pointer to the `ZyanString` instance. + * @param index The insert index. + * @param value The value. + * @param padding_length Padds the converted value with leading zeros, if the number of chars is + * less than the `padding_length`. + * @param uppercase Set `ZYAN_TRUE` to use uppercase letters ('A'-'F') instead of lowercase + * ones ('a'-'f'). + * @param force_sign Set `ZYAN_TRUE`, to force printing of the `+` sign for positive numbers. + * @param prefix The string to use as prefix or `ZYAN_NULL`, if not needed. + * + * @return A zyan status code. + * + * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified + * `ZyanString` instance. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringInsertHexS(ZyanString* string, ZyanUSize index, ZyanI64 value, + ZyanU8 padding_length, ZyanBool uppercase, ZyanBool force_sign, const ZyanString* prefix); + +/* ---------------------------------------------------------------------------------------------- */ +/* Appending */ +/* ---------------------------------------------------------------------------------------------- */ + +#ifndef ZYAN_NO_LIBC + +/** + * Appends formatted text to the destination string. + * + * @param string The destination string. + * @param format The format string. + * @param ... The format arguments. + * + * @return A zyan status code. + * + * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified + * `ZyanString` instance. + */ +ZYAN_PRINTF_ATTR(2, 3) +ZYCORE_EXPORT ZYAN_REQUIRES_LIBC ZyanStatus ZyanStringAppendFormat( + ZyanString* string, const char* format, ...); + +#endif // ZYAN_NO_LIBC + +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Formats the given unsigned ordinal `value` to its decimal text-representation and + * appends it to the `string`. + * + * @param string A pointer to the `ZyanString` instance. + * @param value The value. + * @param padding_length Padds the converted value with leading zeros, if the number of chars is + * less than the `padding_length`. + * + * @return A zyan status code. + * + * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified + * `ZyanString` instance. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringAppendDecU(ZyanString* string, ZyanU64 value, + ZyanU8 padding_length); + +/** + * Formats the given signed ordinal `value` to its decimal text-representation and + * appends it to the `string`. + * + * @param string A pointer to the `ZyanString` instance. + * @param value The value. + * @param padding_length Padds the converted value with leading zeros, if the number of chars is + * less than the `padding_length`. + * @param force_sign Set `ZYAN_TRUE`, to force printing of the `+` sign for positive numbers. + * @param prefix The string to use as prefix or `ZYAN_NULL`, if not needed. + * + * @return A zyan status code. + * + * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified + * `ZyanString` instance. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringAppendDecS(ZyanString* string, ZyanI64 value, + ZyanU8 padding_length, ZyanBool force_sign, const ZyanStringView* prefix); + +/** + * Formats the given unsigned ordinal `value` to its hexadecimal text-representation and + * appends it to the `string`. + * + * @param string A pointer to the `ZyanString` instance. + * @param value The value. + * @param padding_length Padds the converted value with leading zeros, if the number of chars is + * less than the `padding_length`. + * @param uppercase Set `ZYAN_TRUE` to use uppercase letters ('A'-'F') instead of lowercase + * ones ('a'-'f'). + * + * @return A zyan status code. + * + * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified + * `ZyanString` instance. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringAppendHexU(ZyanString* string, ZyanU64 value, + ZyanU8 padding_length, ZyanBool uppercase); + +/** + * Formats the given signed ordinal `value` to its hexadecimal text-representation and + * appends it to the `string`. + * + * @param string A pointer to the `ZyanString` instance. + * @param value The value. + * @param padding_length Padds the converted value with leading zeros, if the number of chars is + * less than the `padding_length`. + * @param uppercase Set `ZYAN_TRUE` to use uppercase letters ('A'-'F') instead of lowercase + * ones ('a'-'f'). + * @param force_sign Set `ZYAN_TRUE`, to force printing of the `+` sign for positive numbers. + * @param prefix The string to use as prefix or `ZYAN_NULL`, if not needed. + * + * @return A zyan status code. + * + * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified + * `ZyanString` instance. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringAppendHexS(ZyanString* string, ZyanI64 value, + ZyanU8 padding_length, ZyanBool uppercase, ZyanBool force_sign, const ZyanStringView* prefix); + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif // ZYCORE_FORMAT_H diff --git a/zycore/include/Zycore/Internal/AtomicGNU.h b/zycore/include/Zycore/Internal/AtomicGNU.h new file mode 100644 index 0000000..ca6b360 --- /dev/null +++ b/zycore/include/Zycore/Internal/AtomicGNU.h @@ -0,0 +1,117 @@ +/*************************************************************************************************** + + Zyan Core Library (Zyan-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +#ifndef ZYCORE_ATOMIC_GNU_H +#define ZYCORE_ATOMIC_GNU_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +/* ============================================================================================== */ +/* Functions */ +/* ============================================================================================== */ + +#if defined(ZYAN_CLANG) || defined(ZYAN_GCC) || defined(ZYAN_ICC) + +/* ---------------------------------------------------------------------------------------------- */ +/* Pointer sized */ +/* ---------------------------------------------------------------------------------------------- */ + +ZYAN_INLINE ZyanUPointer ZyanAtomicCompareExchange(ZyanAtomicPointer* destination, + ZyanUPointer comparand, ZyanUPointer value) +{ + return (ZyanUPointer)(__sync_val_compare_and_swap( + &destination->value, (void*)comparand, (void*)value, &destination->value)); +} + +ZYAN_INLINE ZyanUPointer ZyanAtomicIncrement(ZyanAtomicPointer* destination) +{ + return (ZyanUPointer)(__sync_fetch_and_add(&destination->value, (void*)1, + &destination->value)) + 1; +} + +ZYAN_INLINE ZyanUPointer ZyanAtomicDecrement(ZyanAtomicPointer* destination) +{ + return (ZyanUPointer)(__sync_sub_and_fetch(&destination->value, (void*)1, &destination->value)); +} + +/* ---------------------------------------------------------------------------------------------- */ +/* 32-bit */ +/* ---------------------------------------------------------------------------------------------- */ + +ZYAN_INLINE ZyanU32 ZyanAtomicCompareExchange32(ZyanAtomic32* destination, + ZyanU32 comparand, ZyanU32 value) +{ + return (ZyanU32)(__sync_val_compare_and_swap(&destination->value, comparand, value, + &destination->value)); +} + +ZYAN_INLINE ZyanU32 ZyanAtomicIncrement32(ZyanAtomic32* destination) +{ + return (ZyanU32)(__sync_fetch_and_add(&destination->value, 1, &destination->value)) + 1; +} + +ZYAN_INLINE ZyanU32 ZyanAtomicDecrement32(ZyanAtomic32* destination) +{ + return (ZyanU32)(__sync_sub_and_fetch(&destination->value, 1, &destination->value)); +} + +/* ---------------------------------------------------------------------------------------------- */ +/* 64-bit */ +/* ---------------------------------------------------------------------------------------------- */ + +ZYAN_INLINE ZyanU64 ZyanAtomicCompareExchange64(ZyanAtomic64* destination, + ZyanU64 comparand, ZyanU64 value) +{ + return (ZyanU64)(__sync_val_compare_and_swap(&destination->value, comparand, value, + &destination->value)); +} + +ZYAN_INLINE ZyanU64 ZyanAtomicIncrement64(ZyanAtomic64* destination) +{ + return (ZyanU64)(__sync_fetch_and_add(&destination->value, 1, &destination->value)) + 1; +} + +ZYAN_INLINE ZyanU64 ZyanAtomicDecrement64(ZyanAtomic64* destination) +{ + return (ZyanU64)(__sync_sub_and_fetch(&destination->value, 1, &destination->value)); +} + +/* ---------------------------------------------------------------------------------------------- */ + +#endif + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZYCORE_ATOMIC_GNU_H */ diff --git a/zycore/include/Zycore/Internal/AtomicMSVC.h b/zycore/include/Zycore/Internal/AtomicMSVC.h new file mode 100644 index 0000000..f4dc1e6 --- /dev/null +++ b/zycore/include/Zycore/Internal/AtomicMSVC.h @@ -0,0 +1,141 @@ +/*************************************************************************************************** + + Zyan Core Library (Zyan-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +#ifndef ZYCORE_ATOMIC_MSVC_H +#define ZYCORE_ATOMIC_MSVC_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include +#include + +/* ============================================================================================== */ +/* Functions */ +/* ============================================================================================== */ + +#if defined(ZYAN_MSVC) + +/* ---------------------------------------------------------------------------------------------- */ +/* Pointer sized */ +/* ---------------------------------------------------------------------------------------------- */ + +#if defined(ZYAN_X86) + +static ZYAN_INLINE ZyanUPointer ZyanAtomicCompareExchange(ZyanAtomicPointer* destination, + ZyanUPointer comparand, ZyanUPointer value) +{ + return (ZyanUPointer)ZyanAtomicCompareExchange32((ZyanAtomic32*)destination, comparand, value); +} + +static ZYAN_INLINE ZyanUPointer ZyanAtomicIncrement(ZyanAtomicPointer* destination) +{ + return (ZyanUPointer)ZyanAtomicIncrement32((ZyanAtomic32*)destination); +} + +static ZYAN_INLINE ZyanUPointer ZyanAtomicDecrement(ZyanAtomicPointer* destination) +{ + return (ZyanUPointer)ZyanAtomicDecrement32((ZyanAtomic32*)destination); +} + +#elif defined(ZYAN_X64) + +static ZYAN_INLINE ZyanUPointer ZyanAtomicCompareExchange(ZyanAtomicPointer* destination, + ZyanUPointer comparand, ZyanUPointer value) +{ + return (ZyanUPointer)ZyanAtomicCompareExchange64((ZyanAtomic64*)destination, comparand, value); +} + +static ZYAN_INLINE ZyanUPointer ZyanAtomicIncrement(ZyanAtomicPointer* destination) +{ + return (ZyanUPointer)ZyanAtomicIncrement64((ZyanAtomic64*)destination); +} + +static ZYAN_INLINE ZyanUPointer ZyanAtomicDecrement(ZyanAtomicPointer* destination) +{ + return (ZyanUPointer)ZyanAtomicDecrement64((ZyanAtomic64*)destination); +} + +#else +# error "Unsupported architecture detected" +#endif + +/* ---------------------------------------------------------------------------------------------- */ +/* 32-bit */ +/* ---------------------------------------------------------------------------------------------- */ + +static ZYAN_INLINE ZyanU32 ZyanAtomicCompareExchange32(ZyanAtomic32* destination, + ZyanU32 comparand, ZyanU32 value) +{ + return (ZyanU32)(_InterlockedCompareExchange((volatile LONG*)&(destination->value), + (LONG)value, (LONG)comparand)); +} + +static ZYAN_INLINE ZyanU32 ZyanAtomicIncrement32(ZyanAtomic32* destination) +{ + return (ZyanU32)(_InterlockedIncrement((volatile LONG*)&(destination->value))); +} + +static ZYAN_INLINE ZyanU32 ZyanAtomicDecrement32(ZyanAtomic32* destination) +{ + return (ZyanU32)(_InterlockedDecrement((volatile LONG*)&(destination->value))); +} + +/* ---------------------------------------------------------------------------------------------- */ +/* 64-bit */ +/* ---------------------------------------------------------------------------------------------- */ + +static ZYAN_INLINE ZyanU64 ZyanAtomicCompareExchange64(ZyanAtomic64* destination, + ZyanU64 comparand, ZyanU64 value) +{ + return (ZyanU64)(_InterlockedCompareExchange64((volatile LONG64*)&(destination->value), + (LONG64)value, (LONG64)comparand)); +} + +static ZYAN_INLINE ZyanU64 ZyanAtomicIncrement64(ZyanAtomic64* destination) +{ + return (ZyanU64)(_InterlockedIncrement64((volatile LONG64*)&(destination->value))); +} + +static ZYAN_INLINE ZyanU64 ZyanAtomicDecrement64(ZyanAtomic64* destination) +{ + return (ZyanU64)(_InterlockedDecrement64((volatile LONG64*)&(destination->value))); +} + +/* ---------------------------------------------------------------------------------------------- */ + +#endif + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZYCORE_ATOMIC_MSVC_H */ diff --git a/zycore/include/Zycore/LibC.h b/zycore/include/Zycore/LibC.h new file mode 100644 index 0000000..cb0b2f3 --- /dev/null +++ b/zycore/include/Zycore/LibC.h @@ -0,0 +1,511 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Florian Bernd, Joel Hoener + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * Provides a simple LibC abstraction and fallback routines. + */ + +#ifndef ZYCORE_LIBC_H +#define ZYCORE_LIBC_H + +#ifndef ZYAN_CUSTOM_LIBC + +// Include a custom LibC header and define `ZYAN_CUSTOM_LIBC` to provide your own LibC +// replacement functions + +#ifndef ZYAN_NO_LIBC + +/* ============================================================================================== */ +/* LibC is available */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* errno.h */ +/* ---------------------------------------------------------------------------------------------- */ + +#include + +#define ZYAN_ERRNO errno + +/* ---------------------------------------------------------------------------------------------- */ +/* stdarg.h */ +/* ---------------------------------------------------------------------------------------------- */ + +#include + +/** + * Defines the `ZyanVAList` datatype. + */ +typedef va_list ZyanVAList; + +#define ZYAN_VA_START va_start +#define ZYAN_VA_ARG va_arg +#define ZYAN_VA_END va_end +#define ZYAN_VA_COPY(dest, source) va_copy((dest), (source)) + +/* ---------------------------------------------------------------------------------------------- */ +/* stdio.h */ +/* ---------------------------------------------------------------------------------------------- */ + +#include + +#define ZYAN_FPUTS fputs +#define ZYAN_FPUTC fputc +#define ZYAN_FPRINTF fprintf +#define ZYAN_PRINTF printf +#define ZYAN_PUTC putc +#define ZYAN_PUTS puts +#define ZYAN_SCANF scanf +#define ZYAN_SSCANF sscanf +#define ZYAN_VSNPRINTF vsnprintf + +/** + * Defines the `ZyanFile` datatype. + */ +typedef FILE ZyanFile; + +#define ZYAN_STDIN stdin +#define ZYAN_STDOUT stdout +#define ZYAN_STDERR stderr + +/* ---------------------------------------------------------------------------------------------- */ +/* stdlib.h */ +/* ---------------------------------------------------------------------------------------------- */ + +#include +#define ZYAN_CALLOC calloc +#define ZYAN_FREE free +#define ZYAN_MALLOC malloc +#define ZYAN_REALLOC realloc + +/* ---------------------------------------------------------------------------------------------- */ +/* string.h */ +/* ---------------------------------------------------------------------------------------------- */ + +#include +#define ZYAN_MEMCHR memchr +#define ZYAN_MEMCMP memcmp +#define ZYAN_MEMCPY memcpy +#define ZYAN_MEMMOVE memmove +#define ZYAN_MEMSET memset +#define ZYAN_STRCAT strcat +#define ZYAN_STRCHR strchr +#define ZYAN_STRCMP strcmp +#define ZYAN_STRCOLL strcoll +#define ZYAN_STRCPY strcpy +#define ZYAN_STRCSPN strcspn +#define ZYAN_STRLEN strlen +#define ZYAN_STRNCAT strncat +#define ZYAN_STRNCMP strncmp +#define ZYAN_STRNCPY strncpy +#define ZYAN_STRPBRK strpbrk +#define ZYAN_STRRCHR strrchr +#define ZYAN_STRSPN strspn +#define ZYAN_STRSTR strstr +#define ZYAN_STRTOK strtok +#define ZYAN_STRXFRM strxfrm + +/* ---------------------------------------------------------------------------------------------- */ + +#else // if ZYAN_NO_LIBC + +/* ============================================================================================== */ +/* No LibC available, use our own functions */ +/* ============================================================================================== */ + +#include +#include + +/* + * These implementations are by no means optimized and will be outperformed by pretty much any + * libc implementation out there. We do not aim towards providing competetive implementations here, + * but towards providing a last resort fallback for environments without a working libc. + */ + +/* ---------------------------------------------------------------------------------------------- */ +/* stdarg.h */ +/* ---------------------------------------------------------------------------------------------- */ + +#if defined(ZYAN_MSVC) || defined(ZYAN_ICC) + +/** + * Defines the `ZyanVAList` datatype. + */ +typedef char* ZyanVAList; + +# define ZYAN_VA_START __crt_va_start +# define ZYAN_VA_ARG __crt_va_arg +# define ZYAN_VA_END __crt_va_end +# define ZYAN_VA_COPY(destination, source) ((destination) = (source)) + +#elif defined(ZYAN_GNUC) + +/** + * Defines the `ZyanVAList` datatype. + */ +typedef __builtin_va_list ZyanVAList; + +# define ZYAN_VA_START(v, l) __builtin_va_start(v, l) +# define ZYAN_VA_END(v) __builtin_va_end(v) +# define ZYAN_VA_ARG(v, l) __builtin_va_arg(v, l) +# define ZYAN_VA_COPY(d, s) __builtin_va_copy(d, s) + +#else +# error "Unsupported compiler for no-libc mode." +#endif + +/* ---------------------------------------------------------------------------------------------- */ +/* stdio.h */ +/* ---------------------------------------------------------------------------------------------- */ + +// ZYAN_INLINE int ZYAN_VSNPRINTF (char* const buffer, ZyanUSize const count, +// char const* const format, ZyanVAList args) +// { +// // We cant provide a fallback implementation for this function +// ZYAN_UNUSED(buffer); +// ZYAN_UNUSED(count); +// ZYAN_UNUSED(format); +// ZYAN_UNUSED(args); +// return ZYAN_NULL; +// } + +/* ---------------------------------------------------------------------------------------------- */ +/* stdlib.h */ +/* ---------------------------------------------------------------------------------------------- */ + +// ZYAN_INLINE void* ZYAN_CALLOC(ZyanUSize nitems, ZyanUSize size) +// { +// // We cant provide a fallback implementation for this function +// ZYAN_UNUSED(nitems); +// ZYAN_UNUSED(size); +// return ZYAN_NULL; +// } +// +// ZYAN_INLINE void ZYAN_FREE(void *p) +// { +// // We cant provide a fallback implementation for this function +// ZYAN_UNUSED(p); +// } +// +// ZYAN_INLINE void* ZYAN_MALLOC(ZyanUSize n) +// { +// // We cant provide a fallback implementation for this function +// ZYAN_UNUSED(n); +// return ZYAN_NULL; +// } +// +// ZYAN_INLINE void* ZYAN_REALLOC(void* p, ZyanUSize n) +// { +// // We cant provide a fallback implementation for this function +// ZYAN_UNUSED(p); +// ZYAN_UNUSED(n); +// return ZYAN_NULL; +// } + +/* ---------------------------------------------------------------------------------------------- */ +/* string.h */ +/* ---------------------------------------------------------------------------------------------- */ + +ZYAN_INLINE void* ZYAN_MEMCHR(const void* str, int c, ZyanUSize n) +{ + const ZyanU8* p = (ZyanU8*)str; + while (n--) + { + if (*p != (ZyanU8)c) + { + p++; + } else + { + return (void*)p; + } + } + return 0; +} + +ZYAN_INLINE int ZYAN_MEMCMP(const void* s1, const void* s2, ZyanUSize n) +{ + const ZyanU8* p1 = s1, *p2 = s2; + while (n--) + { + if (*p1 != *p2) + { + return *p1 - *p2; + } + p1++, p2++; + } + return 0; +} + +ZYAN_INLINE void* ZYAN_MEMCPY(void* dst, const void* src, ZyanUSize n) +{ + volatile ZyanU8* dp = dst; + const ZyanU8* sp = src; + while (n--) + { + *dp++ = *sp++; + } + return dst; +} + +ZYAN_INLINE void* ZYAN_MEMMOVE(void* dst, const void* src, ZyanUSize n) +{ + volatile ZyanU8* pd = dst; + const ZyanU8* ps = src; + if (ps < pd) + { + for (pd += n, ps += n; n--;) + { + *--pd = *--ps; + } + } else + { + while (n--) + { + *pd++ = *ps++; + } + } + return dst; +} + +ZYAN_INLINE void* ZYAN_MEMSET(void* dst, int val, ZyanUSize n) +{ + volatile ZyanU8* p = dst; + while (n--) + { + *p++ = (unsigned char)val; + } + return dst; +} + +ZYAN_INLINE char* ZYAN_STRCAT(char* dest, const char* src) +{ + char* ret = dest; + while (*dest) + { + dest++; + } + while ((*dest++ = *src++)); + return ret; +} + +ZYAN_INLINE char* ZYAN_STRCHR(const char* s, int c) +{ + while (*s != (char)c) + { + if (!*s++) + { + return 0; + } + } + return (char*)s; +} + +ZYAN_INLINE int ZYAN_STRCMP(const char* s1, const char* s2) +{ + while (*s1 && (*s1 == *s2)) + { + s1++, s2++; + } + return *(const ZyanU8*)s1 - *(const ZyanU8*)s2; +} + +ZYAN_INLINE int ZYAN_STRCOLL(const char *s1, const char *s2) +{ + // TODO: Implement + + ZYAN_UNUSED(s1); + ZYAN_UNUSED(s2); + + return 0; +} + +ZYAN_INLINE char* ZYAN_STRCPY(char* dest, const char* src) +{ + char* ret = dest; + while ((*dest++ = *src++)); + return ret; +} + +ZYAN_INLINE ZyanUSize ZYAN_STRCSPN(const char *s1, const char *s2) +{ + ZyanUSize ret = 0; + while (*s1) + { + if (ZYAN_STRCHR(s2, *s1)) + { + return ret; + } + s1++, ret++; + } + return ret; +} + +ZYAN_INLINE ZyanUSize ZYAN_STRLEN(const char* str) +{ + const char* p = str; + while (*str) + { + ++str; + } + return str - p; +} + +ZYAN_INLINE char* ZYAN_STRNCAT(char* dest, const char* src, ZyanUSize n) +{ + char* ret = dest; + while (*dest) + { + dest++; + } + while (n--) + { + if (!(*dest++ = *src++)) + { + return ret; + } + } + *dest = 0; + return ret; +} + +ZYAN_INLINE int ZYAN_STRNCMP(const char* s1, const char* s2, ZyanUSize n) +{ + while (n--) + { + if (*s1++ != *s2++) + { + return *(unsigned char*)(s1 - 1) - *(unsigned char*)(s2 - 1); + } + } + return 0; +} + +ZYAN_INLINE char* ZYAN_STRNCPY(char* dest, const char* src, ZyanUSize n) +{ + char* ret = dest; + do + { + if (!n--) + { + return ret; + } + } while ((*dest++ = *src++)); + while (n--) + { + *dest++ = 0; + } + return ret; +} + +ZYAN_INLINE char* ZYAN_STRPBRK(const char* s1, const char* s2) +{ + while (*s1) + { + if(ZYAN_STRCHR(s2, *s1++)) + { + return (char*)--s1; + } + } + return 0; +} + +ZYAN_INLINE char* ZYAN_STRRCHR(const char* s, int c) +{ + char* ret = 0; + do + { + if (*s == (char)c) + { + ret = (char*)s; + } + } while (*s++); + return ret; +} + +ZYAN_INLINE ZyanUSize ZYAN_STRSPN(const char* s1, const char* s2) +{ + ZyanUSize ret = 0; + while (*s1 && ZYAN_STRCHR(s2, *s1++)) + { + ret++; + } + return ret; +} + +ZYAN_INLINE char* ZYAN_STRSTR(const char* s1, const char* s2) +{ + const ZyanUSize n = ZYAN_STRLEN(s2); + while (*s1) + { + if (!ZYAN_MEMCMP(s1++, s2, n)) + { + return (char*)(s1 - 1); + } + } + return 0; +} + +ZYAN_INLINE char* ZYAN_STRTOK(char* str, const char* delim) +{ + static char* p = 0; + if (str) + { + p = str; + } else + if (!p) + { + return 0; + } + str = p + ZYAN_STRSPN(p, delim); + p = str + ZYAN_STRCSPN(str, delim); + if (p == str) + { + return p = 0; + } + p = *p ? *p = 0, p + 1 : 0; + return str; +} + +ZYAN_INLINE ZyanUSize ZYAN_STRXFRM(char* dest, const char* src, ZyanUSize n) +{ + const ZyanUSize n2 = ZYAN_STRLEN(src); + if (n > n2) + { + ZYAN_STRCPY(dest, src); + } + return n2; +} + +/* ---------------------------------------------------------------------------------------------- */ + +#endif + +#endif + +/* ============================================================================================== */ + +#endif /* ZYCORE_LIBC_H */ diff --git a/zycore/include/Zycore/List.h b/zycore/include/Zycore/List.h new file mode 100644 index 0000000..86244b8 --- /dev/null +++ b/zycore/include/Zycore/List.h @@ -0,0 +1,573 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * Implements a doubly linked list. + */ + +#ifndef ZYCORE_LIST_H +#define ZYCORE_LIST_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ============================================================================================== */ +/* Enums and types */ +/* ============================================================================================== */ + +/** + * Defines the `ZyanListNode` struct. + * + * All fields in this struct should be considered as "private". Any changes may lead to unexpected + * behavior. + */ +typedef struct ZyanListNode_ +{ + /** + * A pointer to the previous list node. + */ + struct ZyanListNode_* prev; + /** + * A pointer to the next list node. + */ + struct ZyanListNode_* next; +} ZyanListNode; + +/** + * Defines the `ZyanList` struct. + * + * All fields in this struct should be considered as "private". Any changes may lead to unexpected + * behavior. + */ +typedef struct ZyanList_ +{ + /** + * The memory allocator. + */ + ZyanAllocator* allocator; + /** + * The current number of elements in the list. + */ + ZyanUSize size; + /** + * The size of a single element in bytes. + */ + ZyanUSize element_size; + /** + * The element destructor callback. + */ + ZyanMemberProcedure destructor; + /** + * The head node. + */ + ZyanListNode* head; + /** + * The tail node. + */ + ZyanListNode* tail; + /** + * The data buffer. + * + * Only used for instances created by `ZyanListInitCustomBuffer`. + */ + void* buffer; + /** + * The data buffer capacity (number of bytes). + * + * Only used for instances created by `ZyanListInitCustomBuffer`. + */ + ZyanUSize capacity; + /** + * The first unused node. + * + * When removing a node, the first-unused value is updated to point at the removed node and the + * next node of the removed node will be updated to point at the old first-unused node. + * + * When appending the memory of the first unused-node is recycled to store the new node. The + * value of the first-unused node is then updated to point at the reused nodes next node. + * + * If the first-unused value is `ZYAN_NULL`, any new node will be "allocated" behind the tail + * node (if there is enough space left in the fixed size buffer). + * + * Only used for instances created by `ZyanListInitCustomBuffer`. + */ + ZyanListNode* first_unused; +} ZyanList; + +/* ============================================================================================== */ +/* Macros */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* General */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines an uninitialized `ZyanList` instance. + */ +#define ZYAN_LIST_INITIALIZER \ + { \ + /* allocator */ ZYAN_NULL, \ + /* size */ 0, \ + /* element_size */ 0, \ + /* head */ ZYAN_NULL, \ + /* destructor */ ZYAN_NULL, \ + /* tail */ ZYAN_NULL, \ + /* buffer */ ZYAN_NULL, \ + /* capacity */ 0, \ + /* first_unused */ ZYAN_NULL \ + } + +/* ---------------------------------------------------------------------------------------------- */ +/* Helper macros */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Returns the data value of the given `node`. + * + * @param type The desired value type. + * @param node A pointer to the `ZyanListNode` struct. + * + * @result The data value of the given `node`. + * + * Note that this function is unsafe and might dereference a null-pointer. + */ +#ifdef __cplusplus +#define ZYAN_LIST_GET(type, node) \ + (*reinterpret_cast(ZyanListGetNodeData(node))) +#else +#define ZYAN_LIST_GET(type, node) \ + (*(const type*)ZyanListGetNodeData(node)) +#endif + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Constructor and destructor */ +/* ---------------------------------------------------------------------------------------------- */ + +#ifndef ZYAN_NO_LIBC + +/** + * Initializes the given `ZyanList` instance. + * + * @param list A pointer to the `ZyanList` instance. + * @param element_size The size of a single element in bytes. + * @param destructor A destructor callback that is invoked every time an item is deleted, or + * `ZYAN_NULL` if not needed. + * + * @return A zyan status code. + * + * The memory for the list elements is dynamically allocated by the default allocator. + * + * Finalization with `ZyanListDestroy` is required for all instances created by this function. + */ +ZYCORE_EXPORT ZYAN_REQUIRES_LIBC ZyanStatus ZyanListInit(ZyanList* list, ZyanUSize element_size, + ZyanMemberProcedure destructor); + +#endif // ZYAN_NO_LIBC + +/** + * Initializes the given `ZyanList` instance and sets a custom `allocator`. + * + * @param list A pointer to the `ZyanList` instance. + * @param element_size The size of a single element in bytes. + * @param destructor A destructor callback that is invoked every time an item is deleted, or + * `ZYAN_NULL` if not needed. + * @param allocator A pointer to a `ZyanAllocator` instance. + * + * @return A zyan status code. + * + * Finalization with `ZyanListDestroy` is required for all instances created by this function. + */ +ZYCORE_EXPORT ZyanStatus ZyanListInitEx(ZyanList* list, ZyanUSize element_size, + ZyanMemberProcedure destructor, ZyanAllocator* allocator); + +/** + * Initializes the given `ZyanList` instance and configures it to use a custom user + * defined buffer with a fixed size. + * + * @param list A pointer to the `ZyanList` instance. + * @param element_size The size of a single element in bytes. + * @param destructor A destructor callback that is invoked every time an item is deleted, or + * `ZYAN_NULL` if not needed. + * @param buffer A pointer to the buffer that is used as storage for the elements. + * @param capacity The maximum capacity (number of bytes) of the buffer including the + * space required for the list-nodes. + * + * @return A zyan status code. + * + * The buffer capacity required to store `n` elements of type `T` is be calculated by: + * `size = n * sizeof(ZyanListNode) + n * sizeof(T)` + * + * Finalization is not required for instances created by this function. + */ +ZYCORE_EXPORT ZyanStatus ZyanListInitCustomBuffer(ZyanList* list, ZyanUSize element_size, + ZyanMemberProcedure destructor, void* buffer, ZyanUSize capacity); + +/** + * Destroys the given `ZyanList` instance. + * + * @param list A pointer to the `ZyanList` instance. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanListDestroy(ZyanList* list); + +/* ---------------------------------------------------------------------------------------------- */ +/* Duplication */ +/* ---------------------------------------------------------------------------------------------- */ + +#ifndef ZYAN_NO_LIBC + +/** + * Initializes a new `ZyanList` instance by duplicating an existing list. + * + * @param destination A pointer to the (uninitialized) destination `ZyanList` instance. + * @param source A pointer to the source list. + * + * @return A zyan status code. + * + * The memory for the list is dynamically allocated by the default allocator. + * + * Finalization with `ZyanListDestroy` is required for all instances created by this function. + */ +ZYCORE_EXPORT ZYAN_REQUIRES_LIBC ZyanStatus ZyanListDuplicate(ZyanList* destination, + const ZyanList* source); + +#endif // ZYAN_NO_LIBC + +/** + * Initializes a new `ZyanList` instance by duplicating an existing list and sets a + * custom `allocator`. + * + * @param destination A pointer to the (uninitialized) destination `ZyanList` instance. + * @param source A pointer to the source list. + * @param allocator A pointer to a `ZyanAllocator` instance. + * + * @return A zyan status code. + + * Finalization with `ZyanListDestroy` is required for all instances created by this function. + */ +ZYCORE_EXPORT ZyanStatus ZyanListDuplicateEx(ZyanList* destination, const ZyanList* source, + ZyanAllocator* allocator); + +/** + * Initializes a new `ZyanList` instance by duplicating an existing list and + * configures it to use a custom user defined buffer with a fixed size. + * + * @param destination A pointer to the (uninitialized) destination `ZyanList` instance. + * @param source A pointer to the source list. + * @param buffer A pointer to the buffer that is used as storage for the elements. + * @param capacity The maximum capacity (number of bytes) of the buffer including the + * space required for the list-nodes. + + * This function will fail, if the capacity of the buffer is not sufficient + * to store all elements of the source list. + * + * @return A zyan status code. + * + * The buffer capacity required to store `n` elements of type `T` is be calculated by: + * `size = n * sizeof(ZyanListNode) + n * sizeof(T)` + * + * Finalization is not required for instances created by this function. + */ +ZYCORE_EXPORT ZyanStatus ZyanListDuplicateCustomBuffer(ZyanList* destination, + const ZyanList* source, void* buffer, ZyanUSize capacity); + +/* ---------------------------------------------------------------------------------------------- */ +/* Item access */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Returns a pointer to the first `ZyanListNode` struct of the given list. + * + * @param list A pointer to the `ZyanList` instance. + * @param node Receives a pointer to the first `ZyanListNode` struct of the list. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanListGetHeadNode(const ZyanList* list, const ZyanListNode** node); + +/** + * Returns a pointer to the last `ZyanListNode` struct of the given list. + * + * @param list A pointer to the `ZyanList` instance. + * @param node Receives a pointer to the last `ZyanListNode` struct of the list. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanListGetTailNode(const ZyanList* list, const ZyanListNode** node); + +/** + * Receives a pointer to the previous `ZyanListNode` struct linked to the passed one. + * + * @param node Receives a pointer to the previous `ZyanListNode` struct linked to the passed + * one. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanListGetPrevNode(const ZyanListNode** node); + +/** + * Receives a pointer to the next `ZyanListNode` struct linked to the passed one. + * + * @param node Receives a pointer to the next `ZyanListNode` struct linked to the passed one. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanListGetNextNode(const ZyanListNode** node); + +/** + * Returns a constant pointer to the data of the given `node`. + * + * @param node A pointer to the `ZyanListNode` struct. + * + * @return A constant pointer to the the data of the given `node` or `ZYAN_NULL`, if an error + * occured. + * + * Take a look at `ZyanListGetNodeDataEx`, if you need a function that returns a zyan status code. + */ +ZYCORE_EXPORT const void* ZyanListGetNodeData(const ZyanListNode* node); + +/** + * Returns a constant pointer to the data of the given `node`.. + * + * @param node A pointer to the `ZyanListNode` struct. + * @param value Receives a constant pointer to the data of the given `node`. + * + * Take a look at `ZyanListGetNodeData`, if you need a function that directly returns a pointer. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanListGetNodeDataEx(const ZyanListNode* node, const void** value); + +/** + * Returns a mutable pointer to the data of the given `node`. + * + * @param node A pointer to the `ZyanListNode` struct. + * + * @return A mutable pointer to the the data of the given `node` or `ZYAN_NULL`, if an error + * occured. + * + * Take a look at `ZyanListGetPointerMutableEx` instead, if you need a function that returns a + * zyan status code. + */ +ZYCORE_EXPORT void* ZyanListGetNodeDataMutable(const ZyanListNode* node); + +/** + * Returns a mutable pointer to the data of the given `node`.. + * + * @param node A pointer to the `ZyanListNode` struct. + * @param value Receives a mutable pointer to the data of the given `node`. + * + * Take a look at `ZyanListGetNodeDataMutable`, if you need a function that directly returns a + * pointer. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanListGetNodeDataMutableEx(const ZyanListNode* node, void** value); + +/** + * Assigns a new data value to the given `node`. + * + * @param list A pointer to the `ZyanList` instance. + * @param node A pointer to the `ZyanListNode` struct. + * @param value The value to assign. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanListSetNodeData(const ZyanList* list, const ZyanListNode* node, + const void* value); + +/* ---------------------------------------------------------------------------------------------- */ +/* Insertion */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Adds a new `item` to the end of the list. + * + * @param list A pointer to the `ZyanList` instance. + * @param item A pointer to the item to add. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanListPushBack(ZyanList* list, const void* item); + +/** + * Adds a new `item` to the beginning of the list. + * + * @param list A pointer to the `ZyanList` instance. + * @param item A pointer to the item to add. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanListPushFront(ZyanList* list, const void* item); + +/** + * Constructs an `item` in-place at the end of the list. + * + * @param list A pointer to the `ZyanList` instance. + * @param item Receives a pointer to the new item. + * @param constructor The constructor callback or `ZYAN_NULL`. The new item will be in + * undefined state, if no constructor was passed. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanListEmplaceBack(ZyanList* list, void** item, + ZyanMemberFunction constructor); + +/** + * Constructs an `item` in-place at the beginning of the list. + * + * @param list A pointer to the `ZyanList` instance. + * @param item Receives a pointer to the new item. + * @param constructor The constructor callback or `ZYAN_NULL`. The new item will be in + * undefined state, if no constructor was passed. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanListEmplaceFront(ZyanList* list, void** item, + ZyanMemberFunction constructor); + +/* ---------------------------------------------------------------------------------------------- */ +/* Deletion */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Removes the last element of the list. + * + * @param list A pointer to the `ZyanList` instance. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanListPopBack(ZyanList* list); + +/** + * Removes the firstelement of the list. + * + * @param list A pointer to the `ZyanList` instance. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanListPopFront(ZyanList* list); + +/** + * Removes the given `node` from the list. + * + * @param list A pointer to the `ZyanList` instance. + * @param node A pointer to the `ZyanListNode` struct. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanListRemove(ZyanList* list, const ZyanListNode* node); + +/** + * Removes multiple nodes from the list. + * + * @param list A pointer to the `ZyanList` instance. + * @param first A pointer to the first node. + * @param last A pointer to the last node. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanListRemoveRange(ZyanList* list, const ZyanListNode* first, + const ZyanListNode* last); + +/** + * Erases all elements of the list. + * + * @param list A pointer to the `ZyanList` instance. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanListClear(ZyanList* list); + +/* ---------------------------------------------------------------------------------------------- */ +/* Searching */ +/* ---------------------------------------------------------------------------------------------- */ + +// TODO: + +/* ---------------------------------------------------------------------------------------------- */ +/* Memory management */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Resizes the given `ZyanList` instance. + * + * @param list A pointer to the `ZyanList` instance. + * @param size The new size of the list. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanListResize(ZyanList* list, ZyanUSize size); + +/** + * Resizes the given `ZyanList` instance. + * + * @param list A pointer to the `ZyanList` instance. + * @param size The new size of the list. + * @param initializer A pointer to a value to be used as initializer for new items. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanListResizeEx(ZyanList* list, ZyanUSize size, const void* initializer); + +/* ---------------------------------------------------------------------------------------------- */ +/* Information */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Returns the current size of the list. + * + * @param list A pointer to the `ZyanList` instance. + * @param size Receives the size of the list. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanListGetSize(const ZyanList* list, ZyanUSize* size); + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZYCORE_VECTOR_H */ diff --git a/zycore/include/Zycore/Object.h b/zycore/include/Zycore/Object.h new file mode 100644 index 0000000..d015cef --- /dev/null +++ b/zycore/include/Zycore/Object.h @@ -0,0 +1,84 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * Defines some generic object-related datatypes. + */ + +#ifndef ZYCORE_OBJECT_H +#define ZYCORE_OBJECT_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ============================================================================================== */ +/* Enums and types */ +/* ============================================================================================== */ + +/** + * Defines the `ZyanMemberProcedure` function prototype. + * + * @param object A pointer to the object. + */ +typedef void (*ZyanMemberProcedure)(void* object); + +/** + * Defines the `ZyanConstMemberProcedure` function prototype. + * + * @param object A pointer to the object. + */ +typedef void (*ZyanConstMemberProcedure)(const void* object); + +/** + * Defines the `ZyanMemberFunction` function prototype. + * + * @param object A pointer to the object. + * + * @return A zyan status code. + */ +typedef ZyanStatus (*ZyanMemberFunction)(void* object); + +/** + * Defines the `ZyanConstMemberFunction` function prototype. + * + * @param object A pointer to the object. + * + * @return A zyan status code. + */ +typedef ZyanStatus (*ZyanConstMemberFunction)(const void* object); + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZYCORE_OBJECT_H */ diff --git a/zycore/include/Zycore/Status.h b/zycore/include/Zycore/Status.h new file mode 100644 index 0000000..b0d7fdf --- /dev/null +++ b/zycore/include/Zycore/Status.h @@ -0,0 +1,287 @@ +/*************************************************************************************************** + + Zyan Core Library (Zyan-C) + + Original Author : Florian Bernd, Joel Hoener + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * Status code definitions and check macros. + */ + +#ifndef ZYCORE_STATUS_H +#define ZYCORE_STATUS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* ============================================================================================== */ +/* Enums and types */ +/* ============================================================================================== */ + +/** + * Defines the `ZyanStatus` data type. + */ +typedef ZyanU32 ZyanStatus; + +/* ============================================================================================== */ +/* Macros */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Definition */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines a zyan status code. + * + * @param error `1`, if the status code signals an error or `0`, if not. + * @param module The module id. + * @param code The actual code. + * + * @return The zyan status code. + */ +#define ZYAN_MAKE_STATUS(error, module, code) \ + (ZyanStatus)((((error) & 0x01u) << 31u) | (((module) & 0x7FFu) << 20u) | ((code) & 0xFFFFFu)) + +/* ---------------------------------------------------------------------------------------------- */ +/* Checks */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Checks if a zyan operation was successful. + * + * @param status The zyan status-code to check. + * + * @return `ZYAN_TRUE`, if the operation succeeded or `ZYAN_FALSE`, if not. + */ +#define ZYAN_SUCCESS(status) \ + (!((status) & 0x80000000u)) + +/** + * Checks if a zyan operation failed. + * + * @param status The zyan status-code to check. + * + * @return `ZYAN_TRUE`, if the operation failed or `ZYAN_FALSE`, if not. + */ +#define ZYAN_FAILED(status) \ + ((status) & 0x80000000u) + +/** + * Checks if a zyan operation was successful and returns with the status-code, if not. + * + * @param status The zyan status-code to check. + */ +#define ZYAN_CHECK(status) \ + do \ + { \ + const ZyanStatus status_047620348 = (status); \ + if (!ZYAN_SUCCESS(status_047620348)) \ + { \ + return status_047620348; \ + } \ + } while (0) + +/* ---------------------------------------------------------------------------------------------- */ +/* Information */ +/* ---------------------------------------------------------------------------------------------- */ + + /** + * Returns the module id of a zyan status-code. + * + * @param status The zyan status-code. + * + * @return The module id of the zyan status-code. + */ +#define ZYAN_STATUS_MODULE(status) \ + (((status) >> 20) & 0x7FFu) + + /** + * Returns the code of a zyan status-code. + * + * @param status The zyan status-code. + * + * @return The code of the zyan status-code. + */ +#define ZYAN_STATUS_CODE(status) \ + ((status) & 0xFFFFFu) + +/* ============================================================================================== */ +/* Status codes */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Module IDs */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * The zycore generic module id. + */ +#define ZYAN_MODULE_ZYCORE 0x001u + +/** + * The zycore arg-parse submodule id. + */ +#define ZYAN_MODULE_ARGPARSE 0x003u + +/** + * The base module id for user-defined status codes. + */ +#define ZYAN_MODULE_USER 0x3FFu + +/* ---------------------------------------------------------------------------------------------- */ +/* Status codes (general purpose) */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * The operation completed successfully. + */ +#define ZYAN_STATUS_SUCCESS \ + ZYAN_MAKE_STATUS(0u, ZYAN_MODULE_ZYCORE, 0x00u) + +/** + * The operation failed with an generic error. + */ +#define ZYAN_STATUS_FAILED \ + ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYCORE, 0x01u) + +/** + * The operation completed successfully and returned `ZYAN_TRUE`. + */ +#define ZYAN_STATUS_TRUE \ + ZYAN_MAKE_STATUS(0u, ZYAN_MODULE_ZYCORE, 0x02u) + +/** + * The operation completed successfully and returned `ZYAN_FALSE`. + */ +#define ZYAN_STATUS_FALSE \ + ZYAN_MAKE_STATUS(0u, ZYAN_MODULE_ZYCORE, 0x03u) + +/** + * An invalid argument was passed to a function. + */ +#define ZYAN_STATUS_INVALID_ARGUMENT \ + ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYCORE, 0x04u) + +/** + * An attempt was made to perform an invalid operation. + */ +#define ZYAN_STATUS_INVALID_OPERATION \ + ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYCORE, 0x05u) + +/** + * Insufficient privileges to perform the requested operation. + */ +#define ZYAN_STATUS_ACCESS_DENIED \ + ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYCORE, 0x06u) + +/** + * The requested entity was not found. + */ +#define ZYAN_STATUS_NOT_FOUND \ + ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYCORE, 0x07u) + +/** + * An index passed to a function was out of bounds. + */ +#define ZYAN_STATUS_OUT_OF_RANGE \ + ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYCORE, 0x08u) + +/** + * A buffer passed to a function was too small to complete the requested operation. + */ +#define ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE \ + ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYCORE, 0x09u) + +/** + * Insufficient memory to perform the operation. + */ +#define ZYAN_STATUS_NOT_ENOUGH_MEMORY \ + ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYCORE, 0x0Au) + +/** + * An unknown error occurred during a system function call. + */ +#define ZYAN_STATUS_BAD_SYSTEMCALL \ + ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYCORE, 0x0Bu) + +/** + * The process ran out of resources while performing an operation. + */ +#define ZYAN_STATUS_OUT_OF_RESOURCES \ + ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYCORE, 0x0Cu) + +/** + * A dependency library was not found or does have an unexpected version number or + * feature-set. + */ +#define ZYAN_STATUS_MISSING_DEPENDENCY \ + ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYCORE, 0x0Du) + +/* ---------------------------------------------------------------------------------------------- */ +/* Status codes (arg parse) */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Argument was not expected. + */ +#define ZYAN_STATUS_ARG_NOT_UNDERSTOOD \ + ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ARGPARSE, 0x00u) + +/** + * Too few arguments were provided. + */ +#define ZYAN_STATUS_TOO_FEW_ARGS \ + ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ARGPARSE, 0x01u) + +/** + * Too many arguments were provided. + */ +#define ZYAN_STATUS_TOO_MANY_ARGS \ + ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ARGPARSE, 0x02u) + +/** + * An argument that expected a value misses its value. + */ +#define ZYAN_STATUS_ARG_MISSES_VALUE \ + ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ARGPARSE, 0x03u) + +/** +* A required argument is missing. +*/ +#define ZYAN_STATUS_REQUIRED_ARG_MISSING \ + ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ARGPARSE, 0x04u) + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZYCORE_STATUS_H */ diff --git a/zycore/include/Zycore/String.h b/zycore/include/Zycore/String.h new file mode 100644 index 0000000..7bffaa6 --- /dev/null +++ b/zycore/include/Zycore/String.h @@ -0,0 +1,1011 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * Implements a string type. + */ + +#ifndef ZYCORE_STRING_H +#define ZYCORE_STRING_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ============================================================================================== */ +/* Constants */ +/* ============================================================================================== */ + +/** + * The initial minimum capacity (number of characters) for all dynamically allocated + * string instances - not including the terminating '\0'-character. + */ +#define ZYAN_STRING_MIN_CAPACITY 32 + +/** + * The default growth factor for all string instances. + */ +#define ZYAN_STRING_DEFAULT_GROWTH_FACTOR 2 + +/** + * The default shrink threshold for all string instances. + */ +#define ZYAN_STRING_DEFAULT_SHRINK_THRESHOLD 4 + +/* ============================================================================================== */ +/* Enums and types */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* String flags */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZyanStringFlags` data-type. + */ +typedef ZyanU8 ZyanStringFlags; + +/** + * The string uses a custom user-defined buffer with a fixed capacity. + */ +#define ZYAN_STRING_HAS_FIXED_CAPACITY 0x01 // (1 << 0) + +/* ---------------------------------------------------------------------------------------------- */ +/* String */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZyanString` struct. + * + * The `ZyanString` type is implemented as a size-prefixed string - which allows for a lot of + * performance optimizations. + * Nevertheless null-termination is guaranteed at all times to provide maximum compatibility with + * default C-style strings (use `ZyanStringGetData` to access the C-style string). + * + * All fields in this struct should be considered as "private". Any changes may lead to unexpected + * behavior. + */ +typedef struct ZyanString_ +{ + /** + * String flags. + */ + ZyanStringFlags flags; + /** + * The vector that contains the actual string. + */ + ZyanVector vector; +} ZyanString; + +/* ---------------------------------------------------------------------------------------------- */ +/* View */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZyanStringView` struct. + * + * The `ZyanStringView` type provides a view inside a string (`ZyanString` instances, null- + * terminated C-style strings, or even not-null-terminated custom strings). A view is immutable + * by design and can't be directly converted to a C-style string. + * + * Views might become invalid (e.g. pointing to invalid memory), if the underlying string gets + * destroyed or resized. + * + * The `ZYAN_STRING_TO_VIEW` macro can be used to cast a `ZyanString` to a `ZyanStringView` pointer + * without any runtime overhead. + * Casting a view to a normal string is not supported and will lead to unexpected behavior (use + * `ZyanStringDuplicate` to create a deep-copy instead). + * + * All fields in this struct should be considered as "private". Any changes may lead to unexpected + * behavior. + */ +typedef struct ZyanStringView_ +{ + /** + * The string data. + * + * The view internally re-uses the normal string struct to allow casts without any runtime + * overhead. + */ + ZyanString string; +} ZyanStringView; + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ +/* Macros */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* General */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines an uninitialized `ZyanString` instance. + */ +#define ZYAN_STRING_INITIALIZER \ + { \ + /* flags */ 0, \ + /* vector */ ZYAN_VECTOR_INITIALIZER \ + } + +/* ---------------------------------------------------------------------------------------------- */ +/* Helper macros */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Casts a `ZyanString` pointer to a constant `ZyanStringView` pointer. + */ +#define ZYAN_STRING_TO_VIEW(string) (const ZyanStringView*)(string) + +/** + * Defines a `ZyanStringView` struct that provides a view into a static C-style string. + * + * @param string The C-style string. + */ +#define ZYAN_DEFINE_STRING_VIEW(string) \ + { \ + /* string */ \ + { \ + /* flags */ 0, \ + /* vector */ \ + { \ + /* allocator */ ZYAN_NULL, \ + /* growth_factor */ 1, \ + /* shrink_threshold */ 0, \ + /* size */ sizeof(string), \ + /* capacity */ sizeof(string), \ + /* element_size */ sizeof(char), \ + /* destructor */ ZYAN_NULL, \ + /* data */ (char*)(string) \ + } \ + } \ + } + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Constructor and destructor */ +/* ---------------------------------------------------------------------------------------------- */ + +#ifndef ZYAN_NO_LIBC + +/** + * Initializes the given `ZyanString` instance. + * + * @param string A pointer to the `ZyanString` instance. + * @param capacity The initial capacity (number of characters). + * + * @return A zyan status code. + * + * The memory for the string is dynamically allocated by the default allocator using the default + * growth factor and the default shrink threshold. + * + * The allocated buffer will be at least one character larger than the given `capacity`, to reserve + * space for the terminating '\0'. + * + * Finalization with `ZyanStringDestroy` is required for all strings created by this function. + */ +ZYCORE_EXPORT ZYAN_REQUIRES_LIBC ZyanStatus ZyanStringInit(ZyanString* string, ZyanUSize capacity); + +#endif // ZYAN_NO_LIBC + +/** + * Initializes the given `ZyanString` instance and sets a custom `allocator` and memory + * allocation/deallocation parameters. + * + * @param string A pointer to the `ZyanString` instance. + * @param capacity The initial capacity (number of characters). + * @param allocator A pointer to a `ZyanAllocator` instance. + * @param growth_factor The growth factor. + * @param shrink_threshold The shrink threshold. + * + * @return A zyan status code. + * + * A growth factor of `1` disables overallocation and a shrink threshold of `0` disables + * dynamic shrinking. + * + * The allocated buffer will be at least one character larger than the given `capacity`, to reserve + * space for the terminating '\0'. + * + * Finalization with `ZyanStringDestroy` is required for all strings created by this function. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringInitEx(ZyanString* string, ZyanUSize capacity, + ZyanAllocator* allocator, ZyanU8 growth_factor, ZyanU8 shrink_threshold); + +/** + * Initializes the given `ZyanString` instance and configures it to use a custom user + * defined buffer with a fixed size. + * + * @param string A pointer to the `ZyanString` instance. + * @param buffer A pointer to the buffer that is used as storage for the string. + * @param capacity The maximum capacity (number of characters) of the buffer, including + * the terminating '\0'. + * + * @return A zyan status code. + * + * Finalization is not required for strings created by this function. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringInitCustomBuffer(ZyanString* string, char* buffer, + ZyanUSize capacity); + +/** + * Destroys the given `ZyanString` instance. + * + * @param string A pointer to the `ZyanString` instance. + * + * @return A zyan status code. + * + */ +ZYCORE_EXPORT ZyanStatus ZyanStringDestroy(ZyanString* string); + +/* ---------------------------------------------------------------------------------------------- */ +/* Duplication */ +/* ---------------------------------------------------------------------------------------------- */ + +#ifndef ZYAN_NO_LIBC + +/** + * Initializes a new `ZyanString` instance by duplicating an existing string. + * + * @param destination A pointer to the (uninitialized) destination `ZyanString` instance. + * @param source A pointer to the source string. + * @param capacity The initial capacity (number of characters). + * + * This value is automatically adjusted to the size of the source string, if + * a smaller value was passed. + * + * @return A zyan status code. + * + * The behavior of this function is undefined, if `source` is a view into the `destination` + * string or `destination` points to an already initialized `ZyanString` instance. + * + * The memory for the string is dynamically allocated by the default allocator using the default + * growth factor and the default shrink threshold. + * + * The allocated buffer will be at least one character larger than the given `capacity`, to reserve + * space for the terminating '\0'. + * + * Finalization with `ZyanStringDestroy` is required for all strings created by this function. + */ +ZYCORE_EXPORT ZYAN_REQUIRES_LIBC ZyanStatus ZyanStringDuplicate(ZyanString* destination, + const ZyanStringView* source, ZyanUSize capacity); + +#endif // ZYAN_NO_LIBC + +/** + * Initializes a new `ZyanString` instance by duplicating an existing string and sets a + * custom `allocator` and memory allocation/deallocation parameters. + * + * @param destination A pointer to the (uninitialized) destination `ZyanString` instance. + * @param source A pointer to the source string. + * @param capacity The initial capacity (number of characters). + + * This value is automatically adjusted to the size of the source + * string, if a smaller value was passed. + * @param allocator A pointer to a `ZyanAllocator` instance. + * @param growth_factor The growth factor. + * @param shrink_threshold The shrink threshold. + * + * @return A zyan status code. + * + * The behavior of this function is undefined, if `source` is a view into the `destination` + * string or `destination` points to an already initialized `ZyanString` instance. + * + * A growth factor of `1` disables overallocation and a shrink threshold of `0` disables + * dynamic shrinking. + * + * The allocated buffer will be at least one character larger than the given `capacity`, to reserve + * space for the terminating '\0'. + * + * Finalization with `ZyanStringDestroy` is required for all strings created by this function. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringDuplicateEx(ZyanString* destination, + const ZyanStringView* source, ZyanUSize capacity, ZyanAllocator* allocator, + ZyanU8 growth_factor, ZyanU8 shrink_threshold); + +/** + * Initializes a new `ZyanString` instance by duplicating an existing string and + * configures it to use a custom user defined buffer with a fixed size. + * + * @param destination A pointer to the (uninitialized) destination `ZyanString` instance. + * @param source A pointer to the source string. + * @param buffer A pointer to the buffer that is used as storage for the string. + * @param capacity The maximum capacity (number of characters) of the buffer, including the + * terminating '\0'. + + * This function will fail, if the capacity of the buffer is less or equal to + * the size of the source string. + * + * @return A zyan status code. + * + * The behavior of this function is undefined, if `source` is a view into the `destination` + * string or `destination` points to an already initialized `ZyanString` instance. + * + * Finalization is not required for strings created by this function. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringDuplicateCustomBuffer(ZyanString* destination, + const ZyanStringView* source, char* buffer, ZyanUSize capacity); + +/* ---------------------------------------------------------------------------------------------- */ +/* Concatenation */ +/* ---------------------------------------------------------------------------------------------- */ + +#ifndef ZYAN_NO_LIBC + +/** + * Initializes a new `ZyanString` instance by concatenating two existing strings. + * + * @param destination A pointer to the (uninitialized) destination `ZyanString` instance. + * + * This function will fail, if the destination `ZyanString` instance equals + * one of the source strings. + * @param s1 A pointer to the first source string. + * @param s2 A pointer to the second source string. + * @param capacity The initial capacity (number of characters). + + * This value is automatically adjusted to the combined size of the source + * strings, if a smaller value was passed. + * + * @return A zyan status code. + * + * The behavior of this function is undefined, if `s1` or `s2` are views into the `destination` + * string or `destination` points to an already initialized `ZyanString` instance. + * + * The memory for the string is dynamically allocated by the default allocator using the default + * growth factor and the default shrink threshold. + * + * The allocated buffer will be at least one character larger than the given `capacity`, to reserve + * space for the terminating '\0'. + * + * Finalization with `ZyanStringDestroy` is required for all strings created by this function. + */ +ZYCORE_EXPORT ZYAN_REQUIRES_LIBC ZyanStatus ZyanStringConcat(ZyanString* destination, + const ZyanStringView* s1, const ZyanStringView* s2, ZyanUSize capacity); + +#endif // ZYAN_NO_LIBC + +/** + * Initializes a new `ZyanString` instance by concatenating two existing strings and sets + * a custom `allocator` and memory allocation/deallocation parameters. + * + * @param destination A pointer to the (uninitialized) destination `ZyanString` instance. + * + * This function will fail, if the destination `ZyanString` instance + * equals one of the source strings. + * @param s1 A pointer to the first source string. + * @param s2 A pointer to the second source string. + * @param capacity The initial capacity (number of characters). + * + * This value is automatically adjusted to the combined size of the + * source strings, if a smaller value was passed. + * @param allocator A pointer to a `ZyanAllocator` instance. + * @param growth_factor The growth factor. + * @param shrink_threshold The shrink threshold. + * + * @return A zyan status code. + * + * The behavior of this function is undefined, if `s1` or `s2` are views into the `destination` + * string or `destination` points to an already initialized `ZyanString` instance. + * + * A growth factor of `1` disables overallocation and a shrink threshold of `0` disables + * dynamic shrinking. + * + * The allocated buffer will be at least one character larger than the given `capacity`, to reserve + * space for the terminating '\0'. + * + * Finalization with `ZyanStringDestroy` is required for all strings created by this function. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringConcatEx(ZyanString* destination, const ZyanStringView* s1, + const ZyanStringView* s2, ZyanUSize capacity, ZyanAllocator* allocator, ZyanU8 growth_factor, + ZyanU8 shrink_threshold); + +/** + * Initializes a new `ZyanString` instance by concatenating two existing strings and + * configures it to use a custom user defined buffer with a fixed size. + * + * @param destination A pointer to the (uninitialized) destination `ZyanString` instance. + * + * This function will fail, if the destination `ZyanString` instance equals + * one of the source strings. + * @param s1 A pointer to the first source string. + * @param s2 A pointer to the second source string. + * @param buffer A pointer to the buffer that is used as storage for the string. + * @param capacity The maximum capacity (number of characters) of the buffer. + * + * This function will fail, if the capacity of the buffer is less or equal to + * the combined size of the source strings. + * + * @return A zyan status code. + * + * The behavior of this function is undefined, if `s1` or `s2` are views into the `destination` + * string or `destination` points to an already initialized `ZyanString` instance. + * + * Finalization is not required for strings created by this function. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringConcatCustomBuffer(ZyanString* destination, + const ZyanStringView* s1, const ZyanStringView* s2, char* buffer, ZyanUSize capacity); + +/* ---------------------------------------------------------------------------------------------- */ +/* Views */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Returns a view inside an existing view/string. + * + * @param view A pointer to the `ZyanStringView` instance. + * @param source A pointer to the source string. + * + * @return A zyan status code. + * + * The `ZYAN_STRING_TO_VEW` macro can be used to pass any `ZyanString` instance as value for the + * `source` string. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringViewInsideView(ZyanStringView* view, + const ZyanStringView* source); + +/** + * Returns a view inside an existing view/string starting from the given `index`. + * + * @param view A pointer to the `ZyanStringView` instance. + * @param source A pointer to the source string. + * @param index The start index. + * @param count The number of characters. + * + * @return A zyan status code. + * + * The `ZYAN_STRING_TO_VEW` macro can be used to pass any `ZyanString` instance as value for the + * `source` string. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringViewInsideViewEx(ZyanStringView* view, + const ZyanStringView* source, ZyanUSize index, ZyanUSize count); + +/** + * Returns a view inside a null-terminated C-style string. + * + * @param view A pointer to the `ZyanStringView` instance. + * @param string The C-style string. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringViewInsideBuffer(ZyanStringView* view, const char* string); + +/** + * Returns a view inside a character buffer with custom length. + * + * @param view A pointer to the `ZyanStringView` instance. + * @param buffer A pointer to the buffer containing the string characters. + * @param length The length of the string (number of characters). + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringViewInsideBufferEx(ZyanStringView* view, const char* buffer, + ZyanUSize length); + +/** + * Returns the size (number of characters) of the view. + * + * @param view A pointer to the `ZyanStringView` instance. + * @param size Receives the size (number of characters) of the view. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringViewGetSize(const ZyanStringView* view, ZyanUSize* size); + +/** + * Returns the C-style string of the given `ZyanString` instance. + * + * @warning The string is not guaranteed to be null terminated! + * + * @param view A pointer to the `ZyanStringView` instance. + * @param buffer Receives a pointer to the C-style string. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringViewGetData(const ZyanStringView* view, const char** buffer); + +/* ---------------------------------------------------------------------------------------------- */ +/* Character access */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Returns the character at the given `index`. + * + * @param string A pointer to the `ZyanStringView` instance. + * @param index The character index. + * @param value Receives the desired character of the string. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringGetChar(const ZyanStringView* string, ZyanUSize index, + char* value); + +/** + * Returns a pointer to the character at the given `index`. + * + * @param string A pointer to the `ZyanString` instance. + * @param index The character index. + * @param value Receives a pointer to the desired character in the string. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringGetCharMutable(ZyanString* string, ZyanUSize index, + char** value); + +/** + * Assigns a new value to the character at the given `index`. + * + * @param string A pointer to the `ZyanString` instance. + * @param index The character index. + * @param value The character to assign. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringSetChar(ZyanString* string, ZyanUSize index, char value); + +/* ---------------------------------------------------------------------------------------------- */ +/* Insertion */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Inserts the content of the source string in the destination string at the given `index`. + * + * @param destination The destination string. + * @param index The insert index. + * @param source The source string. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringInsert(ZyanString* destination, ZyanUSize index, + const ZyanStringView* source); + +/** + * Inserts `count` characters of the source string in the destination string at the given + * `index`. + * + * @param destination The destination string. + * @param destination_index The insert index. + * @param source The source string. + * @param source_index The index of the first character to be inserted from the source + * string. + * @param count The number of chars to insert from the source string. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringInsertEx(ZyanString* destination, ZyanUSize destination_index, + const ZyanStringView* source, ZyanUSize source_index, ZyanUSize count); + +/* ---------------------------------------------------------------------------------------------- */ +/* Appending */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Appends the content of the source string to the end of the destination string. + * + * @param destination The destination string. + * @param source The source string. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringAppend(ZyanString* destination, const ZyanStringView* source); + +/** + * Appends `count` characters of the source string to the end of the destination string. + * + * @param destination The destination string. + * @param source The source string. + * @param source_index The index of the first character to be appended from the source string. + * @param count The number of chars to append from the source string. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringAppendEx(ZyanString* destination, const ZyanStringView* source, + ZyanUSize source_index, ZyanUSize count); + +/* ---------------------------------------------------------------------------------------------- */ +/* Deletion */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Deletes characters from the given string, starting at `index`. + * + * @param string A pointer to the `ZyanString` instance. + * @param index The index of the first character to delete. + * @param count The number of characters to delete. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringDelete(ZyanString* string, ZyanUSize index, ZyanUSize count); + +/** + * Deletes all remaining characters from the given string, starting at `index`. + * + * @param string A pointer to the `ZyanString` instance. + * @param index The index of the first character to delete. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringTruncate(ZyanString* string, ZyanUSize index); + +/** + * Erases the given string. + * + * @param string A pointer to the `ZyanString` instance. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringClear(ZyanString* string); + +/* ---------------------------------------------------------------------------------------------- */ +/* Searching */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Searches for the first occurrence of `needle` in the given `haystack` starting from the + * left. + * + * @param haystack The string to search in. + * @param needle The sub-string to search for. + * @param found_index A pointer to a variable that receives the index of the first occurrence of + * `needle`. + * + * @return `ZYAN_STATUS_TRUE`, if the needle was found, `ZYAN_STATUS_FALSE`, if not, or another + * zyan status code, if an error occured. + * + * The `found_index` is set to `-1`, if the needle was not found. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringLPos(const ZyanStringView* haystack, + const ZyanStringView* needle, ZyanISize* found_index); + +/** + * Searches for the first occurrence of `needle` in the given `haystack` starting from the + * left. + * + * @param haystack The string to search in. + * @param needle The sub-string to search for. + * @param found_index A pointer to a variable that receives the index of the first occurrence of + * `needle`. + * @param index The start index. + * @param count The maximum number of characters to iterate, beginning from the start + * `index`. + * + * @return `ZYAN_STATUS_TRUE`, if the needle was found, `ZYAN_STATUS_FALSE`, if not, or another + * zyan status code, if an error occured. + * + * The `found_index` is set to `-1`, if the needle was not found. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringLPosEx(const ZyanStringView* haystack, + const ZyanStringView* needle, ZyanISize* found_index, ZyanUSize index, ZyanUSize count); + +/** + * Performs a case-insensitive search for the first occurrence of `needle` in the given + * `haystack` starting from the left. + * + * @param haystack The string to search in. + * @param needle The sub-string to search for. + * @param found_index A pointer to a variable that receives the index of the first occurrence of + * `needle`. + * + * @return `ZYAN_STATUS_TRUE`, if the needle was found, `ZYAN_STATUS_FALSE`, if not, or another + * zyan status code, if an error occured. + * + * The `found_index` is set to `-1`, if the needle was not found. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringLPosI(const ZyanStringView* haystack, + const ZyanStringView* needle, ZyanISize* found_index); + +/** + * Performs a case-insensitive search for the first occurrence of `needle` in the given + * `haystack` starting from the left. + * + * @param haystack The string to search in. + * @param needle The sub-string to search for. + * @param found_index A pointer to a variable that receives the index of the first occurrence of + * `needle`. + * @param index The start index. + * @param count The maximum number of characters to iterate, beginning from the start + * `index`. + * + * @return `ZYAN_STATUS_TRUE`, if the needle was found, `ZYAN_STATUS_FALSE`, if not, or another + * zyan status code, if an error occurred. + * + * The `found_index` is set to `-1`, if the needle was not found. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringLPosIEx(const ZyanStringView* haystack, + const ZyanStringView* needle, ZyanISize* found_index, ZyanUSize index, ZyanUSize count); + +/** + * Searches for the first occurrence of `needle` in the given `haystack` starting from the + * right. + * + * @param haystack The string to search in. + * @param needle The sub-string to search for. + * @param found_index A pointer to a variable that receives the index of the first occurrence of + * `needle`. + * + * @return `ZYAN_STATUS_TRUE`, if the needle was found, `ZYAN_STATUS_FALSE`, if not, or another + * zyan status code, if an error occurred. + * + * The `found_index` is set to `-1`, if the needle was not found. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringRPos(const ZyanStringView* haystack, + const ZyanStringView* needle, ZyanISize* found_index); + +/** + * Searches for the first occurrence of `needle` in the given `haystack` starting from the + * right. + * + * @param haystack The string to search in. + * @param needle The sub-string to search for. + * @param found_index A pointer to a variable that receives the index of the first occurrence of + * `needle`. + * @param index The start index. + * @param count The maximum number of characters to iterate, beginning from the start + * `index`. + * + * @return `ZYAN_STATUS_TRUE`, if the needle was found, `ZYAN_STATUS_FALSE`, if not, or another + * zyan status code, if an error occurred. + * + * The `found_index` is set to `-1`, if the needle was not found. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringRPosEx(const ZyanStringView* haystack, + const ZyanStringView* needle, ZyanISize* found_index, ZyanUSize index, ZyanUSize count); + +/** + * Performs a case-insensitive search for the first occurrence of `needle` in the given + * `haystack` starting from the right. + * + * @param haystack The string to search in. + * @param needle The sub-string to search for. + * @param found_index A pointer to a variable that receives the index of the first occurrence of + * `needle`. + * + * @return `ZYAN_STATUS_TRUE`, if the needle was found, `ZYAN_STATUS_FALSE`, if not, or another + * zyan status code, if an error occurred. + * + * The `found_index` is set to `-1`, if the needle was not found. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringRPosI(const ZyanStringView* haystack, + const ZyanStringView* needle, ZyanISize* found_index); + +/** + * Performs a case-insensitive search for the first occurrence of `needle` in the given + * `haystack` starting from the right. + * + * @param haystack The string to search in. + * @param needle The sub-string to search for. + * @param found_index A pointer to a variable that receives the index of the first occurrence of + * `needle`. + * @param index The start index. + * @param count The maximum number of characters to iterate, beginning from the start + * `index`. + * + * @return `ZYAN_STATUS_TRUE`, if the needle was found, `ZYAN_STATUS_FALSE`, if not, or another + * zyan status code, if an error occurred. + * + * The `found_index` is set to `-1`, if the needle was not found. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringRPosIEx(const ZyanStringView* haystack, + const ZyanStringView* needle, ZyanISize* found_index, ZyanUSize index, ZyanUSize count); + +/* ---------------------------------------------------------------------------------------------- */ +/* Comparing */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Compares two strings. + * + * @param s1 The first string + * @param s2 The second string. + * @param result Receives the comparison result. + * + * Values: + * - `result < 0` -> The first character that does not match has a lower value + * in `s1` than in `s2`. + * - `result == 0` -> The contents of both strings are equal. + * - `result > 0` -> The first character that does not match has a greater value + * in `s1` than in `s2`. + * + * @return `ZYAN_STATUS_TRUE`, if the strings are equal, `ZYAN_STATUS_FALSE`, if not, or another + * zyan status code, if an error occurred. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringCompare(const ZyanStringView* s1, const ZyanStringView* s2, + ZyanI32* result); + +/** + * Performs a case-insensitive comparison of two strings. + * + * @param s1 The first string + * @param s2 The second string. + * @param result Receives the comparison result. + * + * Values: + * - `result < 0` -> The first character that does not match has a lower value + * in `s1` than in `s2`. + * - `result == 0` -> The contents of both strings are equal. + * - `result > 0` -> The first character that does not match has a greater value + * in `s1` than in `s2`. + * + * @return `ZYAN_STATUS_TRUE`, if the strings are equal, `ZYAN_STATUS_FALSE`, if not, or another + * zyan status code, if an error occurred. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringCompareI(const ZyanStringView* s1, const ZyanStringView* s2, + ZyanI32* result); + +/* ---------------------------------------------------------------------------------------------- */ +/* Case conversion */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Converts the given string to lowercase letters. + * + * @param string A pointer to the `ZyanString` instance. + * + * @return A zyan status code. + * + * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified + * `ZyanString` instance. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringToLowerCase(ZyanString* string); + +/** + * Converts `count` characters of the given string to lowercase letters. + * + * @param string A pointer to the `ZyanString` instance. + * @param index The start index. + * @param count The number of characters to convert, beginning from the start `index`. + * + * @return A zyan status code. + * + * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified + * `ZyanString` instance. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringToLowerCaseEx(ZyanString* string, ZyanUSize index, + ZyanUSize count); + +/** + * Converts the given string to uppercase letters. + * + * @param string A pointer to the `ZyanString` instance. + * + * @return A zyan status code. + * + * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified + * `ZyanString` instance. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringToUpperCase(ZyanString* string); + +/** + * Converts `count` characters of the given string to uppercase letters. + * + * @param string A pointer to the `ZyanString` instance. + * @param index The start index. + * @param count The number of characters to convert, beginning from the start `index`. + * + * @return A zyan status code. + * + * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified + * `ZyanString` instance. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringToUpperCaseEx(ZyanString* string, ZyanUSize index, + ZyanUSize count); + +/* ---------------------------------------------------------------------------------------------- */ +/* Memory management */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Resizes the given `ZyanString` instance. + * + * @param string A pointer to the `ZyanString` instance. + * @param size The new size of the string. + * + * @return A zyan status code. + * + * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified + * `ZyanString` instance. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringResize(ZyanString* string, ZyanUSize size); + +/** + * Changes the capacity of the given `ZyanString` instance. + * + * @param string A pointer to the `ZyanString` instance. + * @param capacity The new minimum capacity of the string. + * + * @return A zyan status code. + * + * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified + * `ZyanString` instance. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringReserve(ZyanString* string, ZyanUSize capacity); + +/** + * Shrinks the capacity of the given string to match it's size. + * + * @param string A pointer to the `ZyanString` instance. + * + * @return A zyan status code. + * + * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified + * `ZyanString` instance. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringShrinkToFit(ZyanString* string); + +/* ---------------------------------------------------------------------------------------------- */ +/* Information */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Returns the current capacity of the string. + * + * @param string A pointer to the `ZyanString` instance. + * @param capacity Receives the size of the string. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringGetCapacity(const ZyanString* string, ZyanUSize* capacity); + +/** + * Returns the current size (number of characters) of the string (excluding the + * terminating zero character). + * + * @param string A pointer to the `ZyanString` instance. + * @param size Receives the size (number of characters) of the string. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringGetSize(const ZyanString* string, ZyanUSize* size); + +/** + * Returns the C-style string of the given `ZyanString` instance. + * + * @param string A pointer to the `ZyanString` instance. + * @param value Receives a pointer to the C-style string. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanStringGetData(const ZyanString* string, const char** value); + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif // ZYCORE_STRING_H diff --git a/zycore/include/Zycore/Types.h b/zycore/include/Zycore/Types.h new file mode 100644 index 0000000..07b9ae2 --- /dev/null +++ b/zycore/include/Zycore/Types.h @@ -0,0 +1,236 @@ +/*************************************************************************************************** + + Zyan Core Library (Zyan-C) + + Original Author : Florian Bernd, Joel Hoener + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * Includes and defines some default data types. + */ + +#ifndef ZYCORE_TYPES_H +#define ZYCORE_TYPES_H + +#include + +/* ============================================================================================== */ +/* Integer types */ +/* ============================================================================================== */ + +#if defined(ZYAN_NO_LIBC) || \ + (defined(ZYAN_MSVC) && defined(ZYAN_KERNEL)) // The WDK LibC lacks stdint.h. + // No LibC mode, use compiler built-in types / macros. +# if defined(ZYAN_MSVC) || defined(ZYAN_ICC) + typedef unsigned __int8 ZyanU8; + typedef unsigned __int16 ZyanU16; + typedef unsigned __int32 ZyanU32; + typedef unsigned __int64 ZyanU64; + typedef signed __int8 ZyanI8; + typedef signed __int16 ZyanI16; + typedef signed __int32 ZyanI32; + typedef signed __int64 ZyanI64; +# if _WIN64 + typedef ZyanU64 ZyanUSize; + typedef ZyanI64 ZyanISize; + typedef ZyanU64 ZyanUPointer; + typedef ZyanI64 ZyanIPointer; +# else + typedef ZyanU32 ZyanUSize; + typedef ZyanI32 ZyanISize; + typedef ZyanU32 ZyanUPointer; + typedef ZyanI32 ZyanIPointer; +# endif +# elif defined(ZYAN_GNUC) + typedef __UINT8_TYPE__ ZyanU8; + typedef __UINT16_TYPE__ ZyanU16; + typedef __UINT32_TYPE__ ZyanU32; + typedef __UINT64_TYPE__ ZyanU64; + typedef __INT8_TYPE__ ZyanI8; + typedef __INT16_TYPE__ ZyanI16; + typedef __INT32_TYPE__ ZyanI32; + typedef __INT64_TYPE__ ZyanI64; + typedef __SIZE_TYPE__ ZyanUSize; + typedef __PTRDIFF_TYPE__ ZyanISize; + typedef __UINTPTR_TYPE__ ZyanUPointer; + typedef __INTPTR_TYPE__ ZyanIPointer; +# else +# error "Unsupported compiler for no-libc mode." +# endif + +# if defined(ZYAN_MSVC) +# define ZYAN_INT8_MIN (-127i8 - 1) +# define ZYAN_INT16_MIN (-32767i16 - 1) +# define ZYAN_INT32_MIN (-2147483647i32 - 1) +# define ZYAN_INT64_MIN (-9223372036854775807i64 - 1) +# define ZYAN_INT8_MAX 127i8 +# define ZYAN_INT16_MAX 32767i16 +# define ZYAN_INT32_MAX 2147483647i32 +# define ZYAN_INT64_MAX 9223372036854775807i64 +# define ZYAN_UINT8_MAX 0xffui8 +# define ZYAN_UINT16_MAX 0xffffui16 +# define ZYAN_UINT32_MAX 0xffffffffui32 +# define ZYAN_UINT64_MAX 0xffffffffffffffffui64 +# else +# define ZYAN_INT8_MAX __INT8_MAX__ +# define ZYAN_INT8_MIN (-ZYAN_INT8_MAX - 1) +# define ZYAN_INT16_MAX __INT16_MAX__ +# define ZYAN_INT16_MIN (-ZYAN_INT16_MAX - 1) +# define ZYAN_INT32_MAX __INT32_MAX__ +# define ZYAN_INT32_MIN (-ZYAN_INT32_MAX - 1) +# define ZYAN_INT64_MAX __INT64_MAX__ +# define ZYAN_INT64_MIN (-ZYAN_INT64_MAX - 1) +# define ZYAN_UINT8_MAX __UINT8_MAX__ +# define ZYAN_UINT16_MAX __UINT16_MAX__ +# define ZYAN_UINT32_MAX __UINT32_MAX__ +# define ZYAN_UINT64_MAX __UINT64_MAX__ +# endif +#else + // If is LibC present, we use stdint types. +# include +# include + typedef uint8_t ZyanU8; + typedef uint16_t ZyanU16; + typedef uint32_t ZyanU32; + typedef uint64_t ZyanU64; + typedef int8_t ZyanI8; + typedef int16_t ZyanI16; + typedef int32_t ZyanI32; + typedef int64_t ZyanI64; + typedef size_t ZyanUSize; + typedef ptrdiff_t ZyanISize; + typedef uintptr_t ZyanUPointer; + typedef intptr_t ZyanIPointer; + +# define ZYAN_INT8_MIN INT8_MIN +# define ZYAN_INT16_MIN INT16_MIN +# define ZYAN_INT32_MIN INT32_MIN +# define ZYAN_INT64_MIN INT64_MIN +# define ZYAN_INT8_MAX INT8_MAX +# define ZYAN_INT16_MAX INT16_MAX +# define ZYAN_INT32_MAX INT32_MAX +# define ZYAN_INT64_MAX INT64_MAX +# define ZYAN_UINT8_MAX UINT8_MAX +# define ZYAN_UINT16_MAX UINT16_MAX +# define ZYAN_UINT32_MAX UINT32_MAX +# define ZYAN_UINT64_MAX UINT64_MAX +#endif + +// Verify size assumptions. +ZYAN_STATIC_ASSERT(sizeof(ZyanU8 ) == 1 ); +ZYAN_STATIC_ASSERT(sizeof(ZyanU16 ) == 2 ); +ZYAN_STATIC_ASSERT(sizeof(ZyanU32 ) == 4 ); +ZYAN_STATIC_ASSERT(sizeof(ZyanU64 ) == 8 ); +ZYAN_STATIC_ASSERT(sizeof(ZyanI8 ) == 1 ); +ZYAN_STATIC_ASSERT(sizeof(ZyanI16 ) == 2 ); +ZYAN_STATIC_ASSERT(sizeof(ZyanI32 ) == 4 ); +ZYAN_STATIC_ASSERT(sizeof(ZyanI64 ) == 8 ); +ZYAN_STATIC_ASSERT(sizeof(ZyanUSize ) == sizeof(void*)); // TODO: This one is incorrect! +ZYAN_STATIC_ASSERT(sizeof(ZyanISize ) == sizeof(void*)); // TODO: This one is incorrect! +ZYAN_STATIC_ASSERT(sizeof(ZyanUPointer) == sizeof(void*)); +ZYAN_STATIC_ASSERT(sizeof(ZyanIPointer) == sizeof(void*)); + +// Verify signedness assumptions (relies on size checks above). +ZYAN_STATIC_ASSERT((ZyanI8 )-1 >> 1 < (ZyanI8 )((ZyanU8 )-1 >> 1)); +ZYAN_STATIC_ASSERT((ZyanI16)-1 >> 1 < (ZyanI16)((ZyanU16)-1 >> 1)); +ZYAN_STATIC_ASSERT((ZyanI32)-1 >> 1 < (ZyanI32)((ZyanU32)-1 >> 1)); +ZYAN_STATIC_ASSERT((ZyanI64)-1 >> 1 < (ZyanI64)((ZyanU64)-1 >> 1)); + +/* ============================================================================================== */ +/* Pointer */ +/* ============================================================================================== */ + +/** + * Defines the `ZyanVoidPointer` data-type. + */ +typedef void* ZyanVoidPointer; + +/** + * Defines the `ZyanConstVoidPointer` data-type. + */ +typedef const void* ZyanConstVoidPointer; + +#define ZYAN_NULL ((void*)0) + +/* ============================================================================================== */ +/* Logic types */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Boolean */ +/* ---------------------------------------------------------------------------------------------- */ + +#define ZYAN_FALSE 0 +#define ZYAN_TRUE 1 + +/** + * Defines the `ZyanBool` data-type. + * + * Represents a default boolean data-type where `0` is interpreted as `false` and all other values + * as `true`. + */ +typedef ZyanU8 ZyanBool; + +/* ---------------------------------------------------------------------------------------------- */ +/* Ternary */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZyanTernary` data-type. + * + * The `ZyanTernary` is a balanced ternary type that uses three truth values indicating `true`, + * `false` and an indeterminate third value. + */ +typedef ZyanI8 ZyanTernary; + +#define ZYAN_TERNARY_FALSE (-1) +#define ZYAN_TERNARY_UNKNOWN 0x00 +#define ZYAN_TERNARY_TRUE 0x01 + +/* ============================================================================================== */ +/* String types */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* C-style strings */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines the `ZyanCharPointer` data-type. + * + * This type is most often used to represent null-terminated strings aka. C-style strings. + */ +typedef char* ZyanCharPointer; + +/** + * Defines the `ZyanConstCharPointer` data-type. + * + * This type is most often used to represent null-terminated strings aka. C-style strings. + */ +typedef const char* ZyanConstCharPointer; + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ + +#endif /* ZYCORE_TYPES_H */ diff --git a/zycore/include/Zycore/Vector.h b/zycore/include/Zycore/Vector.h new file mode 100644 index 0000000..3bf7cbc --- /dev/null +++ b/zycore/include/Zycore/Vector.h @@ -0,0 +1,722 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * Implements the vector container class. + */ + +#ifndef ZYCORE_VECTOR_H +#define ZYCORE_VECTOR_H + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ============================================================================================== */ +/* Constants */ +/* ============================================================================================== */ + +/** + * The initial minimum capacity (number of elements) for all dynamically allocated vector + * instances. + */ +#define ZYAN_VECTOR_MIN_CAPACITY 1 + +/** + * The default growth factor for all vector instances. + */ +#define ZYAN_VECTOR_DEFAULT_GROWTH_FACTOR 2 + +/** + * The default shrink threshold for all vector instances. + */ +#define ZYAN_VECTOR_DEFAULT_SHRINK_THRESHOLD 4 + +/* ============================================================================================== */ +/* Enums and types */ +/* ============================================================================================== */ + +/** + * Defines the `ZyanVector` struct. + * + * All fields in this struct should be considered as "private". Any changes may lead to unexpected + * behavior. + */ +typedef struct ZyanVector_ +{ + /** + * The memory allocator. + */ + ZyanAllocator* allocator; + /** + * The growth factor. + */ + ZyanU8 growth_factor; + /** + * The shrink threshold. + */ + ZyanU8 shrink_threshold; + /** + * The current number of elements in the vector. + */ + ZyanUSize size; + /** + * The maximum capacity (number of elements). + */ + ZyanUSize capacity; + /** + * The size of a single element in bytes. + */ + ZyanUSize element_size; + /** + * The element destructor callback. + */ + ZyanMemberProcedure destructor; + /** + * The data pointer. + */ + void* data; +} ZyanVector; + +/* ============================================================================================== */ +/* Macros */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* General */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Defines an uninitialized `ZyanVector` instance. + */ +#define ZYAN_VECTOR_INITIALIZER \ + { \ + /* allocator */ ZYAN_NULL, \ + /* growth_factor */ 0, \ + /* shrink_threshold */ 0, \ + /* size */ 0, \ + /* capacity */ 0, \ + /* element_size */ 0, \ + /* destructor */ ZYAN_NULL, \ + /* data */ ZYAN_NULL \ + } + +/* ---------------------------------------------------------------------------------------------- */ +/* Helper macros */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Returns the value of the element at the given `index`. + * + * @param type The desired value type. + * @param vector A pointer to the `ZyanVector` instance. + * @param index The element index. + * + * @result The value of the desired element in the vector. + * + * Note that this function is unsafe and might dereference a null-pointer. + */ +#ifdef __cplusplus +#define ZYAN_VECTOR_GET(type, vector, index) \ + (*reinterpret_cast(ZyanVectorGet(vector, index))) +#else +#define ZYAN_VECTOR_GET(type, vector, index) \ + (*(const type*)ZyanVectorGet(vector, index)) +#endif + +/** + * Loops through all elements of the vector. + * + * @param type The desired value type. + * @param vector A pointer to the `ZyanVector` instance. + * @param item_name The name of the iterator item. + * @param body The body to execute for each item in the vector. + */ +#define ZYAN_VECTOR_FOREACH(type, vector, item_name, body) \ + { \ + const ZyanUSize ZYAN_MACRO_CONCAT_EXPAND(size_d50d3303, item_name) = (vector)->size; \ + for (ZyanUSize ZYAN_MACRO_CONCAT_EXPAND(i_bfd62679, item_name) = 0; \ + ZYAN_MACRO_CONCAT_EXPAND(i_bfd62679, item_name) < \ + ZYAN_MACRO_CONCAT_EXPAND(size_d50d3303, item_name); \ + ++ZYAN_MACRO_CONCAT_EXPAND(i_bfd62679, item_name)) \ + { \ + const type item_name = ZYAN_VECTOR_GET(type, vector, \ + ZYAN_MACRO_CONCAT_EXPAND(i_bfd62679, item_name)); \ + body \ + } \ + } + +/** + * Loops through all elements of the vector. + * + * @param type The desired value type. + * @param vector A pointer to the `ZyanVector` instance. + * @param item_name The name of the iterator item. + * @param body The body to execute for each item in the vector. + */ +#define ZYAN_VECTOR_FOREACH_MUTABLE(type, vector, item_name, body) \ + { \ + const ZyanUSize ZYAN_MACRO_CONCAT_EXPAND(size_d50d3303, item_name) = (vector)->size; \ + for (ZyanUSize ZYAN_MACRO_CONCAT_EXPAND(i_bfd62679, item_name) = 0; \ + ZYAN_MACRO_CONCAT_EXPAND(i_bfd62679, item_name) < \ + ZYAN_MACRO_CONCAT_EXPAND(size_d50d3303, item_name); \ + ++ZYAN_MACRO_CONCAT_EXPAND(i_bfd62679, item_name)) \ + { \ + type* const item_name = ZyanVectorGetMutable(vector, \ + ZYAN_MACRO_CONCAT_EXPAND(i_bfd62679, item_name)); \ + body \ + } \ + } + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Constructor and destructor */ +/* ---------------------------------------------------------------------------------------------- */ + +#ifndef ZYAN_NO_LIBC + +/** + * Initializes the given `ZyanVector` instance. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param element_size The size of a single element in bytes. + * @param capacity The initial capacity (number of elements). + * @param destructor A destructor callback that is invoked every time an item is deleted, or + * `ZYAN_NULL` if not needed. + * + * @return A zyan status code. + * + * The memory for the vector elements is dynamically allocated by the default allocator using the + * default growth factor and the default shrink threshold. + * + * Finalization with `ZyanVectorDestroy` is required for all instances created by this function. + */ +ZYCORE_EXPORT ZYAN_REQUIRES_LIBC ZyanStatus ZyanVectorInit(ZyanVector* vector, + ZyanUSize element_size, ZyanUSize capacity, ZyanMemberProcedure destructor); + +#endif // ZYAN_NO_LIBC + +/** + * Initializes the given `ZyanVector` instance and sets a custom `allocator` and memory + * allocation/deallocation parameters. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param element_size The size of a single element in bytes. + * @param capacity The initial capacity (number of elements). + * @param destructor A destructor callback that is invoked every time an item is deleted, + * or `ZYAN_NULL` if not needed. + * @param allocator A pointer to a `ZyanAllocator` instance. + * @param growth_factor The growth factor. + * @param shrink_threshold The shrink threshold. + * + * @return A zyan status code. + * + * A growth factor of `1` disables overallocation and a shrink threshold of `0` disables + * dynamic shrinking. + * + * Finalization with `ZyanVectorDestroy` is required for all instances created by this function. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorInitEx(ZyanVector* vector, ZyanUSize element_size, + ZyanUSize capacity, ZyanMemberProcedure destructor, ZyanAllocator* allocator, + ZyanU8 growth_factor, ZyanU8 shrink_threshold); + +/** + * Initializes the given `ZyanVector` instance and configures it to use a custom user + * defined buffer with a fixed size. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param element_size The size of a single element in bytes. + * @param buffer A pointer to the buffer that is used as storage for the elements. + * @param capacity The maximum capacity (number of elements) of the buffer. + * @param destructor A destructor callback that is invoked every time an item is deleted, or + * `ZYAN_NULL` if not needed. + * + * @return A zyan status code. + * + * Finalization is not required for instances created by this function. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorInitCustomBuffer(ZyanVector* vector, ZyanUSize element_size, + void* buffer, ZyanUSize capacity, ZyanMemberProcedure destructor); + +/** + * Destroys the given `ZyanVector` instance. + * + * @param vector A pointer to the `ZyanVector` instance.. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorDestroy(ZyanVector* vector); + +/* ---------------------------------------------------------------------------------------------- */ +/* Duplication */ +/* ---------------------------------------------------------------------------------------------- */ + +#ifndef ZYAN_NO_LIBC + +/** + * Initializes a new `ZyanVector` instance by duplicating an existing vector. + * + * @param destination A pointer to the (uninitialized) destination `ZyanVector` instance. + * @param source A pointer to the source vector. + * @param capacity The initial capacity (number of elements). + * + * This value is automatically adjusted to the size of the source vector, if + * a smaller value was passed. + * + * @return A zyan status code. + * + * The memory for the vector is dynamically allocated by the default allocator using the default + * growth factor and the default shrink threshold. + * + * Finalization with `ZyanVectorDestroy` is required for all instances created by this function. + */ +ZYCORE_EXPORT ZYAN_REQUIRES_LIBC ZyanStatus ZyanVectorDuplicate(ZyanVector* destination, + const ZyanVector* source, ZyanUSize capacity); + +#endif // ZYAN_NO_LIBC + +/** + * Initializes a new `ZyanVector` instance by duplicating an existing vector and sets a + * custom `allocator` and memory allocation/deallocation parameters. + * + * @param destination A pointer to the (uninitialized) destination `ZyanVector` instance. + * @param source A pointer to the source vector. + * @param capacity The initial capacity (number of elements). + + * This value is automatically adjusted to the size of the source + * vector, if a smaller value was passed. + * @param allocator A pointer to a `ZyanAllocator` instance. + * @param growth_factor The growth factor. + * @param shrink_threshold The shrink threshold. + * + * @return A zyan status code. + * + * A growth factor of `1` disables overallocation and a shrink threshold of `0` disables + * dynamic shrinking. + * + * Finalization with `ZyanVectorDestroy` is required for all instances created by this function. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorDuplicateEx(ZyanVector* destination, const ZyanVector* source, + ZyanUSize capacity, ZyanAllocator* allocator, ZyanU8 growth_factor, ZyanU8 shrink_threshold); + +/** + * Initializes a new `ZyanVector` instance by duplicating an existing vector and + * configures it to use a custom user defined buffer with a fixed size. + * + * @param destination A pointer to the (uninitialized) destination `ZyanVector` instance. + * @param source A pointer to the source vector. + * @param buffer A pointer to the buffer that is used as storage for the elements. + * @param capacity The maximum capacity (number of elements) of the buffer. + + * This function will fail, if the capacity of the buffer is less than the + * size of the source vector. + * + * @return A zyan status code. + * + * Finalization is not required for instances created by this function. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorDuplicateCustomBuffer(ZyanVector* destination, + const ZyanVector* source, void* buffer, ZyanUSize capacity); + +/* ---------------------------------------------------------------------------------------------- */ +/* Element access */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Returns a constant pointer to the element at the given `index`. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param index The element index. + * + * @return A constant pointer to the desired element in the vector or `ZYAN_NULL`, if an error + * occurred. + * + * Note that the returned pointer might get invalid when the vector is resized by either a manual + * call to the memory-management functions or implicitly by inserting or removing elements. + * + * Take a look at `ZyanVectorGetPointer` instead, if you need a function that returns a zyan status + * code. + */ +ZYCORE_EXPORT const void* ZyanVectorGet(const ZyanVector* vector, ZyanUSize index); + +/** + * Returns a mutable pointer to the element at the given `index`. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param index The element index. + * + * @return A mutable pointer to the desired element in the vector or `ZYAN_NULL`, if an error + * occurred. + * + * Note that the returned pointer might get invalid when the vector is resized by either a manual + * call to the memory-management functions or implicitly by inserting or removing elements. + * + * Take a look at `ZyanVectorGetPointerMutable` instead, if you need a function that returns a + * zyan status code. + */ +ZYCORE_EXPORT void* ZyanVectorGetMutable(const ZyanVector* vector, ZyanUSize index); + +/** + * Returns a constant pointer to the element at the given `index`. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param index The element index. + * @param value Receives a constant pointer to the desired element in the vector. + * + * Note that the returned pointer might get invalid when the vector is resized by either a manual + * call to the memory-management functions or implicitly by inserting or removing elements. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorGetPointer(const ZyanVector* vector, ZyanUSize index, + const void** value); + +/** + * Returns a mutable pointer to the element at the given `index`. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param index The element index. + * @param value Receives a mutable pointer to the desired element in the vector. + * + * Note that the returned pointer might get invalid when the vector is resized by either a manual + * call to the memory-management functions or implicitly by inserting or removing elements. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorGetPointerMutable(const ZyanVector* vector, ZyanUSize index, + void** value); + +/** + * Assigns a new value to the element at the given `index`. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param index The value index. + * @param value The value to assign. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorSet(ZyanVector* vector, ZyanUSize index, + const void* value); + +/* ---------------------------------------------------------------------------------------------- */ +/* Insertion */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Adds a new `element` to the end of the vector. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param element A pointer to the element to add. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorPushBack(ZyanVector* vector, const void* element); + +/** + * Inserts an `element` at the given `index` of the vector. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param index The insert index. + * @param element A pointer to the element to insert. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorInsert(ZyanVector* vector, ZyanUSize index, + const void* element); + +/** + * Inserts multiple `elements` at the given `index` of the vector. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param index The insert index. + * @param elements A pointer to the first element. + * @param count The number of elements to insert. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorInsertRange(ZyanVector* vector, ZyanUSize index, + const void* elements, ZyanUSize count); + +/** + * Constructs an `element` in-place at the end of the vector. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param element Receives a pointer to the new element. + * @param constructor The constructor callback or `ZYAN_NULL`. The new element will be in + * undefined state, if no constructor was passed. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorEmplace(ZyanVector* vector, void** element, + ZyanMemberFunction constructor); + +/** + * Constructs an `element` in-place and inserts it at the given `index` of the vector. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param index The insert index. + * @param element Receives a pointer to the new element. + * @param constructor The constructor callback or `ZYAN_NULL`. The new element will be in + * undefined state, if no constructor was passed. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorEmplaceEx(ZyanVector* vector, ZyanUSize index, + void** element, ZyanMemberFunction constructor); + +/* ---------------------------------------------------------------------------------------------- */ +/* Utils */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Swaps the element at `index_first` with the element at `index_second`. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param index_first The index of the first element. + * @param index_second The index of the second element. + * + * @return A zyan status code. + * + * This function requires the vector to have spare capacity for one temporary element. Call + * `ZyanVectorReserve` before this function to increase capacity, if needed. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorSwapElements(ZyanVector* vector, ZyanUSize index_first, + ZyanUSize index_second); + +/* ---------------------------------------------------------------------------------------------- */ +/* Deletion */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Deletes the element at the given `index` of the vector. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param index The element index. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorDelete(ZyanVector* vector, ZyanUSize index); + +/** + * Deletes multiple elements from the given vector, starting at `index`. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param index The index of the first element to delete. + * @param count The number of elements to delete. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorDeleteRange(ZyanVector* vector, ZyanUSize index, + ZyanUSize count); + +/** + * Removes the last element of the vector. + * + * @param vector A pointer to the `ZyanVector` instance. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorPopBack(ZyanVector* vector); + +/** + * Erases all elements of the given vector. + * + * @param vector A pointer to the `ZyanVector` instance. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorClear(ZyanVector* vector); + +/* ---------------------------------------------------------------------------------------------- */ +/* Searching */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Sequentially searches for the first occurrence of `element` in the given vector. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param element A pointer to the element to search for. + * @param found_index A pointer to a variable that receives the index of the found element. + * @param comparison The comparison function to use. + * + * @return `ZYAN_STATUS_TRUE` if the element was found, `ZYAN_STATUS_FALSE` if not or a generic + * zyan status code if an error occurred. + * + * The `found_index` is set to `-1`, if the element was not found. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorFind(const ZyanVector* vector, const void* element, + ZyanISize* found_index, ZyanEqualityComparison comparison); + +/** + * Sequentially searches for the first occurrence of `element` in the given vector. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param element A pointer to the element to search for. + * @param found_index A pointer to a variable that receives the index of the found element. + * @param comparison The comparison function to use. + * @param index The start index. + * @param count The maximum number of elements to iterate, beginning from the start `index`. + * + * @return `ZYAN_STATUS_TRUE` if the element was found, `ZYAN_STATUS_FALSE` if not or a generic + * zyan status code if an error occurred. + * + * The `found_index` is set to `-1`, if the element was not found. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorFindEx(const ZyanVector* vector, const void* element, + ZyanISize* found_index, ZyanEqualityComparison comparison, ZyanUSize index, ZyanUSize count); + +/** + * Searches for the first occurrence of `element` in the given vector using a binary- + * search algorithm. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param element A pointer to the element to search for. + * @param found_index A pointer to a variable that receives the index of the found element. + * @param comparison The comparison function to use. + * + * @return `ZYAN_STATUS_TRUE` if the element was found, `ZYAN_STATUS_FALSE` if not or a generic + * zyan status code if an error occurred. + * + * If found, `found_index` contains the zero-based index of `element`. If not found, `found_index` + * contains the index of the first entry larger than `element`. + * + * This function requires all elements in the vector to be strictly ordered (sorted). + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorBinarySearch(const ZyanVector* vector, const void* element, + ZyanUSize* found_index, ZyanComparison comparison); + +/** + * Searches for the first occurrence of `element` in the given vector using a binary- + * search algorithm. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param element A pointer to the element to search for. + * @param found_index A pointer to a variable that receives the index of the found element. + * @param comparison The comparison function to use. + * @param index The start index. + * @param count The maximum number of elements to iterate, beginning from the start `index`. + * + * @return `ZYAN_STATUS_TRUE` if the element was found, `ZYAN_STATUS_FALSE` if not or a generic + * zyan status code if an error occurred. + * + * If found, `found_index` contains the zero-based index of `element`. If not found, `found_index` + * contains the index of the first entry larger than `element`. + * + * This function requires all elements in the vector to be strictly ordered (sorted). + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorBinarySearchEx(const ZyanVector* vector, const void* element, + ZyanUSize* found_index, ZyanComparison comparison, ZyanUSize index, ZyanUSize count); + +/* ---------------------------------------------------------------------------------------------- */ +/* Memory management */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Resizes the given `ZyanVector` instance. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param size The new size of the vector. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorResize(ZyanVector* vector, ZyanUSize size); + +/** + * Resizes the given `ZyanVector` instance. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param size The new size of the vector. + * @param initializer A pointer to a value to be used as initializer for new items. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorResizeEx(ZyanVector* vector, ZyanUSize size, + const void* initializer); + +/** + * Changes the capacity of the given `ZyanVector` instance. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param capacity The new minimum capacity of the vector. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorReserve(ZyanVector* vector, ZyanUSize capacity); + +/** + * Shrinks the capacity of the given vector to match it's size. + * + * @param vector A pointer to the `ZyanVector` instance. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorShrinkToFit(ZyanVector* vector); + +/* ---------------------------------------------------------------------------------------------- */ +/* Information */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Returns the current capacity of the vector. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param capacity Receives the size of the vector. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorGetCapacity(const ZyanVector* vector, ZyanUSize* capacity); + +/** + * Returns the current size of the vector. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param size Receives the size of the vector. + * + * @return A zyan status code. + */ +ZYCORE_EXPORT ZyanStatus ZyanVectorGetSize(const ZyanVector* vector, ZyanUSize* size); + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZYCORE_VECTOR_H */ diff --git a/zycore/include/Zycore/Zycore.h b/zycore/include/Zycore/Zycore.h new file mode 100644 index 0000000..f4f6bc6 --- /dev/null +++ b/zycore/include/Zycore/Zycore.h @@ -0,0 +1,110 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * Master include file, including everything else. + */ + +#ifndef ZYCORE_H +#define ZYCORE_H + +#include + +// TODO: + +#ifdef __cplusplus +extern "C" { +#endif + +/* ============================================================================================== */ +/* Macros */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Constants */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * A macro that defines the zycore version. + */ +#define ZYCORE_VERSION (ZyanU64)0x0001000100000000 + +/* ---------------------------------------------------------------------------------------------- */ +/* Helper macros */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Extracts the major-part of the zycore version. + * + * @param version The zycore version value + */ +#define ZYCORE_VERSION_MAJOR(version) (ZyanU16)((version & 0xFFFF000000000000) >> 48) + +/** + * Extracts the minor-part of the zycore version. + * + * @param version The zycore version value + */ +#define ZYCORE_VERSION_MINOR(version) (ZyanU16)((version & 0x0000FFFF00000000) >> 32) + +/** + * Extracts the patch-part of the zycore version. + * + * @param version The zycore version value + */ +#define ZYCORE_VERSION_PATCH(version) (ZyanU16)((version & 0x00000000FFFF0000) >> 16) + +/** + * Extracts the build-part of the zycore version. + * + * @param version The zycore version value + */ +#define ZYCORE_VERSION_BUILD(version) (ZyanU16)(version & 0x000000000000FFFF) + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +/** + * Returns the zycore version. + * + * @return The zycore version. + * + * Use the macros provided in this file to extract the major, minor, patch and build part from the + * returned version value. + */ +ZYCORE_EXPORT ZyanU64 ZycoreGetVersion(void); + +/* ============================================================================================== */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZYCORE_H */ diff --git a/zycore/src/API/Memory.c b/zycore/src/API/Memory.c new file mode 100644 index 0000000..fda1e5a --- /dev/null +++ b/zycore/src/API/Memory.c @@ -0,0 +1,132 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +#include + +#ifndef ZYAN_NO_LIBC + +#if defined(ZYAN_WINDOWS) + +#elif defined(ZYAN_POSIX) +# include +#else +# error "Unsupported platform detected" +#endif + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* General */ +/* ---------------------------------------------------------------------------------------------- */ + +ZyanU32 ZyanMemoryGetSystemPageSize() +{ +#if defined(ZYAN_WINDOWS) + + SYSTEM_INFO system_info; + GetSystemInfo(&system_info); + + return system_info.dwPageSize; + +#elif defined(ZYAN_POSIX) + + return sysconf(_SC_PAGE_SIZE); + +#endif +} + +ZyanU32 ZyanMemoryGetSystemAllocationGranularity() +{ +#if defined(ZYAN_WINDOWS) + + SYSTEM_INFO system_info; + GetSystemInfo(&system_info); + + return system_info.dwAllocationGranularity; + +#elif defined(ZYAN_POSIX) + + return sysconf(_SC_PAGE_SIZE); + +#endif +} + +/* ---------------------------------------------------------------------------------------------- */ +/* Memory management */ +/* ---------------------------------------------------------------------------------------------- */ + +ZyanStatus ZyanMemoryVirtualProtect(void* address, ZyanUSize size, + ZyanMemoryPageProtection protection) +{ +#if defined(ZYAN_WINDOWS) + + DWORD old; + if (!VirtualProtect(address, size, protection, &old)) + { + return ZYAN_STATUS_BAD_SYSTEMCALL; + } + +#elif defined(ZYAN_POSIX) + + if (mprotect(address, size, protection)) + { + return ZYAN_STATUS_BAD_SYSTEMCALL; + } + +#endif + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanMemoryVirtualFree(void* address, ZyanUSize size) +{ +#if defined(ZYAN_WINDOWS) + + ZYAN_UNUSED(size); + if (!VirtualFree(address, 0, MEM_RELEASE)) + { + return ZYAN_STATUS_BAD_SYSTEMCALL; + } + +#elif defined(ZYAN_POSIX) + + if (munmap(address, size)) + { + return ZYAN_STATUS_BAD_SYSTEMCALL; + } + +#endif + + return ZYAN_STATUS_SUCCESS; +} + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ + +#endif /* ZYAN_NO_LIBC */ diff --git a/zycore/src/API/Process.c b/zycore/src/API/Process.c new file mode 100644 index 0000000..63e8e8f --- /dev/null +++ b/zycore/src/API/Process.c @@ -0,0 +1,76 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +#include +#if defined(ZYAN_WINDOWS) +#if defined(ZYAN_KERNEL) +# include +#else +# include +#endif +#elif defined(ZYAN_POSIX) +# include +#else +# error "Unsupported platform detected" +#endif +#include + +#ifndef ZYAN_NO_LIBC + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* General */ +/* ---------------------------------------------------------------------------------------------- */ + +ZyanStatus ZyanProcessFlushInstructionCache(void* address, ZyanUSize size) +{ +#if defined(ZYAN_WINDOWS) + + if (!FlushInstructionCache(GetCurrentProcess(), address, size)) + { + return ZYAN_STATUS_BAD_SYSTEMCALL; + } + +#elif defined(ZYAN_POSIX) + + if (msync(address, size, MS_SYNC | MS_INVALIDATE)) + { + return ZYAN_STATUS_BAD_SYSTEMCALL; + } + +#endif + + return ZYAN_STATUS_SUCCESS; +} + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ + +#endif /* ZYAN_NO_LIBC */ diff --git a/zycore/src/API/Synchronization.c b/zycore/src/API/Synchronization.c new file mode 100644 index 0000000..48080bb --- /dev/null +++ b/zycore/src/API/Synchronization.c @@ -0,0 +1,204 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +#include + +#ifndef ZYAN_NO_LIBC + +/* ============================================================================================== */ +/* Internal functions */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* */ +/* ---------------------------------------------------------------------------------------------- */ + + + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +#if defined(ZYAN_POSIX) + +#include + +/* ---------------------------------------------------------------------------------------------- */ +/* Critical Section */ +/* ---------------------------------------------------------------------------------------------- */ + +ZyanStatus ZyanCriticalSectionInitialize(ZyanCriticalSection* critical_section) +{ + pthread_mutexattr_t attribute; + + int error = pthread_mutexattr_init(&attribute); + if (error != 0) + { + if (error == ENOMEM) + { + return ZYAN_STATUS_NOT_ENOUGH_MEMORY; + } + return ZYAN_STATUS_BAD_SYSTEMCALL; + } + pthread_mutexattr_settype(&attribute, PTHREAD_MUTEX_RECURSIVE); + + error = pthread_mutex_init(critical_section, &attribute); + pthread_mutexattr_destroy(&attribute); + if (error != 0) + { + if (error == EAGAIN) + { + return ZYAN_STATUS_OUT_OF_RESOURCES; + } + if (error == ENOMEM) + { + return ZYAN_STATUS_NOT_ENOUGH_MEMORY; + } + if (error == EPERM) + { + return ZYAN_STATUS_ACCESS_DENIED; + } + if ((error == EBUSY) || (error == EINVAL)) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + return ZYAN_STATUS_BAD_SYSTEMCALL; + } + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanCriticalSectionEnter(ZyanCriticalSection* critical_section) +{ + const int error = pthread_mutex_lock(critical_section); + if (error != 0) + { + if (error == EINVAL) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + if (error == EAGAIN) + { + return ZYAN_STATUS_INVALID_OPERATION; + } + return ZYAN_STATUS_BAD_SYSTEMCALL; + } + + return ZYAN_STATUS_SUCCESS; +} + +ZyanBool ZyanCriticalSectionTryEnter(ZyanCriticalSection* critical_section) +{ + // No fine grained error handling for this one + return pthread_mutex_trylock(critical_section) ? ZYAN_FALSE : ZYAN_TRUE; +} + +ZyanStatus ZyanCriticalSectionLeave(ZyanCriticalSection* critical_section) +{ + const int error = pthread_mutex_unlock(critical_section); + if (error != 0) + { + if (error == EINVAL) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + if (error == EPERM) + { + return ZYAN_STATUS_INVALID_OPERATION; + } + return ZYAN_STATUS_BAD_SYSTEMCALL; + } + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanCriticalSectionDelete(ZyanCriticalSection* critical_section) +{ + const int error = pthread_mutex_destroy(critical_section); + if (error != 0) + { + if ((error == EBUSY) || (error == EINVAL)) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + return ZYAN_STATUS_BAD_SYSTEMCALL; + } + + return ZYAN_STATUS_SUCCESS; +} + +/* ---------------------------------------------------------------------------------------------- */ + +#elif defined(ZYAN_WINDOWS) + +/* ---------------------------------------------------------------------------------------------- */ +/* General */ +/* ---------------------------------------------------------------------------------------------- */ + +ZyanStatus ZyanCriticalSectionInitialize(ZyanCriticalSection* critical_section) +{ + InitializeCriticalSection(critical_section); + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanCriticalSectionEnter(ZyanCriticalSection* critical_section) +{ + EnterCriticalSection(critical_section); + + return ZYAN_STATUS_SUCCESS; +} + +ZyanBool ZyanCriticalSectionTryEnter(ZyanCriticalSection* critical_section) +{ + return TryEnterCriticalSection(critical_section) ? ZYAN_TRUE : ZYAN_FALSE; +} + +ZyanStatus ZyanCriticalSectionLeave(ZyanCriticalSection* critical_section) +{ + LeaveCriticalSection(critical_section); + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanCriticalSectionDelete(ZyanCriticalSection* critical_section) +{ + DeleteCriticalSection(critical_section); + + return ZYAN_STATUS_SUCCESS; +} + +/* ---------------------------------------------------------------------------------------------- */ + +#else +# error "Unsupported platform detected" +#endif + +/* ============================================================================================== */ + +#endif /* ZYAN_NO_LIBC */ diff --git a/zycore/src/API/Terminal.c b/zycore/src/API/Terminal.c new file mode 100644 index 0000000..382bd78 --- /dev/null +++ b/zycore/src/API/Terminal.c @@ -0,0 +1,160 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +#include + +#ifndef ZYAN_NO_LIBC + +#if defined(ZYAN_POSIX) +# include +#elif defined(ZYAN_WINDOWS) +# include +# include +#else +# error "Unsupported platform detected" +#endif + +// Provide fallback for old SDK versions +#ifdef ZYAN_WINDOWS +# ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING +# define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 +# endif +#endif + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +ZyanStatus ZyanTerminalEnableVT100(ZyanStandardStream stream) +{ + if ((stream != ZYAN_STDSTREAM_OUT) && (stream != ZYAN_STDSTREAM_ERR)) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + +#ifdef ZYAN_WINDOWS + // Get file descriptor + int file; + switch (stream) + { + case ZYAN_STDSTREAM_OUT: + file = _fileno(ZYAN_STDOUT); + break; + case ZYAN_STDSTREAM_ERR: + file = _fileno(ZYAN_STDERR); + break; + default: + ZYAN_UNREACHABLE; + } + if (file < 0) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + HANDLE const handle = (HANDLE)_get_osfhandle(file); + if (handle == INVALID_HANDLE_VALUE) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + DWORD mode; + if (!GetConsoleMode(handle, &mode)) + { + // The given standard stream is not bound to a terminal + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + if (!SetConsoleMode(handle, mode)) + { + return ZYAN_STATUS_BAD_SYSTEMCALL; + } +#endif + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanTerminalIsTTY(ZyanStandardStream stream) +{ + // Get file descriptor + int file; +#ifdef ZYAN_WINDOWS + switch (stream) + { + case ZYAN_STDSTREAM_IN: + file = _fileno(ZYAN_STDIN); + break; + case ZYAN_STDSTREAM_OUT: + file = _fileno(ZYAN_STDOUT); + break; + case ZYAN_STDSTREAM_ERR: + file = _fileno(ZYAN_STDERR); + break; + default: + ZYAN_UNREACHABLE; + } + if (file < 0) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } +#else + switch (stream) + { + case ZYAN_STDSTREAM_IN: + file = STDIN_FILENO; + break; + case ZYAN_STDSTREAM_OUT: + file = STDOUT_FILENO; + break; + case ZYAN_STDSTREAM_ERR: + file = STDERR_FILENO; + break; + default: + ZYAN_UNREACHABLE; + } +#endif + +#ifdef ZYAN_WINDOWS + if (_isatty(file)) +#else + if ( isatty(file)) +#endif + { + return ZYAN_STATUS_TRUE; + } + if (ZYAN_ERRNO == EBADF) + { + // Invalid file descriptor + return ZYAN_STATUS_INVALID_ARGUMENT; + } + //ZYAN_ASSERT((errno == EINVAL) || (errno == ENOTTY)); + + return ZYAN_STATUS_FALSE; +} + +/* ============================================================================================== */ + +#endif /* ZYAN_NO_LIBC */ diff --git a/zycore/src/API/Thread.c b/zycore/src/API/Thread.c new file mode 100644 index 0000000..0cc3d8c --- /dev/null +++ b/zycore/src/API/Thread.c @@ -0,0 +1,244 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +#include + +#ifndef ZYAN_NO_LIBC + +/* ============================================================================================== */ +/* Internal functions */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Legacy Windows import declarations */ +/* ---------------------------------------------------------------------------------------------- */ + +#if defined(ZYAN_WINDOWS) && defined(_WIN32_WINNT) && \ + (_WIN32_WINNT >= 0x0501) && (_WIN32_WINNT < 0x0600) + +/** + * The Windows SDK conditionally declares the following prototypes: the target OS must be Vista + * (0x0600) or above. MSDN states the same incorrect minimum requirement for the Fls* functions. + * + * However, these functions exist and work perfectly fine on XP (SP3) and Server 2003. + * Preserve backward compatibility with these OSes by declaring the prototypes here if needed. + */ + +#ifndef FLS_OUT_OF_INDEXES +#define FLS_OUT_OF_INDEXES ((DWORD)0xFFFFFFFF) +#endif + +WINBASEAPI +DWORD +WINAPI +FlsAlloc( + _In_opt_ PFLS_CALLBACK_FUNCTION lpCallback + ); + +WINBASEAPI +PVOID +WINAPI +FlsGetValue( + _In_ DWORD dwFlsIndex + ); + +WINBASEAPI +BOOL +WINAPI +FlsSetValue( + _In_ DWORD dwFlsIndex, + _In_opt_ PVOID lpFlsData + ); + +WINBASEAPI +BOOL +WINAPI +FlsFree( + _In_ DWORD dwFlsIndex + ); + +#endif /* (_WIN32_WINNT >= 0x0501) && (_WIN32_WINNT < 0x0600)*/ + + + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +#if defined(ZYAN_POSIX) + +#include + +/* ---------------------------------------------------------------------------------------------- */ +/* General */ +/* ---------------------------------------------------------------------------------------------- */ + +ZyanStatus ZyanThreadGetCurrentThread(ZyanThread* thread) +{ + *thread = pthread_self(); + + return ZYAN_STATUS_SUCCESS; +} + +ZYAN_STATIC_ASSERT(sizeof(ZyanThreadId) <= sizeof(ZyanU64)); +ZyanStatus ZyanThreadGetCurrentThreadId(ZyanThreadId* thread_id) +{ + // TODO: Use `pthread_getthreadid_np` on platforms where it is available + + pthread_t ptid = pthread_self(); + *thread_id = *(ZyanThreadId*)ptid; + + return ZYAN_STATUS_SUCCESS; +} + +/* ---------------------------------------------------------------------------------------------- */ +/* Thread Local Storage */ +/* ---------------------------------------------------------------------------------------------- */ + +ZyanStatus ZyanThreadTlsAlloc(ZyanThreadTlsIndex* index, ZyanThreadTlsCallback destructor) +{ + ZyanThreadTlsIndex value; + const int error = pthread_key_create(&value, destructor); + if (error != 0) + { + if (error == EAGAIN) + { + return ZYAN_STATUS_OUT_OF_RESOURCES; + } + if (error == ENOMEM) + { + return ZYAN_STATUS_NOT_ENOUGH_MEMORY; + } + return ZYAN_STATUS_BAD_SYSTEMCALL; + } + + *index = value; + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanThreadTlsFree(ZyanThreadTlsIndex index) +{ + return !pthread_key_delete(index) ? ZYAN_STATUS_SUCCESS : ZYAN_STATUS_BAD_SYSTEMCALL; +} + +ZyanStatus ZyanThreadTlsGetValue(ZyanThreadTlsIndex index, void** data) +{ + *data = pthread_getspecific(index); + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanThreadTlsSetValue(ZyanThreadTlsIndex index, void* data) +{ + const int error = pthread_setspecific(index, data); + if (error != 0) + { + if (error == EINVAL) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + return ZYAN_STATUS_BAD_SYSTEMCALL; + } + + return ZYAN_STATUS_SUCCESS; +} + +/* ---------------------------------------------------------------------------------------------- */ + +#elif defined(ZYAN_WINDOWS) + +/* ---------------------------------------------------------------------------------------------- */ +/* General */ +/* ---------------------------------------------------------------------------------------------- */ + +ZyanStatus ZyanThreadGetCurrentThread(ZyanThread* thread) +{ + *thread = GetCurrentThread(); + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanThreadGetCurrentThreadId(ZyanThreadId* thread_id) +{ + *thread_id = GetCurrentThreadId(); + + return ZYAN_STATUS_SUCCESS; +} + +/* ---------------------------------------------------------------------------------------------- */ +/* Thread Local Storage (TLS) */ +/* ---------------------------------------------------------------------------------------------- */ + +ZyanStatus ZyanThreadTlsAlloc(ZyanThreadTlsIndex* index, ZyanThreadTlsCallback destructor) +{ + const ZyanThreadTlsIndex value = FlsAlloc(destructor); + if (value == FLS_OUT_OF_INDEXES) + { + return ZYAN_STATUS_OUT_OF_RESOURCES; + } + + *index = value; + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanThreadTlsFree(ZyanThreadTlsIndex index) +{ + return FlsFree(index) ? ZYAN_STATUS_SUCCESS : ZYAN_STATUS_BAD_SYSTEMCALL; +} + +ZyanStatus ZyanThreadTlsGetValue(ZyanThreadTlsIndex index, void** data) +{ + *data = FlsGetValue(index); + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanThreadTlsSetValue(ZyanThreadTlsIndex index, void* data) +{ + if (!FlsSetValue(index, data)) + { + const DWORD error = GetLastError(); + if (error == ERROR_INVALID_PARAMETER) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + return ZYAN_STATUS_BAD_SYSTEMCALL; + } + + return ZYAN_STATUS_SUCCESS; +} + +/* ---------------------------------------------------------------------------------------------- */ + +#else +# error "Unsupported platform detected" +#endif + +/* ============================================================================================== */ + +#endif /* ZYAN_NO_LIBC */ diff --git a/zycore/src/Allocator.c b/zycore/src/Allocator.c new file mode 100644 index 0000000..5fadf64 --- /dev/null +++ b/zycore/src/Allocator.c @@ -0,0 +1,134 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +#include +#include + +/* ============================================================================================== */ +/* Internal functions */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Default allocator */ +/* ---------------------------------------------------------------------------------------------- */ + +#ifndef ZYAN_NO_LIBC + +static ZyanStatus ZyanAllocatorDefaultAllocate(ZyanAllocator* allocator, void** p, + ZyanUSize element_size, ZyanUSize n) +{ + ZYAN_ASSERT(allocator); + ZYAN_ASSERT(p); + ZYAN_ASSERT(element_size); + ZYAN_ASSERT(n); + + ZYAN_UNUSED(allocator); + + *p = ZYAN_MALLOC(element_size * n); + if (!*p) + { + return ZYAN_STATUS_NOT_ENOUGH_MEMORY; + } + + return ZYAN_STATUS_SUCCESS; +} + +static ZyanStatus ZyanAllocatorDefaultReallocate(ZyanAllocator* allocator, void** p, + ZyanUSize element_size, ZyanUSize n) +{ + ZYAN_ASSERT(allocator); + ZYAN_ASSERT(p); + ZYAN_ASSERT(element_size); + ZYAN_ASSERT(n); + + ZYAN_UNUSED(allocator); + + void* const x = ZYAN_REALLOC(*p, element_size * n); + if (!x) + { + return ZYAN_STATUS_NOT_ENOUGH_MEMORY; + } + *p = x; + + return ZYAN_STATUS_SUCCESS; +} + +static ZyanStatus ZyanAllocatorDefaultDeallocate(ZyanAllocator* allocator, void* p, + ZyanUSize element_size, ZyanUSize n) +{ + ZYAN_ASSERT(allocator); + ZYAN_ASSERT(p); + ZYAN_ASSERT(element_size); + ZYAN_ASSERT(n); + + ZYAN_UNUSED(allocator); + ZYAN_UNUSED(element_size); + ZYAN_UNUSED(n); + + ZYAN_FREE(p); + + return ZYAN_STATUS_SUCCESS; +} + +#endif // ZYAN_NO_LIBC + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +ZyanStatus ZyanAllocatorInit(ZyanAllocator* allocator, ZyanAllocatorAllocate allocate, + ZyanAllocatorAllocate reallocate, ZyanAllocatorDeallocate deallocate) +{ + if (!allocator || !allocate || !reallocate || !deallocate) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + allocator->allocate = allocate; + allocator->reallocate = reallocate; + allocator->deallocate = deallocate; + + return ZYAN_STATUS_SUCCESS; +} + +#ifndef ZYAN_NO_LIBC + +ZyanAllocator* ZyanAllocatorDefault(void) +{ + static ZyanAllocator allocator = + { + &ZyanAllocatorDefaultAllocate, + &ZyanAllocatorDefaultReallocate, + &ZyanAllocatorDefaultDeallocate + }; + return &allocator; +} + +#endif + +/* ============================================================================================== */ diff --git a/zycore/src/ArgParse.c b/zycore/src/ArgParse.c new file mode 100644 index 0000000..109cfc8 --- /dev/null +++ b/zycore/src/ArgParse.c @@ -0,0 +1,279 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Joel Hoener + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +#include +#include + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +#ifndef ZYAN_NO_LIBC + +ZyanStatus ZyanArgParse(const ZyanArgParseConfig *cfg, ZyanVector* parsed, + const char** error_token) +{ + return ZyanArgParseEx(cfg, parsed, error_token, ZyanAllocatorDefault()); +} + +#endif + +ZyanStatus ZyanArgParseEx(const ZyanArgParseConfig *cfg, ZyanVector* parsed, + const char** error_token, ZyanAllocator* allocator) +{ +# define ZYAN_ERR_TOK(tok) if (error_token) { *error_token = tok; } + + ZYAN_ASSERT(cfg); + ZYAN_ASSERT(parsed); + + // TODO: Once we have a decent hash map impl, refactor this to use it. The majority of for + // loops through the argument list could be avoided. + + if (cfg->min_unnamed_args > cfg->max_unnamed_args) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + // Check argument syntax. + for (const ZyanArgParseDefinition* def = cfg->args; def && def->name; ++def) + { + // TODO: Duplicate check + + if (!def->name) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + ZyanUSize arg_len = ZYAN_STRLEN(def->name); + if (arg_len < 2 || def->name[0] != '-') + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + // Single dash arguments only accept a single char name. + if (def->name[1] != '-' && arg_len != 2) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + } + + // Initialize output vector. + ZYAN_CHECK(ZyanVectorInitEx(parsed, sizeof(ZyanArgParseArg), cfg->argc, ZYAN_NULL, allocator, + ZYAN_VECTOR_DEFAULT_GROWTH_FACTOR, ZYAN_VECTOR_DEFAULT_SHRINK_THRESHOLD)); + + ZyanStatus err; + ZyanBool accept_dash_args = ZYAN_TRUE; + ZyanUSize num_unnamed_args = 0; + for (ZyanUSize i = 1; i < cfg->argc; ++i) + { + const char* cur_arg = cfg->argv[i]; + ZyanUSize arg_len = ZYAN_STRLEN(cfg->argv[i]); + + // Double-dash argument? + if (accept_dash_args && arg_len >= 2 && ZYAN_MEMCMP(cur_arg, "--", 2) == 0) + { + // GNU style end of argument parsing. + if (arg_len == 2) + { + accept_dash_args = ZYAN_FALSE; + } + // Regular double-dash argument. + else + { + // Allocate parsed argument struct. + ZyanArgParseArg* parsed_arg; + ZYAN_CHECK(ZyanVectorEmplace(parsed, (void**)&parsed_arg, ZYAN_NULL)); + ZYAN_MEMSET(parsed_arg, 0, sizeof(*parsed_arg)); + + // Find corresponding argument definition. + for (const ZyanArgParseDefinition* def = cfg->args; def && def->name; ++def) + { + if (ZYAN_STRCMP(def->name, cur_arg) == 0) + { + parsed_arg->def = def; + break; + } + } + + // Search exhausted & argument not found. RIP. + if (!parsed_arg->def) + { + err = ZYAN_STATUS_ARG_NOT_UNDERSTOOD; + ZYAN_ERR_TOK(cur_arg); + goto failure; + } + + // Does the argument expect a value? If yes, consume next token. + if (!parsed_arg->def->boolean) + { + if (i == cfg->argc - 1) + { + err = ZYAN_STATUS_ARG_MISSES_VALUE; + ZYAN_ERR_TOK(cur_arg); + goto failure; + } + parsed_arg->has_value = ZYAN_TRUE; + ZYAN_CHECK(ZyanStringViewInsideBuffer(&parsed_arg->value, cfg->argv[++i])); + } + } + + // Continue parsing at next token. + continue; + } + + // Single-dash argument? + // TODO: How to deal with just dashes? Current code treats it as unnamed arg. + if (accept_dash_args && arg_len > 1 && cur_arg[0] == '-') + { + // Iterate argument token chars until there are either no more chars left + // or we encounter a non-boolean argument, in which case we consume the + // remaining chars as its value. + for (const char* read_ptr = cur_arg + 1; *read_ptr; ++read_ptr) + { + // Allocate parsed argument struct. + ZyanArgParseArg* parsed_arg; + ZYAN_CHECK(ZyanVectorEmplace(parsed, (void**)&parsed_arg, ZYAN_NULL)); + ZYAN_MEMSET(parsed_arg, 0, sizeof(*parsed_arg)); + + // Find corresponding argument definition. + for (const ZyanArgParseDefinition* def = cfg->args; def && def->name; ++def) + { + if (ZYAN_STRLEN(def->name) == 2 && + def->name[0] == '-' && + def->name[1] == *read_ptr) + { + parsed_arg->def = def; + break; + } + } + + // Search exhausted, no match found? + if (!parsed_arg->def) + { + err = ZYAN_STATUS_ARG_NOT_UNDERSTOOD; + ZYAN_ERR_TOK(cur_arg); + goto failure; + } + + // Requires value? + if (!parsed_arg->def->boolean) + { + // If there are chars left, consume them (e.g. `-n1000`). + if (read_ptr[1]) + { + parsed_arg->has_value = ZYAN_TRUE; + ZYAN_CHECK(ZyanStringViewInsideBuffer(&parsed_arg->value, read_ptr + 1)); + } + // If not, consume next token (e.g. `-n 1000`). + else + { + if (i == cfg->argc - 1) + { + err = ZYAN_STATUS_ARG_MISSES_VALUE; + ZYAN_ERR_TOK(cur_arg) + goto failure; + } + + parsed_arg->has_value = ZYAN_TRUE; + ZYAN_CHECK(ZyanStringViewInsideBuffer(&parsed_arg->value, cfg->argv[++i])); + } + + // Either way, continue with next argument. + goto continue_main_loop; + } + } + } + + // Still here? We're looking at an unnamed argument. + ++num_unnamed_args; + if (num_unnamed_args > cfg->max_unnamed_args) + { + err = ZYAN_STATUS_TOO_MANY_ARGS; + ZYAN_ERR_TOK(cur_arg); + goto failure; + } + + // Allocate parsed argument struct. + ZyanArgParseArg* parsed_arg; + ZYAN_CHECK(ZyanVectorEmplace(parsed, (void**)&parsed_arg, ZYAN_NULL)); + ZYAN_MEMSET(parsed_arg, 0, sizeof(*parsed_arg)); + parsed_arg->has_value = ZYAN_TRUE; + ZYAN_CHECK(ZyanStringViewInsideBuffer(&parsed_arg->value, cur_arg)); + + continue_main_loop:; + } + + // All tokens processed. Do we have enough unnamed arguments? + if (num_unnamed_args < cfg->min_unnamed_args) + { + err = ZYAN_STATUS_TOO_FEW_ARGS; + // No sensible error token for this error type. + goto failure; + } + + // Check whether all required arguments are present. + ZyanUSize num_parsed_args; + ZYAN_CHECK(ZyanVectorGetSize(parsed, &num_parsed_args)); + for (const ZyanArgParseDefinition* def = cfg->args; def && def->name; ++def) + { + if (!def->required) continue; + + ZyanBool arg_found = ZYAN_FALSE; + for (ZyanUSize i = 0; i < num_parsed_args; ++i) + { + const ZyanArgParseArg* arg = ZYAN_NULL; + ZYAN_CHECK(ZyanVectorGetPointer(parsed, i, (const void**)&arg)); + + // Skip unnamed args. + if (!arg->def) continue; + + if (arg->def == def) + { + arg_found = ZYAN_TRUE; + break; + } + } + + if (!arg_found) + { + err = ZYAN_STATUS_REQUIRED_ARG_MISSING; + ZYAN_ERR_TOK(def->name); + goto failure; + } + } + + // Yay! + ZYAN_ERR_TOK(ZYAN_NULL); + return ZYAN_STATUS_SUCCESS; + +failure: + ZYAN_CHECK(ZyanVectorDestroy(parsed)); + return err; + +# undef ZYAN_ERR_TOK +} + +/* ============================================================================================== */ diff --git a/zycore/src/Bitset.c b/zycore/src/Bitset.c new file mode 100644 index 0000000..b1c733d --- /dev/null +++ b/zycore/src/Bitset.c @@ -0,0 +1,670 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +#include +#include + +/* ============================================================================================== */ +/* Internal constants */ +/* ============================================================================================== */ + +#define ZYAN_BITSET_GROWTH_FACTOR 2 +#define ZYAN_BITSET_SHRINK_THRESHOLD 2 + +/* ============================================================================================== */ +/* Internal macros */ +/* ============================================================================================== */ + +/** + * Computes the smallest integer value not less than `x`. + * + * @param x The value. + * + * @return The smallest integer value not less than `x`. + */ +#define ZYAN_BITSET_CEIL(x) \ + (((x) == ((ZyanU32)(x))) ? (ZyanU32)(x) : ((ZyanU32)(x)) + 1) + +/** + * Converts bits to bytes. + * + * @param x The value in bits. + * + * @return The amount of bytes needed to fit `x` bits. + */ +#define ZYAN_BITSET_BITS_TO_BYTES(x) \ + ZYAN_BITSET_CEIL((x) / 8) + +/** + * Returns the offset of the given bit. + * + * @param index The bit index. + * + * @return The offset of the given bit. + */ +#define ZYAN_BITSET_BIT_OFFSET(index) \ + (7 - ((index) % 8)) + +/* ============================================================================================== */ +/* Internal functions */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Helper functions */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Initializes the given `vector` with `count` "zero"-bytes. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param count The number of bytes. + * + * @return A zyan status code. + */ +static ZyanStatus ZyanBitsetInitVectorElements(ZyanVector* vector, ZyanUSize count) +{ + ZYAN_ASSERT(vector); + + static const ZyanU8 zero = 0; + for (ZyanUSize i = 0; i < count; ++i) + { + ZYAN_CHECK(ZyanVectorPushBack(vector, &zero)); + } + + return ZYAN_STATUS_SUCCESS; +} + +/* ---------------------------------------------------------------------------------------------- */ +/* Byte operations */ +/* ---------------------------------------------------------------------------------------------- */ + +static ZyanStatus ZyanBitsetOperationAND(ZyanU8* b1, const ZyanU8* b2) +{ + *b1 &= *b2; + return ZYAN_STATUS_SUCCESS; +} + +static ZyanStatus ZyanBitsetOperationOR (ZyanU8* b1, const ZyanU8* b2) +{ + *b1 |= *b2; + return ZYAN_STATUS_SUCCESS; +} + +static ZyanStatus ZyanBitsetOperationXOR(ZyanU8* b1, const ZyanU8* b2) +{ + *b1 ^= *b2; + return ZYAN_STATUS_SUCCESS; +} + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Constructor and destructor */ +/* ---------------------------------------------------------------------------------------------- */ + +#ifndef ZYAN_NO_LIBC + +ZyanStatus ZyanBitsetInit(ZyanBitset* bitset, ZyanUSize count) +{ + return ZyanBitsetInitEx(bitset, count, ZyanAllocatorDefault(), ZYAN_BITSET_GROWTH_FACTOR, + ZYAN_BITSET_SHRINK_THRESHOLD); +} + +#endif // ZYAN_NO_LIBC + +ZyanStatus ZyanBitsetInitEx(ZyanBitset* bitset, ZyanUSize count, ZyanAllocator* allocator, + ZyanU8 growth_factor, ZyanU8 shrink_threshold) +{ + if (!bitset) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + const ZyanU32 bytes = ZYAN_BITSET_BITS_TO_BYTES(count); + + bitset->size = count; + ZYAN_CHECK(ZyanVectorInitEx(&bitset->bits, sizeof(ZyanU8), bytes, ZYAN_NULL, allocator, + growth_factor, shrink_threshold)); + ZYAN_CHECK(ZyanBitsetInitVectorElements(&bitset->bits, bytes)); + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanBitsetInitBuffer(ZyanBitset* bitset, ZyanUSize count, void* buffer, + ZyanUSize capacity) +{ + if (!bitset) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + const ZyanU32 bytes = ZYAN_BITSET_BITS_TO_BYTES(count); + if (capacity < bytes) + { + return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE; + } + + bitset->size = count; + ZYAN_CHECK(ZyanVectorInitCustomBuffer(&bitset->bits, sizeof(ZyanU8), buffer, capacity, + ZYAN_NULL)); + ZYAN_CHECK(ZyanBitsetInitVectorElements(&bitset->bits, bytes)); + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanBitsetDestroy(ZyanBitset* bitset) +{ + if (!bitset) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + return ZyanVectorDestroy(&bitset->bits); +} + +/* ---------------------------------------------------------------------------------------------- */ +/* Logical operations */ +/* ---------------------------------------------------------------------------------------------- */ + +ZyanStatus ZyanBitsetPerformByteOperation(ZyanBitset* destination, const ZyanBitset* source, + ZyanBitsetByteOperation operation) +{ + if (!destination || !source || !operation) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + ZyanUSize s1; + ZyanUSize s2; + ZYAN_CHECK(ZyanVectorGetSize(&destination->bits, &s1)); + ZYAN_CHECK(ZyanVectorGetSize(&source->bits, &s2)); + + const ZyanUSize min = ZYAN_MIN(s1, s2); + for (ZyanUSize i = 0; i < min; ++i) + { + ZyanU8* v1; + const ZyanU8* v2; + ZYAN_CHECK(ZyanVectorGetPointerMutable(&destination->bits, i, (void**)&v1)); + ZYAN_CHECK(ZyanVectorGetPointer(&source->bits, i, (const void**)&v2)); + + ZYAN_ASSERT(v1); + ZYAN_ASSERT(v2); + + ZYAN_CHECK(operation(v1, v2)); + } + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanBitsetAND(ZyanBitset* destination, const ZyanBitset* source) +{ + return ZyanBitsetPerformByteOperation(destination, source, ZyanBitsetOperationAND); +} + +ZyanStatus ZyanBitsetOR (ZyanBitset* destination, const ZyanBitset* source) +{ + return ZyanBitsetPerformByteOperation(destination, source, ZyanBitsetOperationOR ); +} + +ZyanStatus ZyanBitsetXOR(ZyanBitset* destination, const ZyanBitset* source) +{ + return ZyanBitsetPerformByteOperation(destination, source, ZyanBitsetOperationXOR); +} + +ZyanStatus ZyanBitsetFlip(ZyanBitset* bitset) +{ + if (!bitset) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + ZyanUSize size; + ZYAN_CHECK(ZyanVectorGetSize(&bitset->bits, &size)); + for (ZyanUSize i = 0; i < size; ++i) + { + ZyanU8* value; + ZYAN_CHECK(ZyanVectorGetPointerMutable(&bitset->bits, i, (void**)&value)); + *value = ~(*value); + } + + return ZYAN_STATUS_SUCCESS; +} + +/* ---------------------------------------------------------------------------------------------- */ +/* Bit access */ +/* ---------------------------------------------------------------------------------------------- */ + +ZyanStatus ZyanBitsetSet(ZyanBitset* bitset, ZyanUSize index) +{ + if (!bitset) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + if (index >= bitset->size) + { + return ZYAN_STATUS_OUT_OF_RANGE; + } + + ZyanU8* value; + ZYAN_CHECK(ZyanVectorGetPointerMutable(&bitset->bits, index / 8, (void**)&value)); + + *value |= (1 << ZYAN_BITSET_BIT_OFFSET(index)); + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanBitsetReset(ZyanBitset* bitset, ZyanUSize index) +{ + if (!bitset) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + if (index >= bitset->size) + { + return ZYAN_STATUS_OUT_OF_RANGE; + } + + ZyanU8* value; + ZYAN_CHECK(ZyanVectorGetPointerMutable(&bitset->bits, index / 8, (void**)&value)); + *value &= ~(1 << ZYAN_BITSET_BIT_OFFSET(index)); + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanBitsetAssign(ZyanBitset* bitset, ZyanUSize index, ZyanBool value) +{ + if (value) + { + return ZyanBitsetSet(bitset, index); + } + return ZyanBitsetReset(bitset, index); +} + +ZyanStatus ZyanBitsetToggle(ZyanBitset* bitset, ZyanUSize index) +{ + if (!bitset) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + if (index >= bitset->size) + { + return ZYAN_STATUS_OUT_OF_RANGE; + } + + ZyanU8* value; + ZYAN_CHECK(ZyanVectorGetPointerMutable(&bitset->bits, index / 8, (void**)&value)); + *value ^= (1 << ZYAN_BITSET_BIT_OFFSET(index)); + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanBitsetTest(ZyanBitset* bitset, ZyanUSize index) +{ + if (!bitset) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + if (index >= bitset->size) + { + return ZYAN_STATUS_OUT_OF_RANGE; + } + + const ZyanU8* value; + ZYAN_CHECK(ZyanVectorGetPointer(&bitset->bits, index / 8, (const void**)&value)); + if ((*value & (1 << ZYAN_BITSET_BIT_OFFSET(index))) == 0) + { + return ZYAN_STATUS_FALSE; + } + return ZYAN_STATUS_TRUE; +} + +ZyanStatus ZyanBitsetTestMSB(ZyanBitset* bitset) +{ + if (!bitset) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + return ZyanBitsetTest(bitset, bitset->size - 1); +} + +ZyanStatus ZyanBitsetTestLSB(ZyanBitset* bitset) +{ + return ZyanBitsetTest(bitset, 0); +} + +/* ---------------------------------------------------------------------------------------------- */ + +ZyanStatus ZyanBitsetSetAll(ZyanBitset* bitset) +{ + if (!bitset) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + ZyanUSize size; + ZYAN_CHECK(ZyanVectorGetSize(&bitset->bits, &size)); + for (ZyanUSize i = 0; i < size; ++i) + { + ZyanU8* value; + ZYAN_CHECK(ZyanVectorGetPointerMutable(&bitset->bits, i, (void**)&value)); + *value = 0xFF; + } + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanBitsetResetAll(ZyanBitset* bitset) +{ + if (!bitset) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + ZyanUSize size; + ZYAN_CHECK(ZyanVectorGetSize(&bitset->bits, &size)); + for (ZyanUSize i = 0; i < size; ++i) + { + ZyanU8* value; + ZYAN_CHECK(ZyanVectorGetPointerMutable(&bitset->bits, i, (void**)&value)); + *value = 0x00; + } + + return ZYAN_STATUS_SUCCESS; +} + +/* ---------------------------------------------------------------------------------------------- */ +/* Size management */ +/* ---------------------------------------------------------------------------------------------- */ + +ZyanStatus ZyanBitsetPush(ZyanBitset* bitset, ZyanBool value) +{ + if (!bitset) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + if ((bitset->size++ % 8) == 0) + { + static const ZyanU8 zero = 0; + ZYAN_CHECK(ZyanVectorPushBack(&bitset->bits, &zero)); + } + + return ZyanBitsetAssign(bitset, bitset->size - 1, value); +} + +ZyanStatus ZyanBitsetPop(ZyanBitset* bitset) +{ + if (!bitset) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + if ((--bitset->size % 8) == 0) + { + return ZyanVectorPopBack(&bitset->bits); + } + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanBitsetClear(ZyanBitset* bitset) +{ + if (!bitset) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + bitset->size = 0; + return ZyanVectorClear(&bitset->bits); +} + +/* ---------------------------------------------------------------------------------------------- */ +/* Memory management */ +/* ---------------------------------------------------------------------------------------------- */ + +ZyanStatus ZyanBitsetReserve(ZyanBitset* bitset, ZyanUSize count) +{ + return ZyanVectorReserve(&bitset->bits, ZYAN_BITSET_BITS_TO_BYTES(count)); +} + +ZyanStatus ZyanBitsetShrinkToFit(ZyanBitset* bitset) +{ + return ZyanVectorShrinkToFit(&bitset->bits); +} + +/* ---------------------------------------------------------------------------------------------- */ +/* Information */ +/* ---------------------------------------------------------------------------------------------- */ + +ZyanStatus ZyanBitsetGetSize(const ZyanBitset* bitset, ZyanUSize* size) +{ + if (!bitset) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + *size = bitset->size; + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanBitsetGetCapacity(const ZyanBitset* bitset, ZyanUSize* capacity) +{ + ZYAN_CHECK(ZyanBitsetGetCapacityBytes(bitset, capacity)); + *capacity *= 8; + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanBitsetGetSizeBytes(const ZyanBitset* bitset, ZyanUSize* size) +{ + if (!bitset) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + return ZyanVectorGetSize(&bitset->bits, size); +} + +ZyanStatus ZyanBitsetGetCapacityBytes(const ZyanBitset* bitset, ZyanUSize* capacity) +{ + if (!bitset) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + return ZyanVectorGetCapacity(&bitset->bits, capacity); +} + +/* ---------------------------------------------------------------------------------------------- */ + +ZyanStatus ZyanBitsetCount(const ZyanBitset* bitset, ZyanUSize* count) +{ + if (!bitset || !count) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + *count = 0; + + ZyanUSize size; + ZYAN_CHECK(ZyanVectorGetSize(&bitset->bits, &size)); + for (ZyanUSize i = 0; i < size; ++i) + { + ZyanU8* value; + ZYAN_CHECK(ZyanVectorGetPointer(&bitset->bits, i, (const void**)&value)); + + ZyanU8 popcnt = *value; + popcnt = (popcnt & 0x55) + ((popcnt >> 1) & 0x55); + popcnt = (popcnt & 0x33) + ((popcnt >> 2) & 0x33); + popcnt = (popcnt & 0x0F) + ((popcnt >> 4) & 0x0F); + + *count += popcnt; + } + + *count = ZYAN_MIN(*count, bitset->size); + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanBitsetAll(const ZyanBitset* bitset) +{ + if (!bitset) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + ZyanUSize size; + ZYAN_CHECK(ZyanVectorGetSize(&bitset->bits, &size)); + for (ZyanUSize i = 0; i < size; ++i) + { + ZyanU8* value; + ZYAN_CHECK(ZyanVectorGetPointer(&bitset->bits, i, (const void**)&value)); + if (i < (size - 1)) + { + if (*value != 0xFF) + { + return ZYAN_STATUS_FALSE; + } + } else + { + const ZyanU8 mask = ~(8 - (bitset->size % 8)); + if ((*value & mask) != mask) + { + return ZYAN_STATUS_FALSE; + } + } + } + + return ZYAN_STATUS_TRUE; +} + +ZyanStatus ZyanBitsetAny(const ZyanBitset* bitset) +{ + if (!bitset) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + ZyanUSize size; + ZYAN_CHECK(ZyanVectorGetSize(&bitset->bits, &size)); + for (ZyanUSize i = 0; i < size; ++i) + { + ZyanU8* value; + ZYAN_CHECK(ZyanVectorGetPointer(&bitset->bits, i, (const void**)&value)); + if (i < (size - 1)) + { + if (*value != 0x00) + { + return ZYAN_STATUS_TRUE; + } + } else + { + const ZyanU8 mask = ~(8 - (bitset->size % 8)); + if ((*value & mask) != 0x00) + { + return ZYAN_STATUS_TRUE; + } + } + } + + return ZYAN_STATUS_FALSE; +} + +ZyanStatus ZyanBitsetNone(const ZyanBitset* bitset) +{ + if (!bitset) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + ZyanUSize size; + ZYAN_CHECK(ZyanVectorGetSize(&bitset->bits, &size)); + for (ZyanUSize i = 0; i < size; ++i) + { + ZyanU8* value; + ZYAN_CHECK(ZyanVectorGetPointer(&bitset->bits, i, (const void**)&value)); + if (i < (size - 1)) + { + if (*value != 0x00) + { + return ZYAN_STATUS_FALSE; + } + } else + { + const ZyanU8 mask = ~(8 - (bitset->size % 8)); + if ((*value & mask) != 0x00) + { + return ZYAN_STATUS_FALSE; + } + } + } + + return ZYAN_STATUS_TRUE; +} + +/* ---------------------------------------------------------------------------------------------- */ + +//ZyanStatus ZyanBitsetToU32(const ZyanBitset* bitset, ZyanU32* value) +//{ +// if (!bitset) +// { +// return ZYAN_STATUS_INVALID_ARGUMENT; +// } +// if (bitset->size > 32) +// { +// return ZYAN_STATUS_INVALID_OPERATION; +// } +// +// // TODO: +// +// return ZYAN_STATUS_SUCCESS; +//} +// +//ZyanStatus ZyanBitsetToU64(const ZyanBitset* bitset, ZyanU64* value) +//{ +// if (!bitset) +// { +// return ZYAN_STATUS_INVALID_ARGUMENT; +// } +// if (bitset->size > 64) +// { +// return ZYAN_STATUS_INVALID_OPERATION; +// } +// +// // TODO: +// +// return ZYAN_STATUS_SUCCESS; +//} + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ diff --git a/zycore/src/Format.c b/zycore/src/Format.c new file mode 100644 index 0000000..4529f88 --- /dev/null +++ b/zycore/src/Format.c @@ -0,0 +1,507 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +#include +#include + +/* ============================================================================================== */ +/* Constants */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Defines */ +/* ---------------------------------------------------------------------------------------------- */ + +#define ZYCORE_MAXCHARS_DEC_32 10 +#define ZYCORE_MAXCHARS_DEC_64 20 +#define ZYCORE_MAXCHARS_HEX_32 8 +#define ZYCORE_MAXCHARS_HEX_64 16 + +/* ---------------------------------------------------------------------------------------------- */ +/* Lookup Tables */ +/* ---------------------------------------------------------------------------------------------- */ + +static const char* const DECIMAL_LOOKUP = + "00010203040506070809" + "10111213141516171819" + "20212223242526272829" + "30313233343536373839" + "40414243444546474849" + "50515253545556575859" + "60616263646566676869" + "70717273747576777879" + "80818283848586878889" + "90919293949596979899"; + +/* ---------------------------------------------------------------------------------------------- */ +/* Static strings */ +/* ---------------------------------------------------------------------------------------------- */ + +static const ZyanStringView STR_ADD = ZYAN_DEFINE_STRING_VIEW("+"); +static const ZyanStringView STR_SUB = ZYAN_DEFINE_STRING_VIEW("-"); + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ +/* Internal macros */ +/* ============================================================================================== */ + +/** + * Writes a terminating '\0' character at the end of the string data. + */ +#define ZYCORE_STRING_NULLTERMINATE(string) \ + *(char*)((ZyanU8*)(string)->vector.data + (string)->vector.size - 1) = '\0'; + +/* ============================================================================================== */ +/* Internal functions */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Decimal */ +/* ---------------------------------------------------------------------------------------------- */ + +#if defined(ZYAN_X86) || defined(ZYAN_ARM) || defined(ZYAN_EMSCRIPTEN) || defined(ZYAN_WASM) +ZyanStatus ZyanStringAppendDecU32(ZyanString* string, ZyanU32 value, ZyanU8 padding_length) +{ + if (!string) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + char buffer[ZYCORE_MAXCHARS_DEC_32]; + char *buffer_end = &buffer[ZYCORE_MAXCHARS_DEC_32]; + char *buffer_write_pointer = buffer_end; + while (value >= 100) + { + const ZyanU32 value_old = value; + buffer_write_pointer -= 2; + value /= 100; + ZYAN_MEMCPY(buffer_write_pointer, &DECIMAL_LOOKUP[(value_old - (value * 100)) * 2], 2); + } + buffer_write_pointer -= 2; + ZYAN_MEMCPY(buffer_write_pointer, &DECIMAL_LOOKUP[value * 2], 2); + + const ZyanUSize offset_odd = (ZyanUSize)(value < 10); + const ZyanUSize length_number = buffer_end - buffer_write_pointer - offset_odd; + const ZyanUSize length_total = ZYAN_MAX(length_number, padding_length); + const ZyanUSize length_target = string->vector.size; + + if (string->vector.size + length_total > string->vector.capacity) + { + ZYAN_CHECK(ZyanStringResize(string, string->vector.size + length_total - 1)); + } + + ZyanUSize offset_write = 0; + if (padding_length > length_number) + { + offset_write = padding_length - length_number; + ZYAN_MEMSET((char*)string->vector.data + length_target - 1, '0', offset_write); + } + + ZYAN_MEMCPY((char*)string->vector.data + length_target + offset_write - 1, + buffer_write_pointer + offset_odd, length_number); + string->vector.size = length_target + length_total; + ZYCORE_STRING_NULLTERMINATE(string); + + return ZYAN_STATUS_SUCCESS; +} +#endif + +ZyanStatus ZyanStringAppendDecU64(ZyanString* string, ZyanU64 value, ZyanU8 padding_length) +{ + if (!string) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + char buffer[ZYCORE_MAXCHARS_DEC_64]; + char *buffer_end = &buffer[ZYCORE_MAXCHARS_DEC_64]; + char *buffer_write_pointer = buffer_end; + while (value >= 100) + { + const ZyanU64 value_old = value; + buffer_write_pointer -= 2; + value /= 100; + ZYAN_MEMCPY(buffer_write_pointer, &DECIMAL_LOOKUP[(value_old - (value * 100)) * 2], 2); + } + buffer_write_pointer -= 2; + ZYAN_MEMCPY(buffer_write_pointer, &DECIMAL_LOOKUP[value * 2], 2); + + const ZyanUSize offset_odd = (ZyanUSize)(value < 10); + const ZyanUSize length_number = buffer_end - buffer_write_pointer - offset_odd; + const ZyanUSize length_total = ZYAN_MAX(length_number, padding_length); + const ZyanUSize length_target = string->vector.size; + + if (string->vector.size + length_total > string->vector.capacity) + { + ZYAN_CHECK(ZyanStringResize(string, string->vector.size + length_total - 1)); + } + + ZyanUSize offset_write = 0; + if (padding_length > length_number) + { + offset_write = padding_length - length_number; + ZYAN_MEMSET((char*)string->vector.data + length_target - 1, '0', offset_write); + } + + ZYAN_MEMCPY((char*)string->vector.data + length_target + offset_write - 1, + buffer_write_pointer + offset_odd, length_number); + string->vector.size = length_target + length_total; + ZYCORE_STRING_NULLTERMINATE(string); + + return ZYAN_STATUS_SUCCESS; +} + +/* ---------------------------------------------------------------------------------------------- */ +/* Hexadecimal */ +/* ---------------------------------------------------------------------------------------------- */ + +#if defined(ZYAN_X86) || defined(ZYAN_ARM) || defined(ZYAN_EMSCRIPTEN) || defined(ZYAN_WASM) +ZyanStatus ZyanStringAppendHexU32(ZyanString* string, ZyanU32 value, ZyanU8 padding_length, + ZyanBool uppercase) +{ + if (!string) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + const ZyanUSize len = string->vector.size; + ZyanUSize remaining = string->vector.capacity - string->vector.size; + + if (remaining < (ZyanUSize)padding_length) + { + ZYAN_CHECK(ZyanStringResize(string, len + padding_length - 1)); + remaining = padding_length; + } + + if (!value) + { + const ZyanU8 n = (padding_length ? padding_length : 1); + + if (remaining < (ZyanUSize)n) + { + ZYAN_CHECK(ZyanStringResize(string, string->vector.size + n - 1)); + } + + ZYAN_MEMSET((char*)string->vector.data + len - 1, '0', n); + string->vector.size = len + n; + ZYCORE_STRING_NULLTERMINATE(string); + + return ZYAN_STATUS_SUCCESS; + } + + ZyanU8 n = 0; + char* buffer = ZYAN_NULL; + for (ZyanI8 i = ZYCORE_MAXCHARS_HEX_32 - 1; i >= 0; --i) + { + const ZyanU8 v = (value >> i * 4) & 0x0F; + if (!n) + { + if (!v) + { + continue; + } + if (remaining <= (ZyanU8)i) + { + ZYAN_CHECK(ZyanStringResize(string, string->vector.size + i)); + } + buffer = (char*)string->vector.data + len - 1; + if (padding_length > i) + { + n = padding_length - i - 1; + ZYAN_MEMSET(buffer, '0', n); + } + } + ZYAN_ASSERT(buffer); + if (uppercase) + { + buffer[n++] = "0123456789ABCDEF"[v]; + } else + { + buffer[n++] = "0123456789abcdef"[v]; + } + } + string->vector.size = len + n; + ZYCORE_STRING_NULLTERMINATE(string); + + return ZYAN_STATUS_SUCCESS; +} +#endif + +ZyanStatus ZyanStringAppendHexU64(ZyanString* string, ZyanU64 value, ZyanU8 padding_length, + ZyanBool uppercase) +{ + if (!string) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + const ZyanUSize len = string->vector.size; + ZyanUSize remaining = string->vector.capacity - string->vector.size; + + if (remaining < (ZyanUSize)padding_length) + { + ZYAN_CHECK(ZyanStringResize(string, len + padding_length - 1)); + remaining = padding_length; + } + + if (!value) + { + const ZyanU8 n = (padding_length ? padding_length : 1); + + if (remaining < (ZyanUSize)n) + { + ZYAN_CHECK(ZyanStringResize(string, string->vector.size + n - 1)); + } + + ZYAN_MEMSET((char*)string->vector.data + len - 1, '0', n); + string->vector.size = len + n; + ZYCORE_STRING_NULLTERMINATE(string); + + return ZYAN_STATUS_SUCCESS; + } + + ZyanU8 n = 0; + char* buffer = ZYAN_NULL; + for (ZyanI8 i = ((value & 0xFFFFFFFF00000000) ? + ZYCORE_MAXCHARS_HEX_64 : ZYCORE_MAXCHARS_HEX_32) - 1; i >= 0; --i) + { + const ZyanU8 v = (value >> i * 4) & 0x0F; + if (!n) + { + if (!v) + { + continue; + } + if (remaining <= (ZyanU8)i) + { + ZYAN_CHECK(ZyanStringResize(string, string->vector.size + i)); + } + buffer = (char*)string->vector.data + len - 1; + if (padding_length > i) + { + n = padding_length - i - 1; + ZYAN_MEMSET(buffer, '0', n); + } + } + ZYAN_ASSERT(buffer); + if (uppercase) + { + buffer[n++] = "0123456789ABCDEF"[v]; + } else + { + buffer[n++] = "0123456789abcdef"[v]; + } + } + string->vector.size = len + n; + ZYCORE_STRING_NULLTERMINATE(string); + + return ZYAN_STATUS_SUCCESS; +} + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Insertion */ +/* ---------------------------------------------------------------------------------------------- */ + +//ZyanStatus ZyanStringInsertFormat(ZyanString* string, ZyanUSize index, const char* format, ...) +//{ +// +//} +// +///* ---------------------------------------------------------------------------------------------- */ +// +//ZyanStatus ZyanStringInsertDecU(ZyanString* string, ZyanUSize index, ZyanU64 value, +// ZyanUSize padding_length) +//{ +// +//} +// +//ZyanStatus ZyanStringInsertDecS(ZyanString* string, ZyanUSize index, ZyanI64 value, +// ZyanUSize padding_length, ZyanBool force_sign, const ZyanString* prefix) +//{ +// +//} +// +//ZyanStatus ZyanStringInsertHexU(ZyanString* string, ZyanUSize index, ZyanU64 value, +// ZyanUSize padding_length, ZyanBool uppercase) +//{ +// +//} +// +//ZyanStatus ZyanStringInsertHexS(ZyanString* string, ZyanUSize index, ZyanI64 value, +// ZyanUSize padding_length, ZyanBool uppercase, ZyanBool force_sign, const ZyanString* prefix) +//{ +// +//} + +/* ---------------------------------------------------------------------------------------------- */ +/* Appending */ +/* ---------------------------------------------------------------------------------------------- */ + +#ifndef ZYAN_NO_LIBC + +ZyanStatus ZyanStringAppendFormat(ZyanString* string, const char* format, ...) +{ + if (!string || !format) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + ZyanVAList arglist; + ZYAN_VA_START(arglist, format); + + const ZyanUSize len = string->vector.size; + + ZyanI32 w = ZYAN_VSNPRINTF((char*)string->vector.data + len - 1, + string->vector.capacity - len + 1, format, arglist); + if (w < 0) + { + ZYAN_VA_END(arglist); + return ZYAN_STATUS_FAILED; + } + if (w <= (ZyanI32)(string->vector.capacity - len)) + { + string->vector.size = len + w; + + ZYAN_VA_END(arglist); + return ZYAN_STATUS_SUCCESS; + } + + // The remaining capacity was not sufficent to fit the formatted string. Trying to resize .. + const ZyanStatus status = ZyanStringResize(string, string->vector.size + w - 1); + if (!ZYAN_SUCCESS(status)) + { + ZYAN_VA_END(arglist); + return status; + } + + w = ZYAN_VSNPRINTF((char*)string->vector.data + len - 1, + string->vector.capacity - string->vector.size + 1, format, arglist); + if (w < 0) + { + ZYAN_VA_END(arglist); + return ZYAN_STATUS_FAILED; + } + ZYAN_ASSERT(w <= (ZyanI32)(string->vector.capacity - string->vector.size)); + + ZYAN_VA_END(arglist); + return ZYAN_STATUS_SUCCESS; +} + +#endif // ZYAN_NO_LIBC + +/* ---------------------------------------------------------------------------------------------- */ + +ZyanStatus ZyanStringAppendDecU(ZyanString* string, ZyanU64 value, ZyanU8 padding_length) +{ +#if defined(ZYAN_X64) || defined(ZYAN_AARCH64) + return ZyanStringAppendDecU64(string, value, padding_length); +#else + // Working with 64-bit values is slow on non 64-bit systems + if (value & 0xFFFFFFFF00000000) + { + return ZyanStringAppendDecU64(string, value, padding_length); + } + return ZyanStringAppendDecU32(string, (ZyanU32)value, padding_length); +#endif +} + +ZyanStatus ZyanStringAppendDecS(ZyanString* string, ZyanI64 value, ZyanU8 padding_length, + ZyanBool force_sign, const ZyanStringView* prefix) +{ + if (value < 0) + { + ZYAN_CHECK(ZyanStringAppend(string, &STR_SUB)); + if (prefix) + { + ZYAN_CHECK(ZyanStringAppend(string, prefix)); + } + return ZyanStringAppendDecU(string, ZyanAbsI64(value), padding_length); + } + + if (force_sign) + { + ZYAN_ASSERT(value >= 0); + ZYAN_CHECK(ZyanStringAppend(string, &STR_ADD)); + } + + if (prefix) + { + ZYAN_CHECK(ZyanStringAppend(string, prefix)); + } + return ZyanStringAppendDecU(string, value, padding_length); +} + +ZyanStatus ZyanStringAppendHexU(ZyanString* string, ZyanU64 value, ZyanU8 padding_length, + ZyanBool uppercase) +{ +#if defined(ZYAN_X64) || defined(ZYAN_AARCH64) + return ZyanStringAppendHexU64(string, value, padding_length, uppercase); +#else + // Working with 64-bit values is slow on non 64-bit systems + if (value & 0xFFFFFFFF00000000) + { + return ZyanStringAppendHexU64(string, value, padding_length, uppercase); + } + return ZyanStringAppendHexU32(string, (ZyanU32)value, padding_length, uppercase); +#endif +} + +ZyanStatus ZyanStringAppendHexS(ZyanString* string, ZyanI64 value, ZyanU8 padding_length, + ZyanBool uppercase, ZyanBool force_sign, const ZyanStringView* prefix) +{ + if (value < 0) + { + ZYAN_CHECK(ZyanStringAppend(string, &STR_SUB)); + if (prefix) + { + ZYAN_CHECK(ZyanStringAppend(string, prefix)); + } + return ZyanStringAppendHexU(string, ZyanAbsI64(value), padding_length, uppercase); + } + + if (force_sign) + { + ZYAN_ASSERT(value >= 0); + ZYAN_CHECK(ZyanStringAppend(string, &STR_ADD)); + } + + if (prefix) + { + ZYAN_CHECK(ZyanStringAppend(string, prefix)); + } + return ZyanStringAppendHexU(string, value, padding_length, uppercase); +} + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ diff --git a/zycore/src/List.c b/zycore/src/List.c new file mode 100644 index 0000000..e233da8 --- /dev/null +++ b/zycore/src/List.c @@ -0,0 +1,673 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +#include +#include + +/* ============================================================================================== */ +/* Internal macros */ +/* ============================================================================================== */ + +/** + * Returns a pointer to the data of the given `node`. + * + * @param node A pointer to the `ZyanNodeData` struct. + * + * @return A pointer to the data of the given `node`. + */ +#define ZYCORE_LIST_GET_NODE_DATA(node) \ + ((void*)(node + 1)) + +/* ============================================================================================== */ +/* Internal functions */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Helper functions */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Allocates memory for a new list node. + * + * @param list A pointer to the `ZyanList` instance. + * @param node Receives a pointer to the new `ZyanListNode` struct. + * + * @return A zyan status code. + */ +static ZyanStatus ZyanListAllocateNode(ZyanList* list, ZyanListNode** node) +{ + ZYAN_ASSERT(list); + ZYAN_ASSERT(node); + + const ZyanBool is_dynamic = (list->allocator != ZYAN_NULL); + if (is_dynamic) + { + ZYAN_ASSERT(list->allocator->allocate); + ZYAN_CHECK(list->allocator->allocate(list->allocator, (void**)node, + sizeof(ZyanListNode) + list->element_size, 1)); + } else + { + if (list->first_unused) + { + *node = list->first_unused; + list->first_unused = (*node)->next; + } else + { + const ZyanUSize size = list->size * (sizeof(ZyanListNode) + list->element_size); + if (size + (sizeof(ZyanListNode) + list->element_size) > list->capacity) + { + return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE; + } + + *node = (ZyanListNode*)((ZyanU8*)list->buffer + size); + } + } + + return ZYAN_STATUS_SUCCESS; +} + +/** + * Frees memory of a node. + * + * @param list A pointer to the `ZyanList` instance. + * @param node A pointer to the `ZyanListNode` struct. + * + * @return A zyan status code. + */ +static ZyanStatus ZyanListDeallocateNode(ZyanList* list, ZyanListNode* node) +{ + ZYAN_ASSERT(list); + ZYAN_ASSERT(node); + + const ZyanBool is_dynamic = (list->allocator != ZYAN_NULL); + if (is_dynamic) + { + ZYAN_ASSERT(list->allocator->deallocate); + ZYAN_CHECK(list->allocator->deallocate(list->allocator, (void*)node, + sizeof(ZyanListNode) + list->element_size, 1)); + } else + { + node->next = list->first_unused; + list->first_unused = node; + } + + return ZYAN_STATUS_SUCCESS; +} + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Constructor and destructor */ +/* ---------------------------------------------------------------------------------------------- */ + +#ifndef ZYAN_NO_LIBC + +ZYAN_REQUIRES_LIBC ZyanStatus ZyanListInit(ZyanList* list, ZyanUSize element_size, + ZyanMemberProcedure destructor) +{ + return ZyanListInitEx(list, element_size, destructor, ZyanAllocatorDefault()); +} + +#endif // ZYAN_NO_LIBC + +ZyanStatus ZyanListInitEx(ZyanList* list, ZyanUSize element_size, ZyanMemberProcedure destructor, + ZyanAllocator* allocator) +{ + if (!list || !element_size || !allocator) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + list->allocator = allocator; + list->size = 0; + list->element_size = element_size; + list->destructor = destructor; + list->head = ZYAN_NULL; + list->tail = ZYAN_NULL; + list->buffer = ZYAN_NULL; + list->capacity = 0; + list->first_unused = ZYAN_NULL; + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanListInitCustomBuffer(ZyanList* list, ZyanUSize element_size, + ZyanMemberProcedure destructor, void* buffer, ZyanUSize capacity) +{ + if (!list || !element_size || !buffer || !capacity) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + list->allocator = ZYAN_NULL; + list->size = 0; + list->element_size = element_size; + list->destructor = destructor; + list->head = ZYAN_NULL; + list->tail = ZYAN_NULL; + list->buffer = buffer; + list->capacity = capacity; + list->first_unused = ZYAN_NULL; + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanListDestroy(ZyanList* list) +{ + if (!list) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + ZYAN_ASSERT(list->element_size); + + const ZyanBool is_dynamic = (list->allocator != ZYAN_NULL); + ZyanListNode* node = (is_dynamic || list->destructor) ? list->head : ZYAN_NULL; + while (node) + { + if (list->destructor) + { + list->destructor(ZYCORE_LIST_GET_NODE_DATA(node)); + } + + ZyanListNode* const next = node->next; + + if (is_dynamic) + { + ZYAN_CHECK(list->allocator->deallocate(list->allocator, node, + sizeof(ZyanListNode) + list->element_size, 1)); + } + + node = next; + } + + return ZYAN_STATUS_SUCCESS; +} + +/* ---------------------------------------------------------------------------------------------- */ +/* Duplication */ +/* ---------------------------------------------------------------------------------------------- */ + + + +/* ---------------------------------------------------------------------------------------------- */ +/* Item access */ +/* ---------------------------------------------------------------------------------------------- */ + +ZyanStatus ZyanListGetHeadNode(const ZyanList* list, const ZyanListNode** node) +{ + if (!list) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + *node = list->head; + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanListGetTailNode(const ZyanList* list, const ZyanListNode** node) +{ + if (!list) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + *node = list->tail; + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanListGetPrevNode(const ZyanListNode** node) +{ + if (!node || !*node) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + *node = (*node)->prev; + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanListGetNextNode(const ZyanListNode** node) +{ + if (!node || !*node) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + *node = (*node)->next; + + return ZYAN_STATUS_SUCCESS; +} + +const void* ZyanListGetNodeData(const ZyanListNode* node) +{ + if (!node) + { + return ZYAN_NULL; + } + + return (const void*)ZYCORE_LIST_GET_NODE_DATA(node); +} + +ZyanStatus ZyanListGetNodeDataEx(const ZyanListNode* node, const void** value) +{ + if (!node) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + *value = (const void*)ZYCORE_LIST_GET_NODE_DATA(node); + + return ZYAN_STATUS_SUCCESS; +} + +void* ZyanListGetNodeDataMutable(const ZyanListNode* node) +{ + if (!node) + { + return ZYAN_NULL; + } + + return ZYCORE_LIST_GET_NODE_DATA(node); +} + +ZyanStatus ZyanListGetNodeDataMutableEx(const ZyanListNode* node, void** value) +{ + if (!node) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + *value = ZYCORE_LIST_GET_NODE_DATA(node); + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanListSetNodeData(const ZyanList* list, const ZyanListNode* node, const void* value) +{ + if (!list || !node || !value) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + if (list->destructor) + { + list->destructor(ZYCORE_LIST_GET_NODE_DATA(node)); + } + + ZYAN_ASSERT(list->element_size); + ZYAN_MEMCPY(ZYCORE_LIST_GET_NODE_DATA(node), value, list->element_size); + + return ZYAN_STATUS_SUCCESS; +} + +/* ---------------------------------------------------------------------------------------------- */ +/* Insertion */ +/* ---------------------------------------------------------------------------------------------- */ + +ZyanStatus ZyanListPushBack(ZyanList* list, const void* item) +{ + if (!list || !item) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + ZyanListNode* node; + ZYAN_CHECK(ZyanListAllocateNode(list, &node)); + node->prev = list->tail; + node->next = ZYAN_NULL; + + ZYAN_MEMCPY(ZYCORE_LIST_GET_NODE_DATA(node), item, list->element_size); + + if (!list->head) + { + list->head = node; + list->tail = node; + } else + { + list->tail->next = node; + list->tail = node; + } + ++list->size; + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanListPushFront(ZyanList* list, const void* item) +{ + if (!list || !item) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + ZyanListNode* node; + ZYAN_CHECK(ZyanListAllocateNode(list, &node)); + node->prev = ZYAN_NULL; + node->next = list->head; + + ZYAN_MEMCPY(ZYCORE_LIST_GET_NODE_DATA(node), item, list->element_size); + + if (!list->head) + { + list->head = node; + list->tail = node; + } else + { + list->head->prev= node; + list->head = node; + } + ++list->size; + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanListEmplaceBack(ZyanList* list, void** item, ZyanMemberFunction constructor) +{ + if (!list || !item) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + ZyanListNode* node; + ZYAN_CHECK(ZyanListAllocateNode(list, &node)); + node->prev = list->tail; + node->next = ZYAN_NULL; + + *item = ZYCORE_LIST_GET_NODE_DATA(node); + if (constructor) + { + constructor(*item); + } + + if (!list->head) + { + list->head = node; + list->tail = node; + } else + { + list->tail->next = node; + list->tail = node; + } + ++list->size; + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanListEmplaceFront(ZyanList* list, void** item, ZyanMemberFunction constructor) +{ + if (!list || !item) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + ZyanListNode* node; + ZYAN_CHECK(ZyanListAllocateNode(list, &node)); + node->prev = ZYAN_NULL; + node->next = list->head; + + *item = ZYCORE_LIST_GET_NODE_DATA(node); + if (constructor) + { + constructor(*item); + } + + if (!list->head) + { + list->head = node; + list->tail = node; + } else + { + list->head->prev= node; + list->head = node; + } + ++list->size; + + return ZYAN_STATUS_SUCCESS; +} + +/* ---------------------------------------------------------------------------------------------- */ +/* Deletion */ +/* ---------------------------------------------------------------------------------------------- */ + +ZyanStatus ZyanListPopBack(ZyanList* list) +{ + if (!list) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + if (!list->tail) + { + return ZYAN_STATUS_INVALID_OPERATION; + } + + ZyanListNode* const node = list->tail; + + if (list->destructor) + { + list->destructor(ZYCORE_LIST_GET_NODE_DATA(node)); + } + + list->tail = node->prev; + if (list->tail) + { + list->tail->next = ZYAN_NULL; + } + if (list->head == node) + { + list->head = list->tail; + } + --list->size; + + return ZyanListDeallocateNode(list, node); +} + +ZyanStatus ZyanListPopFront(ZyanList* list) +{ + if (!list) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + if (!list->head) + { + return ZYAN_STATUS_INVALID_OPERATION; + } + + ZyanListNode* const node = list->head; + + if (list->destructor) + { + list->destructor(ZYCORE_LIST_GET_NODE_DATA(node)); + } + + list->head = node->next; + if (list->head) + { + list->head->prev = ZYAN_NULL; + } + if (list->tail == node) + { + list->tail = list->head; + } + --list->size; + + return ZyanListDeallocateNode(list, node); +} + +ZyanStatus ZyanListRemove(ZyanList* list, const ZyanListNode* node) +{ + ZYAN_UNUSED(list); + ZYAN_UNUSED(node); + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanListRemoveRange(ZyanList* list, const ZyanListNode* first, const ZyanListNode* last) +{ + ZYAN_UNUSED(list); + ZYAN_UNUSED(first); + ZYAN_UNUSED(last); + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanListClear(ZyanList* list) +{ + return ZyanListResizeEx(list, 0, ZYAN_NULL); +} + +/* ---------------------------------------------------------------------------------------------- */ +/* Searching */ +/* ---------------------------------------------------------------------------------------------- */ + + + +/* ---------------------------------------------------------------------------------------------- */ +/* Memory management */ +/* ---------------------------------------------------------------------------------------------- */ + +ZyanStatus ZyanListResize(ZyanList* list, ZyanUSize size) +{ + return ZyanListResizeEx(list, size, ZYAN_NULL); +} + +ZyanStatus ZyanListResizeEx(ZyanList* list, ZyanUSize size, const void* initializer) +{ + if (!list) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + if (size == list->size) + { + return ZYAN_STATUS_SUCCESS; + } + + if (size == 0) + { + const ZyanBool is_dynamic = (list->allocator != ZYAN_NULL); + ZyanListNode* node = (is_dynamic || list->destructor) ? list->head : ZYAN_NULL; + while (node) + { + if (list->destructor) + { + list->destructor(ZYCORE_LIST_GET_NODE_DATA(node)); + } + + ZyanListNode* const next = node->next; + + if (is_dynamic) + { + ZYAN_CHECK(list->allocator->deallocate(list->allocator, node, + sizeof(ZyanListNode) + list->element_size, 1)); + } + + node = next; + } + + list->size = 0; + list->head = 0; + list->tail = 0; + list->first_unused = ZYAN_NULL; + + return ZYAN_STATUS_SUCCESS; + } + + if (size > list->size) + { + ZyanListNode* node; + for (ZyanUSize i = list->size; i < size; ++i) + { + ZYAN_CHECK(ZyanListAllocateNode(list, &node)); + node->prev = list->tail; + node->next = ZYAN_NULL; + + if (initializer) + { + ZYAN_MEMCPY(ZYCORE_LIST_GET_NODE_DATA(node), initializer, list->element_size); + } + + if (!list->head) + { + list->head = node; + list->tail = node; + } else + { + list->tail->next = node; + list->tail = node; + } + + // `ZyanListAllocateNode` needs the list size + ++list->size; + } + } else + { + for (ZyanUSize i = size; i < list->size; ++i) + { + ZyanListNode* const node = list->tail; + + if (list->destructor) + { + list->destructor(ZYCORE_LIST_GET_NODE_DATA(node)); + } + + list->tail = node->prev; + if (list->tail) + { + list->tail->next = ZYAN_NULL; + } + + ZYAN_CHECK(ZyanListDeallocateNode(list, node)); + } + + list->size = size; + } + + return ZYAN_STATUS_SUCCESS; +} + +/* ---------------------------------------------------------------------------------------------- */ +/* Information */ +/* ---------------------------------------------------------------------------------------------- */ + +ZyanStatus ZyanListGetSize(const ZyanList* list, ZyanUSize* size) +{ + if (!list) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + *size = list->size; + + return ZYAN_STATUS_SUCCESS; +} + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ diff --git a/zycore/src/String.c b/zycore/src/String.c new file mode 100644 index 0000000..9dce43f --- /dev/null +++ b/zycore/src/String.c @@ -0,0 +1,1098 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +#include +#include + +/* ============================================================================================== */ +/* Internal macros */ +/* ============================================================================================== */ + +/** + * Writes a terminating '\0' character at the end of the string data. + */ +#define ZYCORE_STRING_NULLTERMINATE(string) \ + *(char*)((ZyanU8*)(string)->vector.data + (string)->vector.size - 1) = '\0'; + +/** + * Checks for a terminating '\0' character at the end of the string data. + */ +#define ZYCORE_STRING_ASSERT_NULLTERMINATION(string) \ + ZYAN_ASSERT(*(char*)((ZyanU8*)(string)->vector.data + (string)->vector.size - 1) == '\0'); + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Constructor and destructor */ +/* ---------------------------------------------------------------------------------------------- */ + +#ifndef ZYAN_NO_LIBC + +ZyanStatus ZyanStringInit(ZyanString* string, ZyanUSize capacity) +{ + return ZyanStringInitEx(string, capacity, ZyanAllocatorDefault(), + ZYAN_STRING_DEFAULT_GROWTH_FACTOR, ZYAN_STRING_DEFAULT_SHRINK_THRESHOLD); +} + +#endif // ZYAN_NO_LIBC + +ZyanStatus ZyanStringInitEx(ZyanString* string, ZyanUSize capacity, ZyanAllocator* allocator, + ZyanU8 growth_factor, ZyanU8 shrink_threshold) +{ + if (!string) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + string->flags = 0; + capacity = ZYAN_MAX(ZYAN_STRING_MIN_CAPACITY, capacity) + 1; + ZYAN_CHECK(ZyanVectorInitEx(&string->vector, sizeof(char), capacity, ZYAN_NULL, allocator, + growth_factor, shrink_threshold)); + ZYAN_ASSERT(string->vector.capacity >= capacity); + // Some of the string code relies on `sizeof(char) == 1` + ZYAN_ASSERT(string->vector.element_size == 1); + + *(char*)string->vector.data = '\0'; + ++string->vector.size; + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanStringInitCustomBuffer(ZyanString* string, char* buffer, ZyanUSize capacity) +{ + if (!string || !capacity) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + string->flags = ZYAN_STRING_HAS_FIXED_CAPACITY; + ZYAN_CHECK(ZyanVectorInitCustomBuffer(&string->vector, sizeof(char), (void*)buffer, capacity, + ZYAN_NULL)); + ZYAN_ASSERT(string->vector.capacity == capacity); + // Some of the string code relies on `sizeof(char) == 1` + ZYAN_ASSERT(string->vector.element_size == 1); + + *(char*)string->vector.data = '\0'; + ++string->vector.size; + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanStringDestroy(ZyanString* string) +{ + if (!string) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + if (string->flags & ZYAN_STRING_HAS_FIXED_CAPACITY) + { + return ZYAN_STATUS_SUCCESS; + } + + return ZyanVectorDestroy(&string->vector); +} + +/* ---------------------------------------------------------------------------------------------- */ +/* Duplication */ +/* ---------------------------------------------------------------------------------------------- */ + +#ifndef ZYAN_NO_LIBC + +ZyanStatus ZyanStringDuplicate(ZyanString* destination, const ZyanStringView* source, + ZyanUSize capacity) +{ + return ZyanStringDuplicateEx(destination, source, capacity, ZyanAllocatorDefault(), + ZYAN_STRING_DEFAULT_GROWTH_FACTOR, ZYAN_STRING_DEFAULT_SHRINK_THRESHOLD); +} + +#endif // ZYAN_NO_LIBC + +ZyanStatus ZyanStringDuplicateEx(ZyanString* destination, const ZyanStringView* source, + ZyanUSize capacity, ZyanAllocator* allocator, ZyanU8 growth_factor, ZyanU8 shrink_threshold) +{ + if (!source || !source->string.vector.size) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + const ZyanUSize len = source->string.vector.size; + capacity = ZYAN_MAX(capacity, len - 1); + ZYAN_CHECK(ZyanStringInitEx(destination, capacity, allocator, growth_factor, shrink_threshold)); + ZYAN_ASSERT(destination->vector.capacity >= len); + + ZYAN_MEMCPY(destination->vector.data, source->string.vector.data, + source->string.vector.size - 1); + destination->vector.size = len; + ZYCORE_STRING_NULLTERMINATE(destination); + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanStringDuplicateCustomBuffer(ZyanString* destination, const ZyanStringView* source, + char* buffer, ZyanUSize capacity) +{ + if (!source || !source->string.vector.size) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + const ZyanUSize len = source->string.vector.size; + if (capacity < len) + { + return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE; + } + + ZYAN_CHECK(ZyanStringInitCustomBuffer(destination, buffer, capacity)); + ZYAN_ASSERT(destination->vector.capacity >= len); + + ZYAN_MEMCPY(destination->vector.data, source->string.vector.data, + source->string.vector.size - 1); + destination->vector.size = len; + ZYCORE_STRING_NULLTERMINATE(destination); + + return ZYAN_STATUS_SUCCESS; +} + +/* ---------------------------------------------------------------------------------------------- */ +/* Concatenation */ +/* ---------------------------------------------------------------------------------------------- */ + +#ifndef ZYAN_NO_LIBC + +ZyanStatus ZyanStringConcat(ZyanString* destination, const ZyanStringView* s1, + const ZyanStringView* s2, ZyanUSize capacity) +{ + return ZyanStringConcatEx(destination, s1, s2, capacity, ZyanAllocatorDefault(), + ZYAN_STRING_DEFAULT_GROWTH_FACTOR, ZYAN_STRING_DEFAULT_SHRINK_THRESHOLD); +} + +#endif // ZYAN_NO_LIBC + +ZyanStatus ZyanStringConcatEx(ZyanString* destination, const ZyanStringView* s1, + const ZyanStringView* s2, ZyanUSize capacity, ZyanAllocator* allocator, ZyanU8 growth_factor, + ZyanU8 shrink_threshold) +{ + if (!s1 || !s2 || !s1->string.vector.size || !s2->string.vector.size) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + const ZyanUSize len = s1->string.vector.size + s2->string.vector.size - 1; + capacity = ZYAN_MAX(capacity, len - 1); + ZYAN_CHECK(ZyanStringInitEx(destination, capacity, allocator, growth_factor, shrink_threshold)); + ZYAN_ASSERT(destination->vector.capacity >= len); + + ZYAN_MEMCPY(destination->vector.data, s1->string.vector.data, s1->string.vector.size - 1); + ZYAN_MEMCPY((char*)destination->vector.data + s1->string.vector.size - 1, + s2->string.vector.data, s2->string.vector.size - 1); + destination->vector.size = len; + ZYCORE_STRING_NULLTERMINATE(destination); + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanStringConcatCustomBuffer(ZyanString* destination, const ZyanStringView* s1, + const ZyanStringView* s2, char* buffer, ZyanUSize capacity) +{ + if (!s1 || !s2 || !s1->string.vector.size || !s2->string.vector.size) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + const ZyanUSize len = s1->string.vector.size + s2->string.vector.size - 1; + if (capacity < len) + { + return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE; + } + + ZYAN_CHECK(ZyanStringInitCustomBuffer(destination, buffer, capacity)); + ZYAN_ASSERT(destination->vector.capacity >= len); + + ZYAN_MEMCPY(destination->vector.data, s1->string.vector.data, s1->string.vector.size - 1); + ZYAN_MEMCPY((char*)destination->vector.data + s1->string.vector.size - 1, + s2->string.vector.data, s2->string.vector.size - 1); + destination->vector.size = len; + ZYCORE_STRING_NULLTERMINATE(destination); + + return ZYAN_STATUS_SUCCESS; +} + +/* ---------------------------------------------------------------------------------------------- */ +/* Views */ +/* ---------------------------------------------------------------------------------------------- */ + +ZyanStatus ZyanStringViewInsideView(ZyanStringView* view, const ZyanStringView* source) +{ + if (!view || !source) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + view->string.vector.data = source->string.vector.data; + view->string.vector.size = source->string.vector.size; + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanStringViewInsideViewEx(ZyanStringView* view, const ZyanStringView* source, + ZyanUSize index, ZyanUSize count) +{ + if (!view || !source) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + if (index + count >= source->string.vector.size) + { + return ZYAN_STATUS_OUT_OF_RANGE; + } + + view->string.vector.data = (void*)((char*)source->string.vector.data + index); + view->string.vector.size = count; + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanStringViewInsideBuffer(ZyanStringView* view, const char* string) +{ + if (!view || !string) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + view->string.vector.data = (void*)string; + view->string.vector.size = ZYAN_STRLEN(string) + 1; + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanStringViewInsideBufferEx(ZyanStringView* view, const char* buffer, ZyanUSize length) +{ + if (!view || !buffer || !length) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + view->string.vector.data = (void*)buffer; + view->string.vector.size = length + 1; + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanStringViewGetSize(const ZyanStringView* view, ZyanUSize* size) +{ + if (!view || !size) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + ZYAN_ASSERT(view->string.vector.size >= 1); + *size = view->string.vector.size - 1; + + return ZYAN_STATUS_SUCCESS; +} + +ZYCORE_EXPORT ZyanStatus ZyanStringViewGetData(const ZyanStringView* view, const char** buffer) +{ + if (!view || !buffer) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + *buffer = view->string.vector.data; + + return ZYAN_STATUS_SUCCESS; +} + +/* ---------------------------------------------------------------------------------------------- */ +/* Character access */ +/* ---------------------------------------------------------------------------------------------- */ + +ZyanStatus ZyanStringGetChar(const ZyanStringView* string, ZyanUSize index, char* value) +{ + if (!string || !value) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + // Don't allow direct access to the terminating '\0' character + if (index + 1 >= string->string.vector.size) + { + return ZYAN_STATUS_OUT_OF_RANGE; + } + + const char* chr; + ZYAN_CHECK(ZyanVectorGetPointer(&string->string.vector, index, (const void**)&chr)); + *value = *chr; + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanStringGetCharMutable(ZyanString* string, ZyanUSize index, char** value) +{ + if (!string) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + // Don't allow direct access to the terminating '\0' character + if (index + 1 >= string->vector.size) + { + return ZYAN_STATUS_OUT_OF_RANGE; + } + + return ZyanVectorGetPointerMutable(&string->vector, index, (void**)value); +} + +ZyanStatus ZyanStringSetChar(ZyanString* string, ZyanUSize index, char value) +{ + if (!string) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + // Don't allow direct access to the terminating '\0' character + if (index + 1 >= string->vector.size) + { + return ZYAN_STATUS_OUT_OF_RANGE; + } + + return ZyanVectorSet(&string->vector, index, (void*)&value); +} + +/* ---------------------------------------------------------------------------------------------- */ +/* Insertion */ +/* ---------------------------------------------------------------------------------------------- */ + +ZyanStatus ZyanStringInsert(ZyanString* destination, ZyanUSize index, const ZyanStringView* source) +{ + if (!destination || !source || !source->string.vector.size) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + if (index == destination->vector.size) + { + return ZyanStringAppend(destination, source); + } + + // Don't allow insertion after the terminating '\0' character + if (index >= destination->vector.size) + { + return ZYAN_STATUS_OUT_OF_RANGE; + } + + ZYAN_CHECK(ZyanVectorInsertRange(&destination->vector, index, source->string.vector.data, + source->string.vector.size - 1)); + ZYCORE_STRING_ASSERT_NULLTERMINATION(destination); + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanStringInsertEx(ZyanString* destination, ZyanUSize destination_index, + const ZyanStringView* source, ZyanUSize source_index, ZyanUSize count) +{ + if (!destination || !source || !source->string.vector.size) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + if (destination_index == destination->vector.size) + { + return ZyanStringAppendEx(destination, source, source_index, count); + } + + // Don't allow insertion after the terminating '\0' character + if (destination_index >= destination->vector.size) + { + return ZYAN_STATUS_OUT_OF_RANGE; + } + + // Don't allow access to the terminating '\0' character + if (source_index + count >= source->string.vector.size) + { + return ZYAN_STATUS_OUT_OF_RANGE; + } + + ZYAN_CHECK(ZyanVectorInsertRange(&destination->vector, destination_index, + (char*)source->string.vector.data + source_index, count)); + ZYCORE_STRING_ASSERT_NULLTERMINATION(destination); + + return ZYAN_STATUS_SUCCESS; +} + +/* ---------------------------------------------------------------------------------------------- */ +/* Appending */ +/* ---------------------------------------------------------------------------------------------- */ + +ZyanStatus ZyanStringAppend(ZyanString* destination, const ZyanStringView* source) +{ + if (!destination || !source || !source->string.vector.size) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + const ZyanUSize len = destination->vector.size; + ZYAN_CHECK(ZyanVectorResize(&destination->vector, len + source->string.vector.size - 1)); + ZYAN_MEMCPY((char*)destination->vector.data + len - 1, source->string.vector.data, + source->string.vector.size - 1); + ZYCORE_STRING_NULLTERMINATE(destination); + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanStringAppendEx(ZyanString* destination, const ZyanStringView* source, + ZyanUSize source_index, ZyanUSize count) +{ + if (!destination || !source || !source->string.vector.size) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + // Don't allow access to the terminating '\0' character + if (source_index + count >= source->string.vector.size) + { + return ZYAN_STATUS_OUT_OF_RANGE; + } + + const ZyanUSize len = destination->vector.size; + ZYAN_CHECK(ZyanVectorResize(&destination->vector, len + count)); + ZYAN_MEMCPY((char*)destination->vector.data + len - 1, + (const char*)source->string.vector.data + source_index, count); + ZYCORE_STRING_NULLTERMINATE(destination); + + return ZYAN_STATUS_SUCCESS; +} + +/* ---------------------------------------------------------------------------------------------- */ +/* Deletion */ +/* ---------------------------------------------------------------------------------------------- */ + +ZyanStatus ZyanStringDelete(ZyanString* string, ZyanUSize index, ZyanUSize count) +{ + if (!string) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + // Don't allow removal of the terminating '\0' character + if (index + count >= string->vector.size) + { + return ZYAN_STATUS_OUT_OF_RANGE; + } + + ZYAN_CHECK(ZyanVectorDeleteRange(&string->vector, index, count)); + ZYCORE_STRING_NULLTERMINATE(string); + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanStringTruncate(ZyanString* string, ZyanUSize index) +{ + if (!string) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + // Don't allow removal of the terminating '\0' character + if (index >= string->vector.size) + { + return ZYAN_STATUS_OUT_OF_RANGE; + } + + ZYAN_CHECK(ZyanVectorDeleteRange(&string->vector, index, string->vector.size - index - 1)); + ZYCORE_STRING_NULLTERMINATE(string); + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanStringClear(ZyanString* string) +{ + if (!string) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + ZYAN_CHECK(ZyanVectorClear(&string->vector)); + // `ZyanVector` guarantees a minimum capacity of 1 element/character + ZYAN_ASSERT(string->vector.capacity >= 1); + + *(char*)string->vector.data = '\0'; + string->vector.size++; + + return ZYAN_STATUS_SUCCESS; +} + +/* ---------------------------------------------------------------------------------------------- */ +/* Searching */ +/* ---------------------------------------------------------------------------------------------- */ + +ZyanStatus ZyanStringLPos(const ZyanStringView* haystack, const ZyanStringView* needle, + ZyanISize* found_index) +{ + if (!haystack) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + return ZyanStringLPosEx(haystack, needle, found_index, 0, haystack->string.vector.size - 1); +} + +ZyanStatus ZyanStringLPosEx(const ZyanStringView* haystack, const ZyanStringView* needle, + ZyanISize* found_index, ZyanUSize index, ZyanUSize count) +{ + if (!haystack || !needle || !found_index) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + // Don't allow access to the terminating '\0' character + if (index + count >= haystack->string.vector.size) + { + return ZYAN_STATUS_OUT_OF_RANGE; + } + + if ((haystack->string.vector.size == 1) || (needle->string.vector.size == 1) || + (haystack->string.vector.size < needle->string.vector.size)) + { + *found_index = -1; + return ZYAN_STATUS_FALSE; + } + + const char* s = (const char*)haystack->string.vector.data + index; + const char* b = (const char*)needle->string.vector.data; + for (; s + 1 < (const char*)haystack->string.vector.data + haystack->string.vector.size; ++s) + { + if (*s != *b) + { + continue; + } + const char* a = s; + for (;;) + { + if ((ZyanUSize)(a - (const char*)haystack->string.vector.data) > index + count) + { + *found_index = -1; + return ZYAN_STATUS_FALSE; + } + if (*b == 0) + { + *found_index = (ZyanISize)(s - (const char*)haystack->string.vector.data); + return ZYAN_STATUS_TRUE; + } + if (*a++ != *b++) + { + break; + } + } + b = (char*)needle->string.vector.data; + } + + *found_index = -1; + return ZYAN_STATUS_FALSE; +} + +ZyanStatus ZyanStringLPosI(const ZyanStringView* haystack, const ZyanStringView* needle, + ZyanISize* found_index) +{ + if (!haystack) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + return ZyanStringLPosIEx(haystack, needle, found_index, 0, haystack->string.vector.size - 1); +} + +ZyanStatus ZyanStringLPosIEx(const ZyanStringView* haystack, const ZyanStringView* needle, + ZyanISize* found_index, ZyanUSize index, ZyanUSize count) +{ + // This solution assumes that characters are represented using ASCII representation, i.e., + // codes for 'a', 'b', 'c', .. 'z' are 97, 98, 99, .. 122 respectively. And codes for 'A', + // 'B', 'C', .. 'Z' are 65, 66, .. 95 respectively. + + if (!haystack || !needle || !found_index) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + // Don't allow access to the terminating '\0' character + if (index + count >= haystack->string.vector.size) + { + return ZYAN_STATUS_OUT_OF_RANGE; + } + + if ((haystack->string.vector.size == 1) || (needle->string.vector.size == 1) || + (haystack->string.vector.size < needle->string.vector.size)) + { + *found_index = -1; + return ZYAN_STATUS_FALSE; + } + + const char* s = (const char*)haystack->string.vector.data + index; + const char* b = (const char*)needle->string.vector.data; + for (; s + 1 < (const char*)haystack->string.vector.data + haystack->string.vector.size; ++s) + { + if ((*s != *b) && ((*s ^ 32) != *b)) + { + continue; + } + const char* a = s; + for (;;) + { + if ((ZyanUSize)(a - (const char*)haystack->string.vector.data) > index + count) + { + *found_index = -1; + return ZYAN_STATUS_FALSE; + } + if (*b == 0) + { + *found_index = (ZyanISize)(s - (const char*)haystack->string.vector.data); + return ZYAN_STATUS_TRUE; + } + const char c1 = *a++; + const char c2 = *b++; + if ((c1 != c2) && ((c1 ^ 32) != c2)) + { + break; + } + } + b = (char*)needle->string.vector.data; + } + + *found_index = -1; + return ZYAN_STATUS_FALSE; +} + +ZyanStatus ZyanStringRPos(const ZyanStringView* haystack, const ZyanStringView* needle, + ZyanISize* found_index) +{ + if (!haystack) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + return ZyanStringRPosEx(haystack, needle, found_index, haystack->string.vector.size - 1, + haystack->string.vector.size - 1); +} + +ZyanStatus ZyanStringRPosEx(const ZyanStringView* haystack, const ZyanStringView* needle, + ZyanISize* found_index, ZyanUSize index, ZyanUSize count) +{ + if (!haystack || !needle || !found_index) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + // Don't allow access to the terminating '\0' character + if ((index >= haystack->string.vector.size) || (count > index)) + { + return ZYAN_STATUS_OUT_OF_RANGE; + } + + if (!index || !count || + (haystack->string.vector.size == 1) || (needle->string.vector.size == 1) || + (haystack->string.vector.size < needle->string.vector.size)) + { + *found_index = -1; + return ZYAN_STATUS_FALSE; + } + + const char* s = (const char*)haystack->string.vector.data + index - 1; + const char* b = (const char*)needle->string.vector.data + needle->string.vector.size - 2; + for (; s >= (const char*)haystack->string.vector.data; --s) + { + if (*s != *b) + { + continue; + } + const char* a = s; + for (;;) + { + if (b < (const char*)needle->string.vector.data) + { + *found_index = (ZyanISize)(a - (const char*)haystack->string.vector.data + 1); + return ZYAN_STATUS_TRUE; + } + if (a < (const char*)haystack->string.vector.data + index - count) + { + *found_index = -1; + return ZYAN_STATUS_FALSE; + } + if (*a-- != *b--) + { + break; + } + } + b = (char*)needle->string.vector.data + needle->string.vector.size - 2; + } + + *found_index = -1; + return ZYAN_STATUS_FALSE; +} + +ZyanStatus ZyanStringRPosI(const ZyanStringView* haystack, const ZyanStringView* needle, + ZyanISize* found_index) +{ + if (!haystack) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + return ZyanStringRPosIEx(haystack, needle, found_index, haystack->string.vector.size - 1, + haystack->string.vector.size - 1); +} + +ZyanStatus ZyanStringRPosIEx(const ZyanStringView* haystack, const ZyanStringView* needle, + ZyanISize* found_index, ZyanUSize index, ZyanUSize count) +{ + // This solution assumes that characters are represented using ASCII representation, i.e., + // codes for 'a', 'b', 'c', .. 'z' are 97, 98, 99, .. 122 respectively. And codes for 'A', + // 'B', 'C', .. 'Z' are 65, 66, .. 95 respectively. + + if (!haystack || !needle || !found_index) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + // Don't allow access to the terminating '\0' character + if ((index >= haystack->string.vector.size) || (count > index)) + { + return ZYAN_STATUS_OUT_OF_RANGE; + } + + if (!index || !count || + (haystack->string.vector.size == 1) || (needle->string.vector.size == 1) || + (haystack->string.vector.size < needle->string.vector.size)) + { + *found_index = -1; + return ZYAN_STATUS_FALSE; + } + + const char* s = (const char*)haystack->string.vector.data + index - 1; + const char* b = (const char*)needle->string.vector.data + needle->string.vector.size - 2; + for (; s >= (const char*)haystack->string.vector.data; --s) + { + if ((*s != *b) && ((*s ^ 32) != *b)) + { + continue; + } + const char* a = s; + for (;;) + { + if (b < (const char*)needle->string.vector.data) + { + *found_index = (ZyanISize)(a - (const char*)haystack->string.vector.data + 1); + return ZYAN_STATUS_TRUE; + } + if (a < (const char*)haystack->string.vector.data + index - count) + { + *found_index = -1; + return ZYAN_STATUS_FALSE; + } + const char c1 = *a--; + const char c2 = *b--; + if ((c1 != c2) && ((c1 ^ 32) != c2)) + { + break; + } + } + b = (char*)needle->string.vector.data + needle->string.vector.size - 2; + } + + *found_index = -1; + return ZYAN_STATUS_FALSE; +} + +/* ---------------------------------------------------------------------------------------------- */ +/* Comparing */ +/* ---------------------------------------------------------------------------------------------- */ + +ZyanStatus ZyanStringCompare(const ZyanStringView* s1, const ZyanStringView* s2, ZyanI32* result) +{ + if (!s1 || !s2) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + if (s1->string.vector.size < s2->string.vector.size) + { + *result = -1; + return ZYAN_STATUS_FALSE; + } + if (s1->string.vector.size > s2->string.vector.size) + { + *result = 1; + return ZYAN_STATUS_FALSE; + } + + const char* const a = (char*)s1->string.vector.data; + const char* const b = (char*)s2->string.vector.data; + ZyanUSize i; + for (i = 0; (i + 1 < s1->string.vector.size) && (i + 1 < s2->string.vector.size); ++i) + { + if (a[i] == b[i]) + { + continue; + } + break; + } + + if (a[i] == b[i]) + { + *result = 0; + return ZYAN_STATUS_TRUE; + } + + if ((a[i] | 32) < (b[i] | 32)) + { + *result = -1; + return ZYAN_STATUS_FALSE; + } + + *result = 1; + return ZYAN_STATUS_FALSE; +} + +ZyanStatus ZyanStringCompareI(const ZyanStringView* s1, const ZyanStringView* s2, ZyanI32* result) +{ + // This solution assumes that characters are represented using ASCII representation, i.e., + // codes for 'a', 'b', 'c', .. 'z' are 97, 98, 99, .. 122 respectively. And codes for 'A', + // 'B', 'C', .. 'Z' are 65, 66, .. 95 respectively. + + if (!s1 || !s2) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + if (s1->string.vector.size < s2->string.vector.size) + { + *result = -1; + return ZYAN_STATUS_FALSE; + } + if (s1->string.vector.size > s2->string.vector.size) + { + *result = 1; + return ZYAN_STATUS_FALSE; + } + + const char* const a = (char*)s1->string.vector.data; + const char* const b = (char*)s2->string.vector.data; + ZyanUSize i; + for (i = 0; (i + 1 < s1->string.vector.size) && (i + 1 < s2->string.vector.size); ++i) + { + if ((a[i] == b[i]) || ((a[i] ^ 32) == b[i])) + { + continue; + } + break; + } + + if (a[i] == b[i]) + { + *result = 0; + return ZYAN_STATUS_TRUE; + } + + if ((a[i] | 32) < (b[i] | 32)) + { + *result = -1; + return ZYAN_STATUS_FALSE; + } + + *result = 1; + return ZYAN_STATUS_FALSE; +} + +/* ---------------------------------------------------------------------------------------------- */ +/* Case conversion */ +/* ---------------------------------------------------------------------------------------------- */ + +ZyanStatus ZyanStringToLowerCase(ZyanString* string) +{ + if (!string) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + return ZyanStringToLowerCaseEx(string, 0, string->vector.size - 1); +} + +ZyanStatus ZyanStringToLowerCaseEx(ZyanString* string, ZyanUSize index, ZyanUSize count) +{ + // This solution assumes that characters are represented using ASCII representation, i.e., + // codes for 'a', 'b', 'c', .. 'z' are 97, 98, 99, .. 122 respectively. And codes for 'A', + // 'B', 'C', .. 'Z' are 65, 66, .. 95 respectively. + + if (!string) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + // Don't allow access to the terminating '\0' character + if (index + count >= string->vector.size) + { + return ZYAN_STATUS_OUT_OF_RANGE; + } + + char* s = (char*)string->vector.data + index; + for (ZyanUSize i = index; i < index + count; ++i) + { + const char c = *s; + if ((c >= 'A') && (c <= 'Z')) + { + *s = c | 32; + } + ++s; + } + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanStringToUpperCase(ZyanString* string) +{ + if (!string) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + return ZyanStringToUpperCaseEx(string, 0, string->vector.size - 1); +} + +ZyanStatus ZyanStringToUpperCaseEx(ZyanString* string, ZyanUSize index, ZyanUSize count) +{ + // This solution assumes that characters are represented using ASCII representation, i.e., + // codes for 'a', 'b', 'c', .. 'z' are 97, 98, 99, .. 122 respectively. And codes for 'A', + // 'B', 'C', .. 'Z' are 65, 66, .. 95 respectively. + + if (!string) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + // Don't allow access to the terminating '\0' character + if (index + count >= string->vector.size) + { + return ZYAN_STATUS_OUT_OF_RANGE; + } + + char* s = (char*)string->vector.data + index; + for (ZyanUSize i = index; i < index + count; ++i) + { + const char c = *s; + if ((c >= 'a') && (c <= 'z')) + { + *s = c & ~32; + } + ++s; + } + + return ZYAN_STATUS_SUCCESS; +} + +/* ---------------------------------------------------------------------------------------------- */ +/* Memory management */ +/* ---------------------------------------------------------------------------------------------- */ + +ZyanStatus ZyanStringResize(ZyanString* string, ZyanUSize size) +{ + if (!string) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + ZYAN_CHECK(ZyanVectorResize(&string->vector, size + 1)); + ZYCORE_STRING_NULLTERMINATE(string); + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanStringReserve(ZyanString* string, ZyanUSize capacity) +{ + if (!string) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + return ZyanVectorReserve(&string->vector, capacity); +} + +ZyanStatus ZyanStringShrinkToFit(ZyanString* string) +{ + if (!string) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + return ZyanVectorShrinkToFit(&string->vector); +} + +/* ---------------------------------------------------------------------------------------------- */ +/* Information */ +/* ---------------------------------------------------------------------------------------------- */ + +ZyanStatus ZyanStringGetCapacity(const ZyanString* string, ZyanUSize* capacity) +{ + if (!string) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + ZYAN_ASSERT(string->vector.capacity >= 1); + *capacity = string->vector.capacity - 1; + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanStringGetSize(const ZyanString* string, ZyanUSize* size) +{ + if (!string) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + ZYAN_ASSERT(string->vector.size >= 1); + *size = string->vector.size - 1; + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanStringGetData(const ZyanString* string, const char** value) +{ + if (!string) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + *value = string->vector.data; + + return ZYAN_STATUS_SUCCESS; +} + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ diff --git a/zycore/src/Vector.c b/zycore/src/Vector.c new file mode 100644 index 0000000..f92c9de --- /dev/null +++ b/zycore/src/Vector.c @@ -0,0 +1,846 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +#include +#include + +/* ============================================================================================== */ +/* Internal macros */ +/* ============================================================================================== */ + +/** + * Checks, if the passed vector should grow. + * + * @param size The desired size of the vector. + * @param capacity The current capacity of the vector. + * + * @return `ZYAN_TRUE`, if the vector should grow or `ZYAN_FALSE`, if not. + */ +#define ZYCORE_VECTOR_SHOULD_GROW(size, capacity) \ + ((size) > (capacity)) + +/** + * Checks, if the passed vector should shrink. + * + * @param size The desired size of the vector. + * @param capacity The current capacity of the vector. + * @param threshold The shrink threshold. + * + * @return `ZYAN_TRUE`, if the vector should shrink or `ZYAN_FALSE`, if not. + */ +#define ZYCORE_VECTOR_SHOULD_SHRINK(size, capacity, threshold) \ + (((threshold) != 0) && ((size) * (threshold) < (capacity))) + +/** + * Returns the offset of the element at the given `index`. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param index The element index. + * + * @return The offset of the element at the given `index`. + */ +#define ZYCORE_VECTOR_OFFSET(vector, index) \ + ((void*)((ZyanU8*)(vector)->data + ((index) * (vector)->element_size))) + +/* ============================================================================================== */ +/* Internal functions */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Helper functions */ +/* ---------------------------------------------------------------------------------------------- */ + +/** + * Reallocates the internal buffer of the vector. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param capacity The new capacity. + * + * @return A zyan status code. + */ +static ZyanStatus ZyanVectorReallocate(ZyanVector* vector, ZyanUSize capacity) +{ + ZYAN_ASSERT(vector); + ZYAN_ASSERT(vector->capacity >= ZYAN_VECTOR_MIN_CAPACITY); + ZYAN_ASSERT(vector->element_size); + ZYAN_ASSERT(vector->data); + + if (!vector->allocator) + { + if (vector->capacity < capacity) + { + return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE; + } + return ZYAN_STATUS_SUCCESS; + } + + ZYAN_ASSERT(vector->allocator); + ZYAN_ASSERT(vector->allocator->reallocate); + + if (capacity < ZYAN_VECTOR_MIN_CAPACITY) + { + if (vector->capacity > ZYAN_VECTOR_MIN_CAPACITY) + { + capacity = ZYAN_VECTOR_MIN_CAPACITY; + } else + { + return ZYAN_STATUS_SUCCESS; + } + } + + vector->capacity = capacity; + ZYAN_CHECK(vector->allocator->reallocate(vector->allocator, &vector->data, + vector->element_size, vector->capacity)); + + return ZYAN_STATUS_SUCCESS; +} + +/** + * Shifts all elements starting at the specified `index` by the amount of `count` to the left. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param index The start index. + * @param count The amount of shift operations. + * + * @return A zyan status code. + */ +static ZyanStatus ZyanVectorShiftLeft(ZyanVector* vector, ZyanUSize index, ZyanUSize count) +{ + ZYAN_ASSERT(vector); + ZYAN_ASSERT(vector->element_size); + ZYAN_ASSERT(vector->data); + ZYAN_ASSERT(count > 0); + //ZYAN_ASSERT((ZyanISize)count - (ZyanISize)index + 1 >= 0); + + const void* const source = ZYCORE_VECTOR_OFFSET(vector, index + count); + void* const dest = ZYCORE_VECTOR_OFFSET(vector, index); + const ZyanUSize size = (vector->size - index - count) * vector->element_size; + ZYAN_MEMMOVE(dest, source, size); + + return ZYAN_STATUS_SUCCESS; +} + +/** + * Shifts all elements starting at the specified `index` by the amount of `count` to the right. + * + * @param vector A pointer to the `ZyanVector` instance. + * @param index The start index. + * @param count The amount of shift operations. + * + * @return A zyan status code. + */ +static ZyanStatus ZyanVectorShiftRight(ZyanVector* vector, ZyanUSize index, ZyanUSize count) +{ + ZYAN_ASSERT(vector); + ZYAN_ASSERT(vector->element_size); + ZYAN_ASSERT(vector->data); + ZYAN_ASSERT(count > 0); + ZYAN_ASSERT(vector->size + count <= vector->capacity); + + const void* const source = ZYCORE_VECTOR_OFFSET(vector, index); + void* const dest = ZYCORE_VECTOR_OFFSET(vector, index + count); + const ZyanUSize size = (vector->size - index) * vector->element_size; + ZYAN_MEMMOVE(dest, source, size); + + return ZYAN_STATUS_SUCCESS; +} + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +/* ---------------------------------------------------------------------------------------------- */ +/* Constructor and destructor */ +/* ---------------------------------------------------------------------------------------------- */ + +#ifndef ZYAN_NO_LIBC + +ZyanStatus ZyanVectorInit(ZyanVector* vector, ZyanUSize element_size, ZyanUSize capacity, + ZyanMemberProcedure destructor) +{ + return ZyanVectorInitEx(vector, element_size, capacity, destructor, ZyanAllocatorDefault(), + ZYAN_VECTOR_DEFAULT_GROWTH_FACTOR, ZYAN_VECTOR_DEFAULT_SHRINK_THRESHOLD); +} + +#endif // ZYAN_NO_LIBC + +ZyanStatus ZyanVectorInitEx(ZyanVector* vector, ZyanUSize element_size, ZyanUSize capacity, + ZyanMemberProcedure destructor, ZyanAllocator* allocator, ZyanU8 growth_factor, + ZyanU8 shrink_threshold) +{ + if (!vector || !element_size || !allocator || (growth_factor < 1)) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + ZYAN_ASSERT(allocator->allocate); + + vector->allocator = allocator; + vector->growth_factor = growth_factor; + vector->shrink_threshold = shrink_threshold; + vector->size = 0; + vector->capacity = ZYAN_MAX(ZYAN_VECTOR_MIN_CAPACITY, capacity); + vector->element_size = element_size; + vector->destructor = destructor; + vector->data = ZYAN_NULL; + + return allocator->allocate(vector->allocator, &vector->data, vector->element_size, + vector->capacity); +} + +ZyanStatus ZyanVectorInitCustomBuffer(ZyanVector* vector, ZyanUSize element_size, + void* buffer, ZyanUSize capacity, ZyanMemberProcedure destructor) +{ + if (!vector || !element_size || !buffer || !capacity) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + vector->allocator = ZYAN_NULL; + vector->growth_factor = 1; + vector->shrink_threshold = 0; + vector->size = 0; + vector->capacity = capacity; + vector->element_size = element_size; + vector->destructor = destructor; + vector->data = buffer; + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanVectorDestroy(ZyanVector* vector) +{ + if (!vector) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + ZYAN_ASSERT(vector->element_size); + ZYAN_ASSERT(vector->data); + + if (vector->destructor) + { + for (ZyanUSize i = 0; i < vector->size; ++i) + { + vector->destructor(ZYCORE_VECTOR_OFFSET(vector, i)); + } + } + + if (vector->allocator && vector->capacity) + { + ZYAN_ASSERT(vector->allocator->deallocate); + ZYAN_CHECK(vector->allocator->deallocate(vector->allocator, vector->data, + vector->element_size, vector->capacity)); + } + + vector->data = ZYAN_NULL; + return ZYAN_STATUS_SUCCESS; +} + +/* ---------------------------------------------------------------------------------------------- */ +/* Duplication */ +/* ---------------------------------------------------------------------------------------------- */ + +#ifndef ZYAN_NO_LIBC + +ZyanStatus ZyanVectorDuplicate(ZyanVector* destination, const ZyanVector* source, + ZyanUSize capacity) +{ + return ZyanVectorDuplicateEx(destination, source, capacity, ZyanAllocatorDefault(), + ZYAN_VECTOR_DEFAULT_GROWTH_FACTOR, ZYAN_VECTOR_DEFAULT_SHRINK_THRESHOLD); +} + +#endif // ZYAN_NO_LIBC + +ZyanStatus ZyanVectorDuplicateEx(ZyanVector* destination, const ZyanVector* source, + ZyanUSize capacity, ZyanAllocator* allocator, ZyanU8 growth_factor, ZyanU8 shrink_threshold) +{ + if (!source) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + const ZyanUSize len = source->size; + + capacity = ZYAN_MAX(capacity, len); + ZYAN_CHECK(ZyanVectorInitEx(destination, source->element_size, capacity, source->destructor, + allocator, growth_factor, shrink_threshold)); + ZYAN_ASSERT(destination->capacity >= len); + + ZYAN_MEMCPY(destination->data, source->data, len * source->element_size); + destination->size = len; + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanVectorDuplicateCustomBuffer(ZyanVector* destination, const ZyanVector* source, + void* buffer, ZyanUSize capacity) +{ + if (!source) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + const ZyanUSize len = source->size; + + if (capacity < len) + { + return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE; + } + + ZYAN_CHECK(ZyanVectorInitCustomBuffer(destination, source->element_size, buffer, capacity, + source->destructor)); + ZYAN_ASSERT(destination->capacity >= len); + + ZYAN_MEMCPY(destination->data, source->data, len * source->element_size); + destination->size = len; + + return ZYAN_STATUS_SUCCESS; +} + +/* ---------------------------------------------------------------------------------------------- */ +/* Element access */ +/* ---------------------------------------------------------------------------------------------- */ + +const void* ZyanVectorGet(const ZyanVector* vector, ZyanUSize index) +{ + if (!vector || (index >= vector->size)) + { + return ZYAN_NULL; + } + + ZYAN_ASSERT(vector->element_size); + ZYAN_ASSERT(vector->data); + + return ZYCORE_VECTOR_OFFSET(vector, index); +} + +void* ZyanVectorGetMutable(const ZyanVector* vector, ZyanUSize index) +{ + if (!vector || (index >= vector->size)) + { + return ZYAN_NULL; + } + + ZYAN_ASSERT(vector->element_size); + ZYAN_ASSERT(vector->data); + + return ZYCORE_VECTOR_OFFSET(vector, index); +} + +ZyanStatus ZyanVectorGetPointer(const ZyanVector* vector, ZyanUSize index, const void** value) +{ + if (!vector || !value) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + if (index >= vector->size) + { + return ZYAN_STATUS_OUT_OF_RANGE; + } + + ZYAN_ASSERT(vector->element_size); + ZYAN_ASSERT(vector->data); + + *value = (const void*)ZYCORE_VECTOR_OFFSET(vector, index); + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanVectorGetPointerMutable(const ZyanVector* vector, ZyanUSize index, void** value) +{ + if (!vector || !value) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + if (index >= vector->size) + { + return ZYAN_STATUS_OUT_OF_RANGE; + } + + ZYAN_ASSERT(vector->element_size); + ZYAN_ASSERT(vector->data); + + *value = ZYCORE_VECTOR_OFFSET(vector, index); + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanVectorSet(ZyanVector* vector, ZyanUSize index, const void* value) +{ + if (!vector || !value) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + if (index >= vector->size) + { + return ZYAN_STATUS_OUT_OF_RANGE; + } + + ZYAN_ASSERT(vector->element_size); + ZYAN_ASSERT(vector->data); + + void* const offset = ZYCORE_VECTOR_OFFSET(vector, index); + if (vector->destructor) + { + vector->destructor(offset); + } + ZYAN_MEMCPY(offset, value, vector->element_size); + + return ZYAN_STATUS_SUCCESS; +} + +/* ---------------------------------------------------------------------------------------------- */ +/* Insertion */ +/* ---------------------------------------------------------------------------------------------- */ + +ZyanStatus ZyanVectorPushBack(ZyanVector* vector, const void* element) +{ + if (!vector || !element) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + ZYAN_ASSERT(vector->element_size); + ZYAN_ASSERT(vector->data); + + if (ZYCORE_VECTOR_SHOULD_GROW(vector->size + 1, vector->capacity)) + { + ZYAN_CHECK(ZyanVectorReallocate(vector, + ZYAN_MAX(1, (ZyanUSize)((vector->size + 1) * vector->growth_factor)))); + } + + void* const offset = ZYCORE_VECTOR_OFFSET(vector, vector->size); + ZYAN_MEMCPY(offset, element, vector->element_size); + + ++vector->size; + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanVectorInsert(ZyanVector* vector, ZyanUSize index, const void* element) +{ + return ZyanVectorInsertRange(vector, index, element, 1); +} + +ZyanStatus ZyanVectorInsertRange(ZyanVector* vector, ZyanUSize index, const void* elements, + ZyanUSize count) +{ + if (!vector || !elements || !count) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + if (index > vector->size) + { + return ZYAN_STATUS_OUT_OF_RANGE; + } + + ZYAN_ASSERT(vector->element_size); + ZYAN_ASSERT(vector->data); + + if (ZYCORE_VECTOR_SHOULD_GROW(vector->size + count, vector->capacity)) + { + ZYAN_CHECK(ZyanVectorReallocate(vector, + ZYAN_MAX(1, (ZyanUSize)((vector->size + count) * vector->growth_factor)))); + } + + if (index < vector->size) + { + ZYAN_CHECK(ZyanVectorShiftRight(vector, index, count)); + } + + void* const offset = ZYCORE_VECTOR_OFFSET(vector, index); + ZYAN_MEMCPY(offset, elements, count * vector->element_size); + vector->size += count; + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanVectorEmplace(ZyanVector* vector, void** element, ZyanMemberFunction constructor) +{ + if (!vector) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + return ZyanVectorEmplaceEx(vector, vector->size, element, constructor); +} + +ZyanStatus ZyanVectorEmplaceEx(ZyanVector* vector, ZyanUSize index, void** element, + ZyanMemberFunction constructor) +{ + if (!vector) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + if (index > vector->size) + { + return ZYAN_STATUS_OUT_OF_RANGE; + } + + ZYAN_ASSERT(vector->element_size); + ZYAN_ASSERT(vector->data); + + if (ZYCORE_VECTOR_SHOULD_GROW(vector->size + 1, vector->capacity)) + { + ZYAN_CHECK(ZyanVectorReallocate(vector, + ZYAN_MAX(1, (ZyanUSize)((vector->size + 1) * vector->growth_factor)))); + } + + if (index < vector->size) + { + ZYAN_CHECK(ZyanVectorShiftRight(vector, index, 1)); + } + + *element = ZYCORE_VECTOR_OFFSET(vector, index); + if (constructor) + { + ZYAN_CHECK(constructor(*element)); + } + + ++vector->size; + + return ZYAN_STATUS_SUCCESS; +} + +/* ---------------------------------------------------------------------------------------------- */ +/* Utils */ +/* ---------------------------------------------------------------------------------------------- */ + +ZyanStatus ZyanVectorSwapElements(ZyanVector* vector, ZyanUSize index_first, ZyanUSize index_second) +{ + if (!vector) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + if ((index_first >= vector->size) || (index_second >= vector->size)) + { + return ZYAN_STATUS_OUT_OF_RANGE; + } + + if (vector->size == vector->capacity) + { + return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE; + } + + ZYAN_ASSERT(vector->element_size); + ZYAN_ASSERT(vector->data); + + ZyanU64* const t = ZYCORE_VECTOR_OFFSET(vector, vector->size); + ZyanU64* const a = ZYCORE_VECTOR_OFFSET(vector, index_first); + ZyanU64* const b = ZYCORE_VECTOR_OFFSET(vector, index_second); + ZYAN_MEMCPY(t, a, vector->element_size); + ZYAN_MEMCPY(a, b, vector->element_size); + ZYAN_MEMCPY(b, t, vector->element_size); + + return ZYAN_STATUS_SUCCESS; +} + +/* ---------------------------------------------------------------------------------------------- */ +/* Deletion */ +/* ---------------------------------------------------------------------------------------------- */ + +ZyanStatus ZyanVectorDelete(ZyanVector* vector, ZyanUSize index) +{ + return ZyanVectorDeleteRange(vector, index, 1); +} + +ZyanStatus ZyanVectorDeleteRange(ZyanVector* vector, ZyanUSize index, ZyanUSize count) +{ + if (!vector || !count) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + if (index + count > vector->size) + { + return ZYAN_STATUS_OUT_OF_RANGE; + } + + if (vector->destructor) + { + for (ZyanUSize i = index; i < index + count; ++i) + { + vector->destructor(ZYCORE_VECTOR_OFFSET(vector, i)); + } + } + + if (index + count < vector->size) + { + ZYAN_CHECK(ZyanVectorShiftLeft(vector, index, count)); + } + + vector->size -= count; + if (ZYCORE_VECTOR_SHOULD_SHRINK(vector->size, vector->capacity, vector->shrink_threshold)) + { + return ZyanVectorReallocate(vector, + ZYAN_MAX(1, (ZyanUSize)(vector->size * vector->growth_factor))); + } + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanVectorPopBack(ZyanVector* vector) +{ + if (!vector) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + if (vector->size == 0) + { + return ZYAN_STATUS_OUT_OF_RANGE; + } + + if (vector->destructor) + { + vector->destructor(ZYCORE_VECTOR_OFFSET(vector, vector->size - 1)); + } + + --vector->size; + if (ZYCORE_VECTOR_SHOULD_SHRINK(vector->size, vector->capacity, vector->shrink_threshold)) + { + return ZyanVectorReallocate(vector, + ZYAN_MAX(1, (ZyanUSize)(vector->size * vector->growth_factor))); + } + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanVectorClear(ZyanVector* vector) +{ + return ZyanVectorResizeEx(vector, 0, ZYAN_NULL); +} + +/* ---------------------------------------------------------------------------------------------- */ +/* Searching */ +/* ---------------------------------------------------------------------------------------------- */ + +ZyanStatus ZyanVectorFind(const ZyanVector* vector, const void* element, ZyanISize* found_index, + ZyanEqualityComparison comparison) +{ + if (!vector) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + return ZyanVectorFindEx(vector, element, found_index, comparison, 0, vector->size); +} + +ZyanStatus ZyanVectorFindEx(const ZyanVector* vector, const void* element, ZyanISize* found_index, + ZyanEqualityComparison comparison, ZyanUSize index, ZyanUSize count) +{ + if (!vector) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + if ((index + count > vector->size) || (index == vector->size)) + { + return ZYAN_STATUS_OUT_OF_RANGE; + } + + if (!count) + { + *found_index = -1; + return ZYAN_STATUS_FALSE; + } + + ZYAN_ASSERT(vector->element_size); + ZYAN_ASSERT(vector->data); + + for (ZyanUSize i = index; i < index + count; ++i) + { + if (comparison(ZYCORE_VECTOR_OFFSET(vector, i), element)) + { + *found_index = i; + return ZYAN_STATUS_TRUE; + } + } + + *found_index = -1; + return ZYAN_STATUS_FALSE; +} + +ZyanStatus ZyanVectorBinarySearch(const ZyanVector* vector, const void* element, + ZyanUSize* found_index, ZyanComparison comparison) +{ + if (!vector) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + return ZyanVectorBinarySearchEx(vector, element, found_index, comparison, 0, vector->size); +} + +ZyanStatus ZyanVectorBinarySearchEx(const ZyanVector* vector, const void* element, + ZyanUSize* found_index, ZyanComparison comparison, ZyanUSize index, ZyanUSize count) +{ + if (!vector) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + if (((index >= vector->size) && (count > 0)) || (index + count > vector->size)) + { + return ZYAN_STATUS_OUT_OF_RANGE; + } + + if (!count) + { + *found_index = index; + return ZYAN_STATUS_FALSE; + } + + ZYAN_ASSERT(vector->element_size); + ZYAN_ASSERT(vector->data); + + ZyanStatus status = ZYAN_STATUS_FALSE; + ZyanISize l = index; + ZyanISize h = index + count - 1; + while (l <= h) + { + const ZyanUSize mid = l + ((h - l) >> 1); + const ZyanI32 cmp = comparison(ZYCORE_VECTOR_OFFSET(vector, mid), element); + if (cmp < 0) + { + l = mid + 1; + } else + { + h = mid - 1; + if (cmp == 0) + { + status = ZYAN_STATUS_TRUE; + } + } + } + + *found_index = l; + return status; +} + +/* ---------------------------------------------------------------------------------------------- */ +/* Memory management */ +/* ---------------------------------------------------------------------------------------------- */ + +ZyanStatus ZyanVectorResize(ZyanVector* vector, ZyanUSize size) +{ + return ZyanVectorResizeEx(vector, size, ZYAN_NULL); +} + +ZyanStatus ZyanVectorResizeEx(ZyanVector* vector, ZyanUSize size, const void* initializer) +{ + if (!vector) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + if (size == vector->size) + { + return ZYAN_STATUS_SUCCESS; + } + + if (vector->destructor && (size < vector->size)) + { + for (ZyanUSize i = size; i < vector->size; ++i) + { + vector->destructor(ZYCORE_VECTOR_OFFSET(vector, i)); + } + } + + if (ZYCORE_VECTOR_SHOULD_GROW(size, vector->capacity) || + ZYCORE_VECTOR_SHOULD_SHRINK(size, vector->capacity, vector->shrink_threshold)) + { + ZYAN_ASSERT(vector->growth_factor >= 1); + ZYAN_CHECK(ZyanVectorReallocate(vector, (ZyanUSize)(size * vector->growth_factor))); + } + + if (initializer && (size > vector->size)) + { + for (ZyanUSize i = vector->size; i < size; ++i) + { + ZYAN_MEMCPY(ZYCORE_VECTOR_OFFSET(vector, i), initializer, vector->element_size); + } + } + + vector->size = size; + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanVectorReserve(ZyanVector* vector, ZyanUSize capacity) +{ + if (!vector) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + if (capacity > vector->capacity) + { + ZYAN_CHECK(ZyanVectorReallocate(vector, capacity)); + } + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanVectorShrinkToFit(ZyanVector* vector) +{ + if (!vector) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + return ZyanVectorReallocate(vector, vector->size); +} + +/* ---------------------------------------------------------------------------------------------- */ +/* Information */ +/* ---------------------------------------------------------------------------------------------- */ + +ZyanStatus ZyanVectorGetCapacity(const ZyanVector* vector, ZyanUSize* capacity) +{ + if (!vector) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + *capacity = vector->capacity; + + return ZYAN_STATUS_SUCCESS; +} + +ZyanStatus ZyanVectorGetSize(const ZyanVector* vector, ZyanUSize* size) +{ + if (!vector) + { + return ZYAN_STATUS_INVALID_ARGUMENT; + } + + *size = vector->size; + + return ZYAN_STATUS_SUCCESS; +} + +/* ---------------------------------------------------------------------------------------------- */ + +/* ============================================================================================== */ diff --git a/zycore/src/Zycore.c b/zycore/src/Zycore.c new file mode 100644 index 0000000..9bbb200 --- /dev/null +++ b/zycore/src/Zycore.c @@ -0,0 +1,38 @@ +/*************************************************************************************************** + + Zyan Core Library (Zycore-C) + + Original Author : Florian Bernd + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +#include + +/* ============================================================================================== */ +/* Exported functions */ +/* ============================================================================================== */ + +ZyanU64 ZycoreGetVersion(void) +{ + return ZYCORE_VERSION; +} + +/* ============================================================================================== */ -- 2.17.1