├── .clang-format ├── .clang-tidy ├── .gitattributes ├── CMakeLists.txt ├── LICENSE ├── Makefile ├── README.md ├── changelogs ├── allocator.md ├── dynamicarray.md ├── logger.md └── timer.md ├── cmake └── Config.cmake.in ├── include └── zero │ ├── allocator.h │ ├── dynamicarray.h │ ├── logger.h │ └── timer.h ├── src ├── allocator.h.tpl ├── dynamicarray.h.tpl ├── logger.h.tpl ├── partials │ ├── environment.h │ ├── license.h │ ├── logger.h │ ├── logging.h │ ├── loglevel.h │ ├── platform.h │ ├── status.h │ ├── types.h │ └── unused.h └── timer.h.tpl └── tools └── build └── main.c /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | # Minimum version required for clang-format: 5.0 3 | Language: Cpp 4 | AccessModifierOffset: -4 5 | AlignAfterOpenBracket: Align 6 | AlignConsecutiveAssignments: false 7 | AlignConsecutiveDeclarations: false 8 | AlignEscapedNewlines: Right 9 | AlignOperands: true 10 | AlignTrailingComments: false 11 | AllowAllParametersOfDeclarationOnNextLine: false 12 | AllowShortBlocksOnASingleLine: false 13 | AllowShortCaseLabelsOnASingleLine: false 14 | AllowShortFunctionsOnASingleLine: None 15 | AllowShortIfStatementsOnASingleLine: false 16 | AllowShortLoopsOnASingleLine: false 17 | AlwaysBreakAfterDefinitionReturnType: None 18 | AlwaysBreakAfterReturnType: All 19 | AlwaysBreakBeforeMultilineStrings: false 20 | AlwaysBreakTemplateDeclarations: true 21 | BinPackArguments: false 22 | BinPackParameters: false 23 | BraceWrapping: 24 | AfterClass: false 25 | AfterControlStatement: false 26 | AfterEnum: false 27 | AfterFunction: true 28 | AfterNamespace: true 29 | AfterObjCDeclaration: false 30 | AfterStruct: false 31 | AfterUnion: false 32 | BeforeCatch: true 33 | BeforeElse: false 34 | IndentBraces: false 35 | BreakAfterJavaFieldAnnotations: false 36 | BreakBeforeBinaryOperators: All 37 | BreakBeforeBraces: Custom 38 | BreakBeforeInheritanceComma: true 39 | BreakBeforeTernaryOperators: true 40 | BreakConstructorInitializers: BeforeComma 41 | BreakStringLiterals: true 42 | ColumnLimit: 80 43 | CommentPragmas: '^ IWYU pragma:' 44 | CompactNamespaces: false 45 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 46 | ConstructorInitializerIndentWidth: 4 47 | ContinuationIndentWidth: 4 48 | Cpp11BracedListStyle: true 49 | DerivePointerAlignment: false 50 | DisableFormat: false 51 | FixNamespaceComments: true 52 | ForEachMacros: [] 53 | IncludeCategories: 54 | - Regex: '.*' 55 | Priority: 1 56 | IncludeIsMainRegex: '$' 57 | IndentCaseLabels: true 58 | IndentWidth: 4 59 | IndentWrappedFunctionNames: false 60 | JavaScriptQuotes: Leave 61 | JavaScriptWrapImports: true 62 | KeepEmptyLinesAtTheStartOfBlocks: false 63 | MacroBlockBegin: '' 64 | MacroBlockEnd: '' 65 | MaxEmptyLinesToKeep: 1 66 | NamespaceIndentation: None 67 | ObjCBlockIndentWidth: 4 68 | ObjCSpaceAfterProperty: true 69 | ObjCSpaceBeforeProtocolList: true 70 | PenaltyBreakAssignment: 10 71 | PenaltyBreakBeforeFirstCallParameter: 1 72 | PenaltyBreakComment: 10 73 | PenaltyBreakFirstLessLess: 10 74 | PenaltyBreakString: 20 75 | PenaltyExcessCharacter: 1000 76 | PenaltyReturnTypeOnItsOwnLine: 0 77 | PointerAlignment: Right 78 | ReflowComments: true 79 | SortIncludes: false 80 | SortUsingDeclarations: true 81 | SpaceAfterCStyleCast: false 82 | SpaceAfterTemplateKeyword: false 83 | SpaceBeforeAssignmentOperators: true 84 | SpaceBeforeParens: ControlStatements 85 | SpaceInEmptyParentheses: false 86 | SpacesBeforeTrailingComments: 1 87 | SpacesInAngles: false 88 | SpacesInCStyleCastParentheses: false 89 | SpacesInContainerLiterals: true 90 | SpacesInParentheses: false 91 | SpacesInSquareBrackets: false 92 | Standard: Cpp11 93 | TabWidth: 4 94 | UseTab: Never 95 | ... 96 | -------------------------------------------------------------------------------- /.clang-tidy: -------------------------------------------------------------------------------- 1 | --- 2 | # Minimum version required for clang-tidy: 5.0 3 | Checks: '*,-clang-analyzer-valist.Uninitialized,-llvm-header-guard,-llvm-include-order' 4 | WarningsAsErrors: '' 5 | HeaderFilterRegex: '' 6 | AnalyzeTemporaryDtors: false 7 | FormatStyle: file 8 | ... 9 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.h linguist-language=C 2 | *.tpl linguist-language=C 3 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1) 2 | 3 | project(Zero 4 | VERSION 0.3.0 5 | LANGUAGES C) 6 | 7 | # ------------------------------------------------------------------------------ 8 | 9 | include(CMakePackageConfigHelpers) 10 | include(GNUInstallDirs) 11 | 12 | # ------------------------------------------------------------------------------ 13 | 14 | set(CMAKE_C_STANDARD 99) 15 | set(CMAKE_C_STANDARD_REQUIRED ON) 16 | set(CMAKE_C_EXTENSIONS OFF) 17 | set(CMAKE_CXX_STANDARD 11) 18 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 19 | set(CMAKE_CXX_EXTENSIONS OFF) 20 | 21 | if ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" 22 | OR "${CMAKE_C_COMPILER_ID}" STREQUAL "CLANG") 23 | add_compile_options( 24 | -Wpedantic -Wall -Wextra -Waggregate-return -Wcast-align -Wcast-qual 25 | -Wconversion -Wfloat-equal -Wpointer-arith -Wshadow -Wstrict-overflow=5 26 | -Wswitch -Wswitch-default -Wundef -Wunreachable-code -Wwrite-strings) 27 | endif() 28 | 29 | # ------------------------------------------------------------------------------ 30 | 31 | macro(zr_add_library target) 32 | set(ZR_ADD_LIBRARY_OPTIONS) 33 | set(ZR_ADD_LIBRARY_SINGLE_VALUE_ARGS) 34 | set(ZR_ADD_LIBRARY_MULTI_VALUE_ARGS DEPENDS) 35 | cmake_parse_arguments( 36 | ZR_ADD_LIBRARY 37 | "${ZR_ADD_LIBRARY_OPTIONS}" 38 | "${ZR_ADD_LIBRARY_SINGLE_VALUE_ARGS}" 39 | "${ZR_ADD_LIBRARY_MULTI_VALUE_ARGS}" 40 | ${ARGN}) 41 | 42 | add_library(${target} INTERFACE) 43 | target_include_directories(${target} 44 | INTERFACE 45 | "$" 46 | "$") 47 | target_link_libraries(${target} 48 | INTERFACE ${ZR_ADD_LIBRARY_DEPENDS}) 49 | install( 50 | TARGETS ${target} 51 | EXPORT ${PROJECT_NAME}Targets) 52 | add_library(${PROJECT_NAME}::${target} ALIAS ${target}) 53 | endmacro() 54 | 55 | zr_add_library(allocator) 56 | zr_add_library(dynamicarray) 57 | zr_add_library(logger) 58 | zr_add_library(timer) 59 | 60 | # ------------------------------------------------------------------------------ 61 | 62 | set(ZR_TOOL_TARGETS) 63 | 64 | macro(zr_add_tool) 65 | set(ZR_ADD_TOOL_OPTIONS) 66 | set(ZR_ADD_TOOL_SINGLE_VALUE_ARGS NAME) 67 | set(ZR_ADD_TOOL_MULTI_VALUE_ARGS FILES) 68 | cmake_parse_arguments( 69 | ZR_ADD_TOOL 70 | "${ZR_ADD_TOOL_OPTIONS}" 71 | "${ZR_ADD_TOOL_SINGLE_VALUE_ARGS}" 72 | "${ZR_ADD_TOOL_MULTI_VALUE_ARGS}" 73 | ${ARGN}) 74 | 75 | add_executable(tool-${ZR_ADD_TOOL_NAME} ${ZR_ADD_TOOL_FILES}) 76 | set_target_properties(tool-${ZR_ADD_TOOL_NAME} 77 | PROPERTIES 78 | RUNTIME_OUTPUT_DIRECTORY bin/tools 79 | OUTPUT_NAME ${ZR_ADD_TOOL_NAME}) 80 | list(APPEND ZR_TOOL_TARGETS tool-${ZR_ADD_TOOL_NAME}) 81 | endmacro() 82 | 83 | zr_add_tool( 84 | NAME build 85 | FILES tools/build/main.c) 86 | 87 | add_custom_target(tools DEPENDS ${ZR_TOOL_TARGETS}) 88 | 89 | # ------------------------------------------------------------------------------ 90 | 91 | install( 92 | DIRECTORY include/zero 93 | DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) 94 | 95 | # ------------------------------------------------------------------------------ 96 | 97 | set(ZR_CMAKE_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}) 98 | 99 | configure_package_config_file( 100 | cmake/Config.cmake.in 101 | ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake 102 | INSTALL_DESTINATION ${ZR_CMAKE_INSTALL_DIR}) 103 | 104 | write_basic_package_version_file( 105 | ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake 106 | VERSION ${PROJECT_VERSION} 107 | COMPATIBILITY AnyNewerVersion) 108 | 109 | install( 110 | FILES 111 | ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake 112 | ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake 113 | DESTINATION ${ZR_CMAKE_INSTALL_DIR}) 114 | 115 | install( 116 | EXPORT ${PROJECT_NAME}Targets 117 | FILE ${PROJECT_NAME}Targets.cmake 118 | NAMESPACE ${PROJECT_NAME}:: 119 | DESTINATION ${ZR_CMAKE_INSTALL_DIR}) 120 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Christopher Crouzet 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PROJECT_DIR := $(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST))))) 2 | 3 | # ------------------------------------------------------------------------------ 4 | 5 | ifndef outdir 6 | OUT_DIR := build 7 | else 8 | OUT_DIR := $(outdir) 9 | endif 10 | 11 | ifndef config 12 | CONFIG := release 13 | else ifneq "$(filter-out debug release all,$(config))" "" 14 | $(error the 'config' option is not valid) 15 | else ifneq "$(filter all,$(config))" "" 16 | CONFIG := debug release 17 | else 18 | CONFIG := $(config) 19 | endif 20 | 21 | # ------------------------------------------------------------------------------ 22 | 23 | PROJECT := zero 24 | 25 | # ------------------------------------------------------------------------------ 26 | 27 | FORMAT_FILES := 28 | TIDY_FILES := 29 | 30 | # ------------------------------------------------------------------------------ 31 | 32 | # $(1): build directory. 33 | # $(2): rule. 34 | define zr_forward_rule_impl = 35 | $(MAKE) -C $(1) -s $(2) 36 | endef 37 | 38 | # Forward a rule to the generated Makefiles. 39 | # $(1): rule. 40 | define zr_forward_rule = 41 | $(foreach _x,$(BUILD_DIRS), $(call \ 42 | zr_forward_rule_impl,$(_x),$(1))) 43 | endef 44 | 45 | # ------------------------------------------------------------------------------ 46 | 47 | # Create a Makefile rule. 48 | # # $(1): configuration. 49 | define zr_create_makefile = 50 | $$(OUT_DIR)/$(1)/Makefile: 51 | @ mkdir -p $$(OUT_DIR)/$(1) 52 | @ cd $$(OUT_DIR)/$(1) && cmake \ 53 | -DCMAKE_BUILD_TYPE=$(1) \ 54 | -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ 55 | $(PROJECT_DIR) 56 | 57 | BUILD_DIRS += $$(OUT_DIR)/$(1) 58 | MAKE_FILES += $$(OUT_DIR)/$(1)/Makefile 59 | endef 60 | 61 | $(foreach _config,$(CONFIG),$(eval $(call \ 62 | zr_create_makefile,$(_config)))) 63 | 64 | # ------------------------------------------------------------------------------ 65 | 66 | tool-build: $(MAKE_FILES) 67 | @ $(call zr_forward_rule,tool-build) 68 | 69 | tools: $(MAKE_FILES) 70 | @ $(call zr_forward_rule,tools) 71 | 72 | .PHONY: tool-build tools 73 | 74 | TOOLS := $(notdir $(wildcard tools/*)) 75 | FORMAT_FILES += $(foreach _x,$(TOOLS),$(wildcard tools/$(_x)/*.[ch])) 76 | TIDY_FILES += $(foreach _x,$(TOOLS),$(wildcard tools/$(_x)/*.[ch])) 77 | 78 | # ------------------------------------------------------------------------------ 79 | 80 | TEMPLATES := $(wildcard src/*.tpl) 81 | INCLUDES := $(TEMPLATES:src/%.h.tpl=include/$(PROJECT)/%.h) 82 | 83 | $(INCLUDES): include/$(PROJECT)/%.h: src/%.h.tpl 84 | @ mkdir -p $(@D) 85 | @ $(firstword $(BUILD_DIRS))/bin/tools/build $< $@ 86 | 87 | $(INCLUDES): tool-build 88 | 89 | includes: $(INCLUDES) 90 | 91 | .PHONY: includes 92 | 93 | FORMAT_FILES += $(TEMPLATES) $(INCLUDES) $(wildcard src/partials/*.h) 94 | TIDY_FILES += $(INCLUDES) 95 | 96 | # ------------------------------------------------------------------------------ 97 | 98 | CLANG_VERSION := $(shell \ 99 | clang --version \ 100 | | grep version \ 101 | | sed 's/^.*version \([0-9]*\.[0-9]*\.[0-9]*\).*$$/\1/') 102 | CLANG_DIR := $(shell dirname $(shell which clang)) 103 | CLANG_INCLUDE_DIR := $(CLANG_DIR)/../lib/clang/$(CLANG_VERSION)/include 104 | 105 | format: 106 | @ clang-format -i -style=file $(FORMAT_FILES) 107 | 108 | tidy: $(firstword $(MAKE_FILES)) 109 | @ clang-tidy $(TIDY_FILES) \ 110 | -p $(firstword $(BUILD_DIRS))/compile_commands.json \ 111 | -- -I$(CLANG_INCLUDE_DIR) 112 | 113 | .PHONY: format tidy 114 | 115 | # ------------------------------------------------------------------------------ 116 | 117 | install: $(MAKE_FILES) 118 | @ $(call zr_forward_rule,install) 119 | 120 | .PHONY: install 121 | 122 | # ------------------------------------------------------------------------------ 123 | 124 | clean: 125 | @ rm -rf $(OUT_DIR) 126 | 127 | .PHONY: clean 128 | 129 | # ------------------------------------------------------------------------------ 130 | 131 | all: includes 132 | 133 | .PHONY: all 134 | 135 | .DEFAULT_GOAL := all 136 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Zero 2 | ==== 3 | 4 | Zero is a bunch of single-file libraries for C/C++. 5 | 6 | It is written in C89 at the exception of a couple of features borrowed from C99, 7 | namely fixed-width integer types and variadic macros. 8 | 9 | 10 | ## Features 11 | 12 | * mostly C89-compliant 13 | * headers don't include anything by default [1] 14 | * implementations are included upon defining the `ZR_DEFINE_IMPLEMENTATION` 15 | macro 16 | * each library is a standalone single file to ease integration into projects 17 | * simple 18 | 19 | 1. The only exception being `` for headers defining functions with a 20 | `va_list` object as parameter. 21 | 22 | 23 | ## Libraries 24 | 25 | 26 | | library | description | latest version | changelog | 27 | |---------|-------------|----------------|-----------| 28 | **[allocator.h](include/zero/allocator.h)** | Aligned and non-aligned wrappers of malloc/realloc/free | 0.2.0 | [changelog](changelogs/allocator.md) 29 | **[dynamicarray.h](include/zero/dynamicarray.h)** | Contiguous array that can grow and shrink | 0.1.0 | [changelog](changelogs/dynamicarray.md) 30 | **[logger.h](include/zero/logger.h)** | Simple logger with different log levels and colouring | 0.2.0 | [changelog](changelogs/logger.md) 31 | **[timer.h](include/zero/timer.h)** | High-resolution real time clock and CPU (user/system) clocks | 0.2.0 | [changelog](changelogs/timer.md) 32 | 33 | 34 | ## FAQ 35 | 36 | ### Why defining custom fixed-width integer types and even `size_t`? 37 | 38 | Because most projects target common platforms (Windows, Linux, macOS), thus 39 | using either the ILP32, LP64, or LLP64 data models, which all guarantee the 40 | `char` type to be 8 bits, `short` to be 16 bits, `int` to be 32 bits, and 41 | `long long` to be 64 bits. If such types can be accurately defined in a few 42 | lines for most of the projects, then why including a standard header that 43 | resolves to _thousands_ of lines of code with its dependencies? For the exotic 44 | platforms, the macro `ZR_USE_STD_FIXED_TYPES` can be defined, or each type can 45 | be overridden individually. 46 | 47 | The same applies to redefining `size_t`—on almost all platforms the size of 48 | `size_t` equals the targeted architecture, that is either 32 or 64 bits. Here 49 | again, if that's not enough then it's still possible to define 50 | the macro `ZR_USE_STD_BASIC_TYPES`. 51 | 52 | Note that these custom types are only used for the public interface defined in 53 | the headers, to avoid cluttering project headers including them. But the 54 | implementation sections make free use of standard headers as needed 55 | (including standard fixed-width integer types and `size_t`). 56 | -------------------------------------------------------------------------------- /changelogs/allocator.md: -------------------------------------------------------------------------------- 1 | Changelog For `zero/allocator.h` 2 | ================================ 3 | 4 | Version numbers comply with the [Sementic Versioning Specification (SemVer)]. 5 | 6 | 7 | ## [v0.2.0] (2018-05-26) 8 | 9 | ### Added 10 | 11 | * Global macro `ZR_ENABLE_DEBUGGING`. 12 | * Log messages. 13 | 14 | 15 | ### Changed 16 | 17 | * Refer directly to structs and enums instead of using typedefs. 18 | * `zrFree()` and `zrFreeAligned()` now accept a const pointer to `void`. 19 | * Rename the macro `ZR_IMPLEMENTATION` to `ZR_DEFINE_IMPLEMENTATION`. 20 | * Rename the macros `ZR_ALLOCATOR_STATIC` and `ZR_STATIC` respectively to 21 | `ZR_ALLOCATOR_SPECIFY_INTERNAL_LINKAGE` and `ZR_SPECIFY_INTERNAL_LINKAGE`. 22 | * Don't define the `extern "C"` as a namespace. 23 | * Apply minor internal changes. 24 | 25 | 26 | ### Removed 27 | 28 | * Module-specific macros such as `ZR_ALLOCATOR_ASSERT`, `ZR_ALLOCATOR_MALLOC`, 29 | `ZR_ALLOCATOR_REALLOC`, and `ZR_ALLOCATOR_FREE`. 30 | 31 | 32 | ## [v0.1.1] (2018-03-13) 33 | 34 | ## Added 35 | 36 | * Module-specific macros, overriding the global ones. 37 | 38 | 39 | ### Changed 40 | 41 | * Rewrite the power of two check. 42 | * Guard against warnings from `-Wunused-function`. 43 | * Make the architecture macros private. 44 | * Make static assertion messages private types. 45 | * Wrap all private code into the module's namespace. 46 | * Apply minor internal changes. 47 | 48 | 49 | ## v0.1.0 (2018-01-20) 50 | 51 | * Initial release. 52 | 53 | 54 | [Sementic Versioning Specification (SemVer)]: https://semver.org 55 | [v0.2.0]: https://github.com/christophercrouzet/zero/compare/allocator-v0.1.1...allocator-v0.2.0 56 | [v0.1.1]: https://github.com/christophercrouzet/zero/compare/allocator-v0.1.0...allocator-v0.1.1 57 | -------------------------------------------------------------------------------- /changelogs/dynamicarray.md: -------------------------------------------------------------------------------- 1 | Changelog For `zero/dynamicarray.h` 2 | =================================== 3 | 4 | Version numbers comply with the [Sementic Versioning Specification (SemVer)]. 5 | 6 | 7 | ## v0.1.0 (2018-05-25) 8 | 9 | * Initial release. 10 | 11 | 12 | [Sementic Versioning Specification (SemVer)]: https://semver.org 13 | -------------------------------------------------------------------------------- /changelogs/logger.md: -------------------------------------------------------------------------------- 1 | Changelog For `zero/logger.h` 2 | ============================= 3 | 4 | Version numbers comply with the [Sementic Versioning Specification (SemVer)]. 5 | 6 | 7 | ## [v0.2.0] (2018-05-26) 8 | 9 | ### Added 10 | 11 | * Log level 'trace'. 12 | * Log messages. 13 | 14 | 15 | ### Changed 16 | 17 | * Swap the color for the 'info' log level with 'trace'. 18 | * Refer directly to structs and enums instead of using typedefs. 19 | * Reverse the log level ordering. 20 | * Rename the macro `ZR_DISABLE_LOG_COLORING` to `ZR_DISABLE_LOG_STYLING`. 21 | * Rename the macro `ZR_IMPLEMENTATION` to `ZR_DEFINE_IMPLEMENTATION`. 22 | * Rename the macros `ZR_LOGGER_STATIC` and `ZR_STATIC` respectively to 23 | `ZR_LOGGER_SPECIFY_INTERNAL_LINKAGE` and `ZR_SPECIFY_INTERNAL_LINKAGE`. 24 | * Don't define the `extern "C"` as a namespace. 25 | * Apply minor internal changes. 26 | 27 | 28 | ### Removed 29 | 30 | * Module-specific macro `ZR_LOGGER_ASSERT`. 31 | 32 | 33 | ## [v0.1.1] (2018-03-13) 34 | 35 | ## Added 36 | 37 | * Make macros definable for this module only, overriding the project-level ones. 38 | 39 | 40 | ### Changed 41 | 42 | * Check for the POSIX.1 feature set. 43 | * Guard against warnings from `-Wunused-function`. 44 | * Guard against warnings from `-Wundef`. 45 | * Wrap all private code into the module's namespace. 46 | * Apply minor internal changes. 47 | 48 | 49 | ## v0.1.0 (2018-01-20) 50 | 51 | * Initial release. 52 | 53 | 54 | [Sementic Versioning Specification (SemVer)]: https://semver.org 55 | [v0.2.0]: https://github.com/christophercrouzet/zero/compare/logger-v0.1.1...logger-v0.2.0 56 | [v0.1.1]: https://github.com/christophercrouzet/zero/compare/logger-v0.1.0...logger-v0.1.1 57 | -------------------------------------------------------------------------------- /changelogs/timer.md: -------------------------------------------------------------------------------- 1 | Changelog For `zero/timer.h` 2 | ============================ 3 | 4 | Version numbers comply with the [Sementic Versioning Specification (SemVer)]. 5 | 6 | 7 | ## [v0.2.0] (2018-05-26) 8 | 9 | ### Added 10 | 11 | * Log messages. 12 | 13 | 14 | ### Changed 15 | 16 | * Guard against `_POSIX_C_SOURCE` being not defined. 17 | * Refer directly to structs and enums instead of using typedefs. 18 | * Rename `ZrResult` to `ZrStatus`. 19 | * Rename the macro `ZR_IMPLEMENTATION` to `ZR_DEFINE_IMPLEMENTATION`. 20 | * Rename the macros `ZR_TIMER_STATIC` and `ZR_STATIC` respectively to 21 | `ZR_TIMER_SPECIFY_INTERNAL_LINKAGE` and `ZR_SPECIFY_INTERNAL_LINKAGE`. 22 | * Don't define the `extern "C"` as a namespace. 23 | 24 | 25 | ### Removed 26 | 27 | * Module-specific macro `ZR_TIMER_ASSERT`. 28 | 29 | 30 | ## v0.1.0 (2018-03-13) 31 | 32 | * Initial release. 33 | 34 | 35 | [v0.2.0]: https://github.com/christophercrouzet/zero/compare/timer-v0.1.0...timer-v0.2.0 36 | [Sementic Versioning Specification (SemVer)]: https://semver.org 37 | -------------------------------------------------------------------------------- /cmake/Config.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | 3 | include(${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake) 4 | -------------------------------------------------------------------------------- /include/zero/allocator.h: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2018 Christopher Crouzet 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | #ifndef ZERO_ALLOCATOR_H 26 | #define ZERO_ALLOCATOR_H 27 | 28 | #define ZR_ALLOCATOR_MAJOR_VERSION 0 29 | #define ZR_ALLOCATOR_MINOR_VERSION 1 30 | #define ZR_ALLOCATOR_PATCH_VERSION 1 31 | 32 | #ifndef ZRP_ARCH_DEFINED 33 | #define ZRP_ARCH_DEFINED 34 | #if defined(__x86_64__) || defined(_M_X64) 35 | #define ZRP_ARCH_X86_64 36 | #elif defined(__i386) || defined(_M_IX86) 37 | #define ZRP_ARCH_X86_32 38 | #elif defined(__itanium__) || defined(_M_IA64) 39 | #define ZRP_ARCH_ITANIUM_64 40 | #elif defined(__powerpc64__) || defined(__ppc64__) 41 | #define ZRP_ARCH_POWERPC_64 42 | #elif defined(__powerpc__) || defined(__ppc__) 43 | #define ZRP_ARCH_POWERPC_32 44 | #elif defined(__aarch64__) 45 | #define ZRP_ARCH_ARM_64 46 | #elif defined(__arm__) 47 | #define ZRP_ARCH_ARM_32 48 | #endif 49 | #endif /* ZRP_ARCH_DEFINED */ 50 | 51 | /* 52 | The environment macro represents whether the code is to be generated for a 53 | 32-bit or 64-bit target platform. Some CPUs, such as the x86-64 processors, 54 | allow running code in 32-bit mode if compiled using the -m32 or -mx32 55 | compiler switches, in which case `ZR_ENVIRONMENT` is set to 32. 56 | */ 57 | #ifndef ZR_ENVIRONMENT 58 | #if (!defined(ZRP_ARCH_X86_64) || defined(__ILP32__)) \ 59 | && !defined(ZRP_ARCH_ITANIUM_64) && !defined(ZRP_ARCH_POWERPC_64) \ 60 | && !defined(ZRP_ARCH_ARM_64) 61 | #define ZR_ENVIRONMENT 32 62 | #else 63 | #define ZR_ENVIRONMENT 64 64 | #endif 65 | #ifdef ZR_DEFINE_IMPLEMENTATION 66 | typedef char zrp_invalid_environment_value 67 | [ZR_ENVIRONMENT == 32 || ZR_ENVIRONMENT == 64 ? 1 : -1]; 68 | #endif /* ZR_DEFINE_IMPLEMENTATION */ 69 | #endif /* ZR_ENVIRONMENT */ 70 | 71 | #ifndef ZRP_PLATFORM_DEFINED 72 | #define ZRP_PLATFORM_DEFINED 73 | #if defined(_WIN32) 74 | #define ZRP_PLATFORM_WINDOWS 75 | #elif defined(__unix__) || defined(__APPLE__) 76 | #define ZRP_PLATFORM_UNIX 77 | #if defined(__APPLE__) 78 | #define ZRP_PLATFORM_DARWIN 79 | #if TARGET_OS_IPHONE == 1 80 | #define ZRP_PLATFORM_IOS 81 | #elif TARGET_OS_MAC == 1 82 | #define ZRP_PLATFORM_MACOS 83 | #endif 84 | #elif defined(__linux__) 85 | #define ZRP_PLATFORM_LINUX 86 | #endif 87 | #endif 88 | #endif /* ZRP_PLATFORM_DEFINED */ 89 | 90 | #ifndef ZRP_FIXED_TYPES_DEFINED 91 | #define ZRP_FIXED_TYPES_DEFINED 92 | #ifdef ZR_USE_STD_FIXED_TYPES 93 | #include 94 | typedef int8_t ZrInt8; 95 | typedef uint8_t ZrUint8; 96 | typedef int16_t ZrInt16; 97 | typedef uint16_t ZrUint16; 98 | typedef int32_t ZrInt32; 99 | typedef uint32_t ZrUint32; 100 | typedef int64_t ZrInt64; 101 | typedef uint64_t ZrUint64; 102 | #else 103 | /* 104 | The focus here is on the common data models, that is ILP32 (most recent 105 | 32-bit systems), LP64 (Unix-like systems), and LLP64 (Windows). All of these 106 | models have the `char` type set to 8 bits, `short` to 16 bits, `int` to 107 | 32 bits, and `long long` to 64 bits. 108 | */ 109 | #ifdef ZR_INT8 110 | typedef ZR_INT8 ZrInt8; 111 | #else 112 | typedef char ZrInt8; 113 | #endif 114 | #ifdef ZR_UINT8 115 | typedef ZR_UINT8 ZrUint8; 116 | #else 117 | typedef unsigned char ZrUint8; 118 | #endif 119 | #ifdef ZR_INT16 120 | typedef ZR_INT16 ZrInt16; 121 | #else 122 | typedef short ZrInt16; 123 | #endif 124 | #ifdef ZR_UINT16 125 | typedef ZR_UINT16 ZrUint16; 126 | #else 127 | typedef unsigned short ZrUint16; 128 | #endif 129 | #ifdef ZR_INT32 130 | typedef ZR_INT32 ZrInt32; 131 | #else 132 | typedef int ZrInt32; 133 | #endif 134 | #ifdef ZR_UINT32 135 | typedef ZR_UINT32 ZrUint32; 136 | #else 137 | typedef unsigned int ZrUint32; 138 | #endif 139 | #ifdef ZR_INT64 140 | typedef ZR_INT64 ZrInt64; 141 | #else 142 | typedef long long ZrInt64; 143 | #endif 144 | #ifdef ZR_UINT64 145 | typedef ZR_UINT64 ZrUint64; 146 | #else 147 | typedef unsigned long long ZrUint64; 148 | #endif 149 | #endif /* ZR_USE_STD_FIXED_TYPES */ 150 | #ifdef ZR_DEFINE_IMPLEMENTATION 151 | typedef char zrp_invalid_int8_type[sizeof(ZrInt8) == 1 ? 1 : -1]; 152 | typedef char zrp_invalid_uint8_type[sizeof(ZrUint8) == 1 ? 1 : -1]; 153 | typedef char zrp_invalid_int16_type[sizeof(ZrInt16) == 2 ? 1 : -1]; 154 | typedef char zrp_invalid_uint16_type[sizeof(ZrUint16) == 2 ? 1 : -1]; 155 | typedef char zrp_invalid_int32_type[sizeof(ZrInt32) == 4 ? 1 : -1]; 156 | typedef char zrp_invalid_uint32_type[sizeof(ZrUint32) == 4 ? 1 : -1]; 157 | typedef char zrp_invalid_int64_type[sizeof(ZrInt64) == 8 ? 1 : -1]; 158 | typedef char zrp_invalid_uint64_type[sizeof(ZrUint64) == 8 ? 1 : -1]; 159 | #endif /* ZR_DEFINE_IMPLEMENTATION */ 160 | #endif /* ZRP_FIXED_TYPES_DEFINED */ 161 | 162 | #ifndef ZRP_BASIC_TYPES_DEFINED 163 | #define ZRP_BASIC_TYPES_DEFINED 164 | #ifdef ZR_USE_STD_BASIC_TYPES 165 | #include 166 | typedef size_t ZrSize; 167 | #else 168 | /* 169 | The C standard provides no guarantees about the size of the type `size_t`, 170 | and some exotic platforms will in fact provide original values, but this 171 | should cover most of the use cases. 172 | */ 173 | #ifdef ZR_SIZE_TYPE 174 | typedef ZR_SIZE_TYPE ZrSize; 175 | #elif ZR_ENVIRONMENT == 32 176 | typedef ZrUint32 ZrSize; 177 | #else 178 | typedef ZrUint64 ZrSize; 179 | #endif 180 | #endif 181 | #ifdef ZR_DEFINE_IMPLEMENTATION 182 | typedef char 183 | zrp_invalid_size_type[sizeof(ZrSize) == sizeof sizeof(void *) ? 1 : -1]; 184 | #endif /* ZR_DEFINE_IMPLEMENTATION */ 185 | #endif /* ZRP_BASIC_TYPES_DEFINED */ 186 | 187 | #if defined(ZR_ALLOCATOR_SPECIFY_INTERNAL_LINKAGE) \ 188 | || defined(ZR_SPECIFY_INTERNAL_LINKAGE) 189 | #define ZRP_ALLOCATOR_LINKAGE static 190 | #elif defined(__cplusplus) 191 | #define ZRP_ALLOCATOR_LINKAGE extern "C" 192 | #else 193 | #define ZRP_ALLOCATOR_LINKAGE extern 194 | #endif 195 | 196 | ZRP_ALLOCATOR_LINKAGE void * 197 | zrAllocate(ZrSize size); 198 | 199 | ZRP_ALLOCATOR_LINKAGE void * 200 | zrReallocate(void *pOriginal, ZrSize size); 201 | 202 | ZRP_ALLOCATOR_LINKAGE void 203 | zrFree(const void *pMemory); 204 | 205 | ZRP_ALLOCATOR_LINKAGE void * 206 | zrAllocateAligned(ZrSize size, ZrSize alignment); 207 | 208 | ZRP_ALLOCATOR_LINKAGE void * 209 | zrReallocateAligned(void *pOriginal, ZrSize size, ZrSize alignment); 210 | 211 | ZRP_ALLOCATOR_LINKAGE void 212 | zrFreeAligned(const void *pMemory); 213 | 214 | #endif /* ZERO_ALLOCATOR_H */ 215 | 216 | #ifdef ZR_DEFINE_IMPLEMENTATION 217 | #ifndef ZRP_ALLOCATOR_IMPLEMENTATION_DEFINED 218 | #define ZRP_ALLOCATOR_IMPLEMENTATION_DEFINED 219 | 220 | #include 221 | #include 222 | #include 223 | #include 224 | #include 225 | 226 | #ifndef ZR_ASSERT 227 | #include 228 | #define ZR_ASSERT assert 229 | #endif /* ZR_ASSERT */ 230 | 231 | #ifndef ZR_MALLOC 232 | #include 233 | #define ZR_MALLOC malloc 234 | #endif /* ZR_MALLOC */ 235 | 236 | #ifndef ZR_REALLOC 237 | #include 238 | #define ZR_REALLOC realloc 239 | #endif /* ZR_REALLOC */ 240 | 241 | #ifndef ZR_FREE 242 | #include 243 | #define ZR_FREE free 244 | #endif /* ZR_FREE */ 245 | 246 | #ifndef ZRP_UNUSED_DEFINED 247 | #define ZRP_UNUSED_DEFINED 248 | #ifdef __GNUC__ 249 | #define ZRP_MAYBE_UNUSED __attribute__((unused)) 250 | #else 251 | #define ZRP_MAYBE_UNUSED 252 | #endif 253 | #endif /* ZRP_UNUSED_DEFINED */ 254 | 255 | #ifndef ZRP_LOGGING_DEFINED 256 | #define ZRP_LOGGING_DEFINED 257 | 258 | #if defined(ZR_SET_LOGGING_LEVEL_DEBUG) 259 | #define ZRP_LOGGING_LEVEL ZR_LOG_LEVEL_DEBUG 260 | #elif defined(ZR_SET_LOGGING_LEVEL_TRACE) 261 | #define ZRP_LOGGING_LEVEL ZR_LOG_LEVEL_TRACE 262 | #elif defined(ZR_SET_LOGGING_LEVEL_INFO) 263 | #define ZRP_LOGGING_LEVEL ZR_LOG_LEVEL_INFO 264 | #elif defined(ZR_SET_LOGGING_LEVEL_WARNING) 265 | #define ZRP_LOGGING_LEVEL ZR_LOG_LEVEL_WARNING 266 | #elif defined(ZR_SET_LOGGING_LEVEL_ERROR) 267 | #define ZRP_LOGGING_LEVEL ZR_LOG_LEVEL_ERROR 268 | #elif defined(ZR_ENABLE_DEBUGGING) \ 269 | || (!defined(ZR_DISABLE_DEBUGGING) \ 270 | && (defined(DEBUG) || !defined(NDEBUG))) 271 | #define ZRP_LOGGING_LEVEL ZR_LOG_LEVEL_DEBUG 272 | #else 273 | #define ZRP_LOGGING_LEVEL ZR_LOG_LEVEL_WARNING 274 | #endif 275 | 276 | #ifdef ZR_DISABLE_LOGGING 277 | #define ZRP_LOGGING 0 278 | #else 279 | #define ZRP_LOGGING 1 280 | #endif /* ZR_DISABLE_LOGGING */ 281 | 282 | #ifndef ZR_LOG 283 | #define ZR_LOG(level, ...) \ 284 | do { \ 285 | if (ZRP_LOGGING && level <= ZRP_LOGGING_LEVEL) { \ 286 | zrpLoggerLog(level, __FILE__, __LINE__, __VA_ARGS__); \ 287 | } \ 288 | } while (0) 289 | #endif /* ZR_LOG */ 290 | 291 | #define ZRP_LOG_DEBUG(...) ZR_LOG(ZR_LOG_LEVEL_DEBUG, __VA_ARGS__) 292 | 293 | #define ZRP_LOG_TRACE(...) ZR_LOG(ZR_LOG_LEVEL_TRACE, __VA_ARGS__) 294 | 295 | #define ZRP_LOG_INFO(...) ZR_LOG(ZR_LOG_LEVEL_INFO, __VA_ARGS__) 296 | 297 | #define ZRP_LOG_WARNING(...) ZR_LOG(ZR_LOG_LEVEL_WARNING, __VA_ARGS__) 298 | 299 | #define ZRP_LOG_ERROR(...) ZR_LOG(ZR_LOG_LEVEL_ERROR, __VA_ARGS__) 300 | 301 | #endif /* ZRP_LOGGING_DEFINED */ 302 | 303 | #ifndef ZRP_LOGLEVEL_DEFINED 304 | #define ZRP_LOGLEVEL_DEFINED 305 | 306 | enum ZrLogLevel { 307 | ZR_LOG_LEVEL_ERROR = 0, 308 | ZR_LOG_LEVEL_WARNING = 1, 309 | ZR_LOG_LEVEL_INFO = 2, 310 | ZR_LOG_LEVEL_TRACE = 3, 311 | ZR_LOG_LEVEL_DEBUG = 4 312 | }; 313 | 314 | #endif /* ZRP_LOGLEVEL_DEFINED */ 315 | 316 | #ifndef ZRP_LOGGER_DEFINED 317 | #define ZRP_LOGGER_DEFINED 318 | 319 | #if !defined(ZR_DISABLE_LOG_STYLING) && defined(ZRP_PLATFORM_UNIX) \ 320 | && defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 1 321 | #include 322 | #define ZRP_LOGGER_LOG_STYLING 1 323 | #else 324 | #define ZRP_LOGGER_LOG_STYLING 0 325 | #endif 326 | 327 | #if ZRP_LOGGER_LOG_STYLING 328 | enum ZrpLoggerStyle { 329 | ZRP_LOGGER_STYLE_RESET = 0, 330 | ZRP_LOGGER_STYLE_BLACK = 1, 331 | ZRP_LOGGER_STYLE_RED = 2, 332 | ZRP_LOGGER_STYLE_GREEN = 3, 333 | ZRP_LOGGER_STYLE_YELLOW = 4, 334 | ZRP_LOGGER_STYLE_BLUE = 5, 335 | ZRP_LOGGER_STYLE_MAGENTA = 6, 336 | ZRP_LOGGER_STYLE_CYAN = 7, 337 | ZRP_LOGGER_STYLE_BRIGHT_BLACK = 8, 338 | ZRP_LOGGER_STYLE_BRIGHT_RED = 9, 339 | ZRP_LOGGER_STYLE_BRIGHT_GREEN = 10, 340 | ZRP_LOGGER_STYLE_BRIGHT_YELLOW = 11, 341 | ZRP_LOGGER_STYLE_BRIGHT_BLUE = 12, 342 | ZRP_LOGGER_STYLE_BRIGHT_MAGENTA = 13, 343 | ZRP_LOGGER_STYLE_BRIGHT_CYAN = 14 344 | }; 345 | #endif /* ZRP_LOGGER_LOG_STYLING */ 346 | 347 | static void 348 | zrpLoggerGetLogLevelName(const char **ppName, enum ZrLogLevel level) 349 | { 350 | ZR_ASSERT(ppName != NULL); 351 | 352 | switch (level) { 353 | case ZR_LOG_LEVEL_ERROR: 354 | *ppName = "error"; 355 | return; 356 | case ZR_LOG_LEVEL_WARNING: 357 | *ppName = "warning"; 358 | return; 359 | case ZR_LOG_LEVEL_INFO: 360 | *ppName = "info"; 361 | return; 362 | case ZR_LOG_LEVEL_TRACE: 363 | *ppName = "trace"; 364 | return; 365 | case ZR_LOG_LEVEL_DEBUG: 366 | *ppName = "debug"; 367 | return; 368 | default: 369 | ZR_ASSERT(0); 370 | } 371 | } 372 | 373 | #if ZRP_LOGGER_LOG_STYLING 374 | static void 375 | zrpLoggerGetLogLevelStyle(enum ZrpLoggerStyle *pStyle, enum ZrLogLevel level) 376 | { 377 | ZR_ASSERT(pStyle != NULL); 378 | 379 | switch (level) { 380 | case ZR_LOG_LEVEL_ERROR: 381 | *pStyle = ZRP_LOGGER_STYLE_BRIGHT_RED; 382 | return; 383 | case ZR_LOG_LEVEL_WARNING: 384 | *pStyle = ZRP_LOGGER_STYLE_BRIGHT_YELLOW; 385 | return; 386 | case ZR_LOG_LEVEL_INFO: 387 | *pStyle = ZRP_LOGGER_STYLE_BRIGHT_GREEN; 388 | return; 389 | case ZR_LOG_LEVEL_TRACE: 390 | *pStyle = ZRP_LOGGER_STYLE_BRIGHT_CYAN; 391 | return; 392 | case ZR_LOG_LEVEL_DEBUG: 393 | *pStyle = ZRP_LOGGER_STYLE_BRIGHT_MAGENTA; 394 | return; 395 | default: 396 | ZR_ASSERT(0); 397 | }; 398 | } 399 | 400 | static void 401 | zrpLoggerGetStyleAnsiCode(const char **ppCode, enum ZrpLoggerStyle style) 402 | { 403 | ZR_ASSERT(ppCode != NULL); 404 | 405 | switch (style) { 406 | case ZRP_LOGGER_STYLE_RESET: 407 | *ppCode = "\x1b[0m"; 408 | return; 409 | case ZRP_LOGGER_STYLE_BLACK: 410 | *ppCode = "\x1b[30m"; 411 | return; 412 | case ZRP_LOGGER_STYLE_RED: 413 | *ppCode = "\x1b[31m"; 414 | return; 415 | case ZRP_LOGGER_STYLE_GREEN: 416 | *ppCode = "\x1b[32m"; 417 | return; 418 | case ZRP_LOGGER_STYLE_YELLOW: 419 | *ppCode = "\x1b[33m"; 420 | return; 421 | case ZRP_LOGGER_STYLE_BLUE: 422 | *ppCode = "\x1b[34m"; 423 | return; 424 | case ZRP_LOGGER_STYLE_MAGENTA: 425 | *ppCode = "\x1b[35m"; 426 | return; 427 | case ZRP_LOGGER_STYLE_CYAN: 428 | *ppCode = "\x1b[36m"; 429 | return; 430 | case ZRP_LOGGER_STYLE_BRIGHT_BLACK: 431 | *ppCode = "\x1b[1;30m"; 432 | return; 433 | case ZRP_LOGGER_STYLE_BRIGHT_RED: 434 | *ppCode = "\x1b[1;31m"; 435 | return; 436 | case ZRP_LOGGER_STYLE_BRIGHT_GREEN: 437 | *ppCode = "\x1b[1;32m"; 438 | return; 439 | case ZRP_LOGGER_STYLE_BRIGHT_YELLOW: 440 | *ppCode = "\x1b[1;33m"; 441 | return; 442 | case ZRP_LOGGER_STYLE_BRIGHT_BLUE: 443 | *ppCode = "\x1b[1;34m"; 444 | return; 445 | case ZRP_LOGGER_STYLE_BRIGHT_MAGENTA: 446 | *ppCode = "\x1b[1;35m"; 447 | return; 448 | case ZRP_LOGGER_STYLE_BRIGHT_CYAN: 449 | *ppCode = "\x1b[1;36m"; 450 | return; 451 | default: 452 | ZR_ASSERT(0); 453 | } 454 | } 455 | #endif /* ZRP_LOGGER_LOG_STYLING */ 456 | 457 | ZRP_MAYBE_UNUSED static void 458 | zrpLoggerLogVaList(enum ZrLogLevel level, 459 | const char *pFile, 460 | int line, 461 | const char *pFormat, 462 | va_list args) 463 | { 464 | const char *pLevelName; 465 | const char *pLevelStyleStart; 466 | const char *pLevelStyleEnd; 467 | 468 | ZR_ASSERT(pFile != NULL); 469 | ZR_ASSERT(pFormat != NULL); 470 | 471 | zrpLoggerGetLogLevelName(&pLevelName, level); 472 | 473 | #if ZRP_LOGGER_LOG_STYLING 474 | if (isatty(fileno(stderr))) { 475 | enum ZrpLoggerStyle levelStyle; 476 | 477 | zrpLoggerGetLogLevelStyle(&levelStyle, level); 478 | zrpLoggerGetStyleAnsiCode(&pLevelStyleStart, levelStyle); 479 | zrpLoggerGetStyleAnsiCode(&pLevelStyleEnd, ZRP_LOGGER_STYLE_RESET); 480 | } else { 481 | pLevelStyleStart = pLevelStyleEnd = ""; 482 | } 483 | #else 484 | pLevelStyleStart = pLevelStyleEnd = ""; 485 | #endif /* ZRP_LOGGER_LOG_STYLING */ 486 | 487 | fprintf(stderr, 488 | "%s:%d: %s%s%s: ", 489 | pFile, 490 | line, 491 | pLevelStyleStart, 492 | pLevelName, 493 | pLevelStyleEnd); 494 | vfprintf(stderr, pFormat, args); 495 | } 496 | 497 | ZRP_MAYBE_UNUSED static void 498 | zrpLoggerLog(enum ZrLogLevel level, 499 | const char *pFile, 500 | int line, 501 | const char *pFormat, 502 | ...) 503 | { 504 | va_list args; 505 | 506 | ZR_ASSERT(pFile != NULL); 507 | ZR_ASSERT(pFormat != NULL); 508 | 509 | va_start(args, pFormat); 510 | zrpLoggerLogVaList(level, pFile, line, pFormat, args); 511 | va_end(args); 512 | } 513 | 514 | #endif /* ZRP_LOGGER_DEFINED */ 515 | 516 | #if defined(ZR_ALLOCATOR_ENABLE_DEBUGGING) || defined(ZR_ENABLE_DEBUGGING) 517 | #define ZRP_ALLOCATOR_DEBUGGING 1 518 | #else 519 | #define ZRP_ALLOCATOR_DEBUGGING 0 520 | #endif 521 | 522 | #define ZRP_ALLOCATOR_CAST_CONST(type, x) (type)(uintptr_t)(x) 523 | 524 | #ifdef __cplusplus 525 | template 526 | struct ZrpAllocatorAlignmentOfHelper { 527 | char first; 528 | T second; 529 | }; 530 | #define ZRP_ALLOCATOR_GET_ALIGNMENT_OF(type) \ 531 | offsetof(ZrpAllocatorAlignmentOfHelper, second) 532 | #else 533 | #define ZRP_ALLOCATOR_GET_ALIGNMENT_OF(type) \ 534 | offsetof( \ 535 | struct { \ 536 | char first; \ 537 | type second; \ 538 | }, \ 539 | second) 540 | #endif /* __cplusplus */ 541 | 542 | #define ZRP_ALLOCATOR_IS_POWER_OF_TWO(x) \ 543 | (((x) == ((x) & -(x))) && (x)) 544 | 545 | /* 546 | The aligned allocator works by allocating a block of larger size than 547 | requested to hold some necessary bookkeeping and some padding space to 548 | secure the desired alignment. 549 | 550 | block user pointer 551 | / / 552 | +---------+--------+------+---------+ 553 | | padding | header | size | padding | 554 | +---------+--------+------+---------+ 555 | \ \ 556 | 0 offset 557 | 558 | The sum of the front and back paddings equals `alignment - 1`, and the 559 | pointer returned to the user is located at a distance of `offset` from 560 | the beginning of the block. 561 | */ 562 | 563 | #define ZRP_ALLOCATOR_GET_ALIGNED_BLOCK(pBuffer, offset) \ 564 | (void *)((unsigned char *)(pBuffer) - (offset)) 565 | #define ZRP_ALLOCATOR_GET_ALIGNED_HEADER(pBuffer) \ 566 | ((struct ZrpAllocatorAlignedHeader *)(pBuffer))[-1] 567 | #define ZRP_ALLOCATOR_GET_ALIGNED_BUFFER(pBlock, alignment) \ 568 | (void *)((uintptr_t)((unsigned char *)(pBlock) + (alignment)-1 \ 569 | + sizeof(struct ZrpAllocatorAlignedHeader)) \ 570 | & ~(uintptr_t)((alignment)-1)) 571 | 572 | #define ZRP_ALLOCATOR_GET_ALIGNED_BLOCK_SIZE(size, alignment) \ 573 | (size) + (alignment)-1 + sizeof(struct ZrpAllocatorAlignedHeader) 574 | 575 | struct ZrpAllocatorAlignedHeader { 576 | ptrdiff_t offset; 577 | size_t size; 578 | #if ZRP_ALLOCATOR_DEBUGGING 579 | size_t alignment; 580 | #endif /* ZRP_ALLOCATOR_DEBUGGING */ 581 | }; 582 | 583 | typedef char zrp_allocator_invalid_aligned_header_alignment 584 | [ZRP_ALLOCATOR_IS_POWER_OF_TWO( 585 | ZRP_ALLOCATOR_GET_ALIGNMENT_OF(struct ZrpAllocatorAlignedHeader)) 586 | ? 1 587 | : -1]; 588 | typedef char zrp_allocator_invalid_void_pointer_alignment 589 | [ZRP_ALLOCATOR_IS_POWER_OF_TWO(sizeof(void *)) ? 1 : -1]; 590 | 591 | /* 592 | Any power of two alignment requested for the user pointer that is greater or 593 | equal to this minimum value is guaranteed to be a multiple of 594 | `sizeof(void *)`, thus conforming to the requirement of `posix_memalign()`, 595 | and is also guaranteed to provide correct alignment for the block header. 596 | */ 597 | static const size_t zrpAllocatorMinAlignment 598 | = ZRP_ALLOCATOR_GET_ALIGNMENT_OF(struct ZrpAllocatorAlignedHeader) 599 | > sizeof(void *) 600 | ? ZRP_ALLOCATOR_GET_ALIGNMENT_OF(struct ZrpAllocatorAlignedHeader) 601 | : sizeof(void *); 602 | 603 | ZRP_MAYBE_UNUSED static int 604 | zrpAllocatorIsPowerOfTwo(size_t x) 605 | { 606 | /* Verify exactly one bit is set. */ 607 | return (x == (x & -x)) && x; 608 | } 609 | 610 | ZRP_MAYBE_UNUSED ZRP_ALLOCATOR_LINKAGE void * 611 | zrAllocate(ZrSize size) 612 | { 613 | if (size == 0) { 614 | ZRP_LOG_INFO("allocation called with a size of 0\n"); 615 | return NULL; 616 | } 617 | 618 | return ZR_MALLOC((size_t)size); 619 | } 620 | 621 | ZRP_MAYBE_UNUSED ZRP_ALLOCATOR_LINKAGE void * 622 | zrReallocate(void *pOriginal, ZrSize size) 623 | { 624 | if (pOriginal == NULL) { 625 | return zrAllocate(size); 626 | } 627 | 628 | if (size == 0) { 629 | ZRP_LOG_INFO("reallocation called with a size of 0\n"); 630 | zrFree(pOriginal); 631 | return NULL; 632 | } 633 | 634 | return ZR_REALLOC(pOriginal, (size_t)size); 635 | } 636 | 637 | ZRP_MAYBE_UNUSED ZRP_ALLOCATOR_LINKAGE void 638 | zrFree(const void *pMemory) 639 | { 640 | ZR_FREE(ZRP_ALLOCATOR_CAST_CONST(void *, pMemory)); 641 | } 642 | 643 | ZRP_MAYBE_UNUSED ZRP_ALLOCATOR_LINKAGE void * 644 | zrAllocateAligned(ZrSize size, ZrSize alignment) 645 | { 646 | void *pBuffer; 647 | void *pBlock; 648 | struct ZrpAllocatorAlignedHeader *pHeader; 649 | 650 | ZR_ASSERT(zrpAllocatorIsPowerOfTwo((size_t)alignment)); 651 | 652 | if (size == 0) { 653 | ZRP_LOG_INFO("allocation called with a size of 0\n"); 654 | return NULL; 655 | } 656 | 657 | if (alignment < zrpAllocatorMinAlignment) { 658 | alignment = (ZrSize)zrpAllocatorMinAlignment; 659 | } 660 | 661 | pBlock = ZR_MALLOC( 662 | (size_t)ZRP_ALLOCATOR_GET_ALIGNED_BLOCK_SIZE(size, alignment)); 663 | if (pBlock == NULL) { 664 | ZRP_LOG_ERROR("failed to allocate the block\n"); 665 | return NULL; 666 | } 667 | 668 | pBuffer = ZRP_ALLOCATOR_GET_ALIGNED_BUFFER(pBlock, alignment); 669 | 670 | pHeader = &ZRP_ALLOCATOR_GET_ALIGNED_HEADER(pBuffer); 671 | pHeader->offset = (unsigned char *)pBuffer - (unsigned char *)pBlock; 672 | pHeader->size = (size_t)size; 673 | #if ZRP_ALLOCATOR_DEBUGGING 674 | pHeader->alignment = (size_t)alignment; 675 | #endif /* ZRP_ALLOCATOR_DEBUGGING */ 676 | 677 | return pBuffer; 678 | } 679 | 680 | ZRP_MAYBE_UNUSED ZRP_ALLOCATOR_LINKAGE void * 681 | zrReallocateAligned(void *pOriginal, ZrSize size, ZrSize alignment) 682 | { 683 | void *pBuffer; 684 | struct ZrpAllocatorAlignedHeader originalHeader; 685 | void *pOriginalBlock; 686 | void *pBlock; 687 | struct ZrpAllocatorAlignedHeader *pHeader; 688 | 689 | ZR_ASSERT(zrpAllocatorIsPowerOfTwo((size_t)alignment)); 690 | 691 | if (pOriginal == NULL) { 692 | return zrAllocateAligned(size, alignment); 693 | } 694 | 695 | if (size == 0) { 696 | ZRP_LOG_INFO("reallocation called with a size of 0\n"); 697 | zrFreeAligned(pOriginal); 698 | return NULL; 699 | } 700 | 701 | if (alignment < zrpAllocatorMinAlignment) { 702 | alignment = (ZrSize)zrpAllocatorMinAlignment; 703 | } 704 | 705 | originalHeader = ZRP_ALLOCATOR_GET_ALIGNED_HEADER(pOriginal); 706 | #if ZRP_ALLOCATOR_DEBUGGING 707 | ZR_ASSERT(alignment == originalHeader.alignment); 708 | #endif /* ZRP_ALLOCATOR_DEBUGGING */ 709 | 710 | pOriginalBlock 711 | = ZRP_ALLOCATOR_GET_ALIGNED_BLOCK(pOriginal, originalHeader.offset); 712 | pBlock = ZR_REALLOC( 713 | pOriginalBlock, 714 | (size_t)ZRP_ALLOCATOR_GET_ALIGNED_BLOCK_SIZE(size, alignment)); 715 | if (pBlock == NULL) { 716 | ZRP_LOG_ERROR("failed to allocate the block\n"); 717 | return NULL; 718 | } 719 | 720 | if (pBlock == pOriginalBlock) { 721 | /* `realloc()` expanded the block in place. */ 722 | ZRP_ALLOCATOR_GET_ALIGNED_HEADER(pOriginal).size = (size_t)size; 723 | return pOriginal; 724 | } 725 | 726 | pBuffer = ZRP_ALLOCATOR_GET_ALIGNED_BUFFER(pBlock, alignment); 727 | 728 | pHeader = &ZRP_ALLOCATOR_GET_ALIGNED_HEADER(pBuffer); 729 | pHeader->offset = (unsigned char *)pBuffer - (unsigned char *)pBlock; 730 | pHeader->size = (size_t)size; 731 | 732 | if (pHeader->offset == originalHeader.offset) { 733 | /* 734 | `realloc()` allocated a new block that is still correctly 735 | aligned. 736 | */ 737 | return pBuffer; 738 | } 739 | 740 | memmove(pBuffer, 741 | (void *)((unsigned char *)pBlock + originalHeader.offset), 742 | originalHeader.size); 743 | 744 | return pBuffer; 745 | } 746 | 747 | ZRP_MAYBE_UNUSED ZRP_ALLOCATOR_LINKAGE void 748 | zrFreeAligned(const void *pMemory) 749 | { 750 | struct ZrpAllocatorAlignedHeader *pHeader; 751 | 752 | if (pMemory == NULL) { 753 | return; 754 | } 755 | 756 | pHeader = &ZRP_ALLOCATOR_GET_ALIGNED_HEADER( 757 | ZRP_ALLOCATOR_CAST_CONST(void *, pMemory)); 758 | ZR_FREE(ZRP_ALLOCATOR_GET_ALIGNED_BLOCK( 759 | ZRP_ALLOCATOR_CAST_CONST(void *, pMemory), pHeader->offset)); 760 | } 761 | 762 | #endif /* ZRP_ALLOCATOR_IMPLEMENTATION_DEFINED */ 763 | #endif /* ZR_DEFINE_IMPLEMENTATION */ 764 | -------------------------------------------------------------------------------- /include/zero/dynamicarray.h: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2018 Christopher Crouzet 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | #ifndef ZERO_DYNAMICARRAY_H 26 | #define ZERO_DYNAMICARRAY_H 27 | 28 | #define ZR_DYNAMICARRAY_MAJOR_VERSION 0 29 | #define ZR_DYNAMICARRAY_MINOR_VERSION 1 30 | #define ZR_DYNAMICARRAY_PATCH_VERSION 1 31 | 32 | #ifndef ZRP_ARCH_DEFINED 33 | #define ZRP_ARCH_DEFINED 34 | #if defined(__x86_64__) || defined(_M_X64) 35 | #define ZRP_ARCH_X86_64 36 | #elif defined(__i386) || defined(_M_IX86) 37 | #define ZRP_ARCH_X86_32 38 | #elif defined(__itanium__) || defined(_M_IA64) 39 | #define ZRP_ARCH_ITANIUM_64 40 | #elif defined(__powerpc64__) || defined(__ppc64__) 41 | #define ZRP_ARCH_POWERPC_64 42 | #elif defined(__powerpc__) || defined(__ppc__) 43 | #define ZRP_ARCH_POWERPC_32 44 | #elif defined(__aarch64__) 45 | #define ZRP_ARCH_ARM_64 46 | #elif defined(__arm__) 47 | #define ZRP_ARCH_ARM_32 48 | #endif 49 | #endif /* ZRP_ARCH_DEFINED */ 50 | 51 | /* 52 | The environment macro represents whether the code is to be generated for a 53 | 32-bit or 64-bit target platform. Some CPUs, such as the x86-64 processors, 54 | allow running code in 32-bit mode if compiled using the -m32 or -mx32 55 | compiler switches, in which case `ZR_ENVIRONMENT` is set to 32. 56 | */ 57 | #ifndef ZR_ENVIRONMENT 58 | #if (!defined(ZRP_ARCH_X86_64) || defined(__ILP32__)) \ 59 | && !defined(ZRP_ARCH_ITANIUM_64) && !defined(ZRP_ARCH_POWERPC_64) \ 60 | && !defined(ZRP_ARCH_ARM_64) 61 | #define ZR_ENVIRONMENT 32 62 | #else 63 | #define ZR_ENVIRONMENT 64 64 | #endif 65 | #ifdef ZR_DEFINE_IMPLEMENTATION 66 | typedef char zrp_invalid_environment_value 67 | [ZR_ENVIRONMENT == 32 || ZR_ENVIRONMENT == 64 ? 1 : -1]; 68 | #endif /* ZR_DEFINE_IMPLEMENTATION */ 69 | #endif /* ZR_ENVIRONMENT */ 70 | 71 | #ifndef ZRP_PLATFORM_DEFINED 72 | #define ZRP_PLATFORM_DEFINED 73 | #if defined(_WIN32) 74 | #define ZRP_PLATFORM_WINDOWS 75 | #elif defined(__unix__) || defined(__APPLE__) 76 | #define ZRP_PLATFORM_UNIX 77 | #if defined(__APPLE__) 78 | #define ZRP_PLATFORM_DARWIN 79 | #if TARGET_OS_IPHONE == 1 80 | #define ZRP_PLATFORM_IOS 81 | #elif TARGET_OS_MAC == 1 82 | #define ZRP_PLATFORM_MACOS 83 | #endif 84 | #elif defined(__linux__) 85 | #define ZRP_PLATFORM_LINUX 86 | #endif 87 | #endif 88 | #endif /* ZRP_PLATFORM_DEFINED */ 89 | 90 | #ifndef ZRP_FIXED_TYPES_DEFINED 91 | #define ZRP_FIXED_TYPES_DEFINED 92 | #ifdef ZR_USE_STD_FIXED_TYPES 93 | #include 94 | typedef int8_t ZrInt8; 95 | typedef uint8_t ZrUint8; 96 | typedef int16_t ZrInt16; 97 | typedef uint16_t ZrUint16; 98 | typedef int32_t ZrInt32; 99 | typedef uint32_t ZrUint32; 100 | typedef int64_t ZrInt64; 101 | typedef uint64_t ZrUint64; 102 | #else 103 | /* 104 | The focus here is on the common data models, that is ILP32 (most recent 105 | 32-bit systems), LP64 (Unix-like systems), and LLP64 (Windows). All of these 106 | models have the `char` type set to 8 bits, `short` to 16 bits, `int` to 107 | 32 bits, and `long long` to 64 bits. 108 | */ 109 | #ifdef ZR_INT8 110 | typedef ZR_INT8 ZrInt8; 111 | #else 112 | typedef char ZrInt8; 113 | #endif 114 | #ifdef ZR_UINT8 115 | typedef ZR_UINT8 ZrUint8; 116 | #else 117 | typedef unsigned char ZrUint8; 118 | #endif 119 | #ifdef ZR_INT16 120 | typedef ZR_INT16 ZrInt16; 121 | #else 122 | typedef short ZrInt16; 123 | #endif 124 | #ifdef ZR_UINT16 125 | typedef ZR_UINT16 ZrUint16; 126 | #else 127 | typedef unsigned short ZrUint16; 128 | #endif 129 | #ifdef ZR_INT32 130 | typedef ZR_INT32 ZrInt32; 131 | #else 132 | typedef int ZrInt32; 133 | #endif 134 | #ifdef ZR_UINT32 135 | typedef ZR_UINT32 ZrUint32; 136 | #else 137 | typedef unsigned int ZrUint32; 138 | #endif 139 | #ifdef ZR_INT64 140 | typedef ZR_INT64 ZrInt64; 141 | #else 142 | typedef long long ZrInt64; 143 | #endif 144 | #ifdef ZR_UINT64 145 | typedef ZR_UINT64 ZrUint64; 146 | #else 147 | typedef unsigned long long ZrUint64; 148 | #endif 149 | #endif /* ZR_USE_STD_FIXED_TYPES */ 150 | #ifdef ZR_DEFINE_IMPLEMENTATION 151 | typedef char zrp_invalid_int8_type[sizeof(ZrInt8) == 1 ? 1 : -1]; 152 | typedef char zrp_invalid_uint8_type[sizeof(ZrUint8) == 1 ? 1 : -1]; 153 | typedef char zrp_invalid_int16_type[sizeof(ZrInt16) == 2 ? 1 : -1]; 154 | typedef char zrp_invalid_uint16_type[sizeof(ZrUint16) == 2 ? 1 : -1]; 155 | typedef char zrp_invalid_int32_type[sizeof(ZrInt32) == 4 ? 1 : -1]; 156 | typedef char zrp_invalid_uint32_type[sizeof(ZrUint32) == 4 ? 1 : -1]; 157 | typedef char zrp_invalid_int64_type[sizeof(ZrInt64) == 8 ? 1 : -1]; 158 | typedef char zrp_invalid_uint64_type[sizeof(ZrUint64) == 8 ? 1 : -1]; 159 | #endif /* ZR_DEFINE_IMPLEMENTATION */ 160 | #endif /* ZRP_FIXED_TYPES_DEFINED */ 161 | 162 | #ifndef ZRP_BASIC_TYPES_DEFINED 163 | #define ZRP_BASIC_TYPES_DEFINED 164 | #ifdef ZR_USE_STD_BASIC_TYPES 165 | #include 166 | typedef size_t ZrSize; 167 | #else 168 | /* 169 | The C standard provides no guarantees about the size of the type `size_t`, 170 | and some exotic platforms will in fact provide original values, but this 171 | should cover most of the use cases. 172 | */ 173 | #ifdef ZR_SIZE_TYPE 174 | typedef ZR_SIZE_TYPE ZrSize; 175 | #elif ZR_ENVIRONMENT == 32 176 | typedef ZrUint32 ZrSize; 177 | #else 178 | typedef ZrUint64 ZrSize; 179 | #endif 180 | #endif 181 | #ifdef ZR_DEFINE_IMPLEMENTATION 182 | typedef char 183 | zrp_invalid_size_type[sizeof(ZrSize) == sizeof sizeof(void *) ? 1 : -1]; 184 | #endif /* ZR_DEFINE_IMPLEMENTATION */ 185 | #endif /* ZRP_BASIC_TYPES_DEFINED */ 186 | 187 | #ifndef ZRP_STATUS_DEFINED 188 | #define ZRP_STATUS_DEFINED 189 | enum ZrStatus { 190 | ZR_SUCCESS = 0, 191 | ZR_ERROR = -1, 192 | ZR_ERROR_ALLOCATION = -2, 193 | ZR_ERROR_MAX_SIZE_EXCEEDED = -3 194 | }; 195 | #endif /* ZRP_STATUS_DEFINED */ 196 | 197 | #if defined(ZR_DYNAMICARRAY_SPECIFY_INTERNAL_LINKAGE) \ 198 | || defined(ZR_SPECIFY_INTERNAL_LINKAGE) 199 | #define ZRP_DYNAMICARRAY_LINKAGE static 200 | #elif defined(__cplusplus) 201 | #define ZRP_DYNAMICARRAY_LINKAGE extern "C" 202 | #else 203 | #define ZRP_DYNAMICARRAY_LINKAGE extern 204 | #endif 205 | 206 | #define ZRP_DYNAMICARRAY_DECLARE_CREATE_FUNCTION(name, type) \ 207 | ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus zrCreate##name(type **ppArray, \ 208 | ZrSize size) 209 | 210 | #define ZRP_DYNAMICARRAY_DECLARE_DESTROY_FUNCTION(name, type) \ 211 | ZRP_DYNAMICARRAY_LINKAGE void zrDestroy##name(type *pArray) 212 | 213 | #define ZRP_DYNAMICARRAY_DECLARE_GET_SIZE_FUNCTION(name, type) \ 214 | ZRP_DYNAMICARRAY_LINKAGE void zrGet##name##Size(const type *pArray, \ 215 | ZrSize *pSize) 216 | 217 | #define ZRP_DYNAMICARRAY_DECLARE_GET_CAPACITY_FUNCTION(name, type) \ 218 | ZRP_DYNAMICARRAY_LINKAGE void zrGet##name##Capacity(const type *pArray, \ 219 | ZrSize *pCapacity) 220 | 221 | #define ZRP_DYNAMICARRAY_DECLARE_GET_MAX_CAPACITY_FUNCTION(name, type) \ 222 | ZRP_DYNAMICARRAY_LINKAGE void zrGet##name##MaxCapacity(const type *pArray, \ 223 | ZrSize *pCapacity) 224 | 225 | #define ZRP_DYNAMICARRAY_DECLARE_RESIZE_FUNCTION(name, type) \ 226 | ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus zrResize##name(type **ppArray, \ 227 | ZrSize size) 228 | 229 | #define ZRP_DYNAMICARRAY_DECLARE_RESERVE_FUNCTION(name, type) \ 230 | ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus zrReserve##name(type **ppArray, \ 231 | ZrSize capacity) 232 | 233 | #define ZRP_DYNAMICARRAY_DECLARE_EXTEND_FUNCTION(name, type) \ 234 | ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus zrExtend##name( \ 235 | type **ppSlice, type **ppArray, ZrSize position, ZrSize size) 236 | 237 | #define ZRP_DYNAMICARRAY_DECLARE_EXTEND_FRONT_FUNCTION(name, type) \ 238 | ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus zrExtend##name##Front( \ 239 | type **ppSlice, type **ppArray, ZrSize size) 240 | 241 | #define ZRP_DYNAMICARRAY_DECLARE_EXTEND_BACK_FUNCTION(name, type) \ 242 | ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus zrExtend##name##Back( \ 243 | type **ppSlice, type **ppArray, ZrSize size) 244 | 245 | #define ZRP_DYNAMICARRAY_DECLARE_INSERT_FUNCTION(name, type) \ 246 | ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus zrInsert##name( \ 247 | type **ppArray, ZrSize position, ZrSize size, const type *pValues) 248 | 249 | #define ZRP_DYNAMICARRAY_DECLARE_INSERT_FRONT_FUNCTION(name, type) \ 250 | ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus zrInsert##name##Front( \ 251 | type **ppArray, ZrSize size, const type *pValues) 252 | 253 | #define ZRP_DYNAMICARRAY_DECLARE_INSERT_BACK_FUNCTION(name, type) \ 254 | ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus zrInsert##name##Back( \ 255 | type **ppArray, ZrSize size, const type *pValues) 256 | 257 | #define ZRP_DYNAMICARRAY_DECLARE_PUSH_FUNCTION(name, type) \ 258 | ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus zrPush##name( \ 259 | type **ppArray, ZrSize position, type value) 260 | 261 | #define ZRP_DYNAMICARRAY_DECLARE_PUSH_FRONT_FUNCTION(name, type) \ 262 | ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus zrPush##name##Front(type **ppArray, \ 263 | type value) 264 | 265 | #define ZRP_DYNAMICARRAY_DECLARE_PUSH_BACK_FUNCTION(name, type) \ 266 | ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus zrPush##name##Back(type **ppArray, \ 267 | type value) 268 | 269 | #define ZRP_DYNAMICARRAY_DECLARE_TRIM_FUNCTION(name, type) \ 270 | ZRP_DYNAMICARRAY_LINKAGE void zrTrim##name( \ 271 | type *pArray, ZrSize position, ZrSize size) 272 | 273 | #define ZRP_DYNAMICARRAY_DECLARE_TRIM_FRONT_FUNCTION(name, type) \ 274 | ZRP_DYNAMICARRAY_LINKAGE void zrTrim##name##Front(type *pArray, ZrSize size) 275 | 276 | #define ZRP_DYNAMICARRAY_DECLARE_TRIM_BACK_FUNCTION(name, type) \ 277 | ZRP_DYNAMICARRAY_LINKAGE void zrTrim##name##Back(type *pArray, ZrSize size) 278 | 279 | #define ZR_MAKE_DYNAMIC_ARRAY(name, type) \ 280 | ZRP_DYNAMICARRAY_DECLARE_MAX_CAPACITY(name, type) \ 281 | ZRP_DYNAMICARRAY_DECLARE_CREATE_FUNCTION(name, type) \ 282 | ZRP_DYNAMICARRAY_DECLARE_DESTROY_FUNCTION(name, type) \ 283 | ZRP_DYNAMICARRAY_DECLARE_GET_SIZE_FUNCTION(name, type) \ 284 | ZRP_DYNAMICARRAY_DECLARE_GET_CAPACITY_FUNCTION(name, type) \ 285 | ZRP_DYNAMICARRAY_DECLARE_GET_MAX_CAPACITY_FUNCTION(name, type) \ 286 | ZRP_DYNAMICARRAY_DECLARE_RESIZE_FUNCTION(name, type) \ 287 | ZRP_DYNAMICARRAY_DECLARE_RESERVE_FUNCTION(name, type) \ 288 | ZRP_DYNAMICARRAY_DECLARE_EXTEND_FUNCTION(name, type) \ 289 | ZRP_DYNAMICARRAY_DECLARE_EXTEND_FRONT_FUNCTION(name, type) \ 290 | ZRP_DYNAMICARRAY_DECLARE_EXTEND_BACK_FUNCTION(name, type) \ 291 | ZRP_DYNAMICARRAY_DECLARE_INSERT_FUNCTION(name, type) \ 292 | ZRP_DYNAMICARRAY_DECLARE_INSERT_FRONT_FUNCTION(name, type) \ 293 | ZRP_DYNAMICARRAY_DECLARE_INSERT_BACK_FUNCTION(name, type) \ 294 | ZRP_DYNAMICARRAY_DECLARE_PUSH_FUNCTION(name, type) \ 295 | ZRP_DYNAMICARRAY_DECLARE_PUSH_FRONT_FUNCTION(name, type) \ 296 | ZRP_DYNAMICARRAY_DECLARE_PUSH_BACK_FUNCTION(name, type) \ 297 | ZRP_DYNAMICARRAY_DECLARE_TRIM_FUNCTION(name, type) \ 298 | ZRP_DYNAMICARRAY_DECLARE_TRIM_FRONT_FUNCTION(name, type) \ 299 | ZRP_DYNAMICARRAY_DECLARE_TRIM_BACK_FUNCTION(name, type) 300 | 301 | #endif /* ZERO_DYNAMICARRAY_H */ 302 | 303 | #ifdef ZR_DEFINE_IMPLEMENTATION 304 | #ifndef ZRP_DYNAMICARRAY_IMPLEMENTATION_DEFINED 305 | #define ZRP_DYNAMICARRAY_IMPLEMENTATION_DEFINED 306 | 307 | #include 308 | #include 309 | #include 310 | #include 311 | 312 | #ifndef ZR_ASSERT 313 | #include 314 | #define ZR_ASSERT assert 315 | #endif /* ZR_ASSERT */ 316 | 317 | #ifndef ZR_REALLOC 318 | #include 319 | #define ZR_REALLOC realloc 320 | #endif /* ZR_REALLOC */ 321 | 322 | #ifndef ZR_FREE 323 | #include 324 | #define ZR_FREE free 325 | #endif /* ZR_FREE */ 326 | 327 | #ifndef ZRP_UNUSED_DEFINED 328 | #define ZRP_UNUSED_DEFINED 329 | #ifdef __GNUC__ 330 | #define ZRP_MAYBE_UNUSED __attribute__((unused)) 331 | #else 332 | #define ZRP_MAYBE_UNUSED 333 | #endif 334 | #endif /* ZRP_UNUSED_DEFINED */ 335 | 336 | #ifndef ZRP_LOGGING_DEFINED 337 | #define ZRP_LOGGING_DEFINED 338 | 339 | #if defined(ZR_SET_LOGGING_LEVEL_DEBUG) 340 | #define ZRP_LOGGING_LEVEL ZR_LOG_LEVEL_DEBUG 341 | #elif defined(ZR_SET_LOGGING_LEVEL_TRACE) 342 | #define ZRP_LOGGING_LEVEL ZR_LOG_LEVEL_TRACE 343 | #elif defined(ZR_SET_LOGGING_LEVEL_INFO) 344 | #define ZRP_LOGGING_LEVEL ZR_LOG_LEVEL_INFO 345 | #elif defined(ZR_SET_LOGGING_LEVEL_WARNING) 346 | #define ZRP_LOGGING_LEVEL ZR_LOG_LEVEL_WARNING 347 | #elif defined(ZR_SET_LOGGING_LEVEL_ERROR) 348 | #define ZRP_LOGGING_LEVEL ZR_LOG_LEVEL_ERROR 349 | #elif defined(ZR_ENABLE_DEBUGGING) \ 350 | || (!defined(ZR_DISABLE_DEBUGGING) \ 351 | && (defined(DEBUG) || !defined(NDEBUG))) 352 | #define ZRP_LOGGING_LEVEL ZR_LOG_LEVEL_DEBUG 353 | #else 354 | #define ZRP_LOGGING_LEVEL ZR_LOG_LEVEL_WARNING 355 | #endif 356 | 357 | #ifdef ZR_DISABLE_LOGGING 358 | #define ZRP_LOGGING 0 359 | #else 360 | #define ZRP_LOGGING 1 361 | #endif /* ZR_DISABLE_LOGGING */ 362 | 363 | #ifndef ZR_LOG 364 | #define ZR_LOG(level, ...) \ 365 | do { \ 366 | if (ZRP_LOGGING && level <= ZRP_LOGGING_LEVEL) { \ 367 | zrpLoggerLog(level, __FILE__, __LINE__, __VA_ARGS__); \ 368 | } \ 369 | } while (0) 370 | #endif /* ZR_LOG */ 371 | 372 | #define ZRP_LOG_DEBUG(...) ZR_LOG(ZR_LOG_LEVEL_DEBUG, __VA_ARGS__) 373 | 374 | #define ZRP_LOG_TRACE(...) ZR_LOG(ZR_LOG_LEVEL_TRACE, __VA_ARGS__) 375 | 376 | #define ZRP_LOG_INFO(...) ZR_LOG(ZR_LOG_LEVEL_INFO, __VA_ARGS__) 377 | 378 | #define ZRP_LOG_WARNING(...) ZR_LOG(ZR_LOG_LEVEL_WARNING, __VA_ARGS__) 379 | 380 | #define ZRP_LOG_ERROR(...) ZR_LOG(ZR_LOG_LEVEL_ERROR, __VA_ARGS__) 381 | 382 | #endif /* ZRP_LOGGING_DEFINED */ 383 | 384 | #ifndef ZRP_LOGLEVEL_DEFINED 385 | #define ZRP_LOGLEVEL_DEFINED 386 | 387 | enum ZrLogLevel { 388 | ZR_LOG_LEVEL_ERROR = 0, 389 | ZR_LOG_LEVEL_WARNING = 1, 390 | ZR_LOG_LEVEL_INFO = 2, 391 | ZR_LOG_LEVEL_TRACE = 3, 392 | ZR_LOG_LEVEL_DEBUG = 4 393 | }; 394 | 395 | #endif /* ZRP_LOGLEVEL_DEFINED */ 396 | 397 | #ifndef ZRP_LOGGER_DEFINED 398 | #define ZRP_LOGGER_DEFINED 399 | 400 | #if !defined(ZR_DISABLE_LOG_STYLING) && defined(ZRP_PLATFORM_UNIX) \ 401 | && defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 1 402 | #include 403 | #define ZRP_LOGGER_LOG_STYLING 1 404 | #else 405 | #define ZRP_LOGGER_LOG_STYLING 0 406 | #endif 407 | 408 | #if ZRP_LOGGER_LOG_STYLING 409 | enum ZrpLoggerStyle { 410 | ZRP_LOGGER_STYLE_RESET = 0, 411 | ZRP_LOGGER_STYLE_BLACK = 1, 412 | ZRP_LOGGER_STYLE_RED = 2, 413 | ZRP_LOGGER_STYLE_GREEN = 3, 414 | ZRP_LOGGER_STYLE_YELLOW = 4, 415 | ZRP_LOGGER_STYLE_BLUE = 5, 416 | ZRP_LOGGER_STYLE_MAGENTA = 6, 417 | ZRP_LOGGER_STYLE_CYAN = 7, 418 | ZRP_LOGGER_STYLE_BRIGHT_BLACK = 8, 419 | ZRP_LOGGER_STYLE_BRIGHT_RED = 9, 420 | ZRP_LOGGER_STYLE_BRIGHT_GREEN = 10, 421 | ZRP_LOGGER_STYLE_BRIGHT_YELLOW = 11, 422 | ZRP_LOGGER_STYLE_BRIGHT_BLUE = 12, 423 | ZRP_LOGGER_STYLE_BRIGHT_MAGENTA = 13, 424 | ZRP_LOGGER_STYLE_BRIGHT_CYAN = 14 425 | }; 426 | #endif /* ZRP_LOGGER_LOG_STYLING */ 427 | 428 | static void 429 | zrpLoggerGetLogLevelName(const char **ppName, enum ZrLogLevel level) 430 | { 431 | ZR_ASSERT(ppName != NULL); 432 | 433 | switch (level) { 434 | case ZR_LOG_LEVEL_ERROR: 435 | *ppName = "error"; 436 | return; 437 | case ZR_LOG_LEVEL_WARNING: 438 | *ppName = "warning"; 439 | return; 440 | case ZR_LOG_LEVEL_INFO: 441 | *ppName = "info"; 442 | return; 443 | case ZR_LOG_LEVEL_TRACE: 444 | *ppName = "trace"; 445 | return; 446 | case ZR_LOG_LEVEL_DEBUG: 447 | *ppName = "debug"; 448 | return; 449 | default: 450 | ZR_ASSERT(0); 451 | } 452 | } 453 | 454 | #if ZRP_LOGGER_LOG_STYLING 455 | static void 456 | zrpLoggerGetLogLevelStyle(enum ZrpLoggerStyle *pStyle, enum ZrLogLevel level) 457 | { 458 | ZR_ASSERT(pStyle != NULL); 459 | 460 | switch (level) { 461 | case ZR_LOG_LEVEL_ERROR: 462 | *pStyle = ZRP_LOGGER_STYLE_BRIGHT_RED; 463 | return; 464 | case ZR_LOG_LEVEL_WARNING: 465 | *pStyle = ZRP_LOGGER_STYLE_BRIGHT_YELLOW; 466 | return; 467 | case ZR_LOG_LEVEL_INFO: 468 | *pStyle = ZRP_LOGGER_STYLE_BRIGHT_GREEN; 469 | return; 470 | case ZR_LOG_LEVEL_TRACE: 471 | *pStyle = ZRP_LOGGER_STYLE_BRIGHT_CYAN; 472 | return; 473 | case ZR_LOG_LEVEL_DEBUG: 474 | *pStyle = ZRP_LOGGER_STYLE_BRIGHT_MAGENTA; 475 | return; 476 | default: 477 | ZR_ASSERT(0); 478 | }; 479 | } 480 | 481 | static void 482 | zrpLoggerGetStyleAnsiCode(const char **ppCode, enum ZrpLoggerStyle style) 483 | { 484 | ZR_ASSERT(ppCode != NULL); 485 | 486 | switch (style) { 487 | case ZRP_LOGGER_STYLE_RESET: 488 | *ppCode = "\x1b[0m"; 489 | return; 490 | case ZRP_LOGGER_STYLE_BLACK: 491 | *ppCode = "\x1b[30m"; 492 | return; 493 | case ZRP_LOGGER_STYLE_RED: 494 | *ppCode = "\x1b[31m"; 495 | return; 496 | case ZRP_LOGGER_STYLE_GREEN: 497 | *ppCode = "\x1b[32m"; 498 | return; 499 | case ZRP_LOGGER_STYLE_YELLOW: 500 | *ppCode = "\x1b[33m"; 501 | return; 502 | case ZRP_LOGGER_STYLE_BLUE: 503 | *ppCode = "\x1b[34m"; 504 | return; 505 | case ZRP_LOGGER_STYLE_MAGENTA: 506 | *ppCode = "\x1b[35m"; 507 | return; 508 | case ZRP_LOGGER_STYLE_CYAN: 509 | *ppCode = "\x1b[36m"; 510 | return; 511 | case ZRP_LOGGER_STYLE_BRIGHT_BLACK: 512 | *ppCode = "\x1b[1;30m"; 513 | return; 514 | case ZRP_LOGGER_STYLE_BRIGHT_RED: 515 | *ppCode = "\x1b[1;31m"; 516 | return; 517 | case ZRP_LOGGER_STYLE_BRIGHT_GREEN: 518 | *ppCode = "\x1b[1;32m"; 519 | return; 520 | case ZRP_LOGGER_STYLE_BRIGHT_YELLOW: 521 | *ppCode = "\x1b[1;33m"; 522 | return; 523 | case ZRP_LOGGER_STYLE_BRIGHT_BLUE: 524 | *ppCode = "\x1b[1;34m"; 525 | return; 526 | case ZRP_LOGGER_STYLE_BRIGHT_MAGENTA: 527 | *ppCode = "\x1b[1;35m"; 528 | return; 529 | case ZRP_LOGGER_STYLE_BRIGHT_CYAN: 530 | *ppCode = "\x1b[1;36m"; 531 | return; 532 | default: 533 | ZR_ASSERT(0); 534 | } 535 | } 536 | #endif /* ZRP_LOGGER_LOG_STYLING */ 537 | 538 | ZRP_MAYBE_UNUSED static void 539 | zrpLoggerLogVaList(enum ZrLogLevel level, 540 | const char *pFile, 541 | int line, 542 | const char *pFormat, 543 | va_list args) 544 | { 545 | const char *pLevelName; 546 | const char *pLevelStyleStart; 547 | const char *pLevelStyleEnd; 548 | 549 | ZR_ASSERT(pFile != NULL); 550 | ZR_ASSERT(pFormat != NULL); 551 | 552 | zrpLoggerGetLogLevelName(&pLevelName, level); 553 | 554 | #if ZRP_LOGGER_LOG_STYLING 555 | if (isatty(fileno(stderr))) { 556 | enum ZrpLoggerStyle levelStyle; 557 | 558 | zrpLoggerGetLogLevelStyle(&levelStyle, level); 559 | zrpLoggerGetStyleAnsiCode(&pLevelStyleStart, levelStyle); 560 | zrpLoggerGetStyleAnsiCode(&pLevelStyleEnd, ZRP_LOGGER_STYLE_RESET); 561 | } else { 562 | pLevelStyleStart = pLevelStyleEnd = ""; 563 | } 564 | #else 565 | pLevelStyleStart = pLevelStyleEnd = ""; 566 | #endif /* ZRP_LOGGER_LOG_STYLING */ 567 | 568 | fprintf(stderr, 569 | "%s:%d: %s%s%s: ", 570 | pFile, 571 | line, 572 | pLevelStyleStart, 573 | pLevelName, 574 | pLevelStyleEnd); 575 | vfprintf(stderr, pFormat, args); 576 | } 577 | 578 | ZRP_MAYBE_UNUSED static void 579 | zrpLoggerLog(enum ZrLogLevel level, 580 | const char *pFile, 581 | int line, 582 | const char *pFormat, 583 | ...) 584 | { 585 | va_list args; 586 | 587 | ZR_ASSERT(pFile != NULL); 588 | ZR_ASSERT(pFormat != NULL); 589 | 590 | va_start(args, pFormat); 591 | zrpLoggerLogVaList(level, pFile, line, pFormat, args); 592 | va_end(args); 593 | } 594 | 595 | #endif /* ZRP_LOGGER_DEFINED */ 596 | 597 | #define ZRP_DYNAMICARRAY_GET_BLOCK(pBuffer) \ 598 | ((void *)&((struct ZrpDynamicArrayHeader *)(pBuffer))[-1]) 599 | #define ZRP_DYNAMICARRAY_GET_HEADER(pBlock) \ 600 | ((struct ZrpDynamicArrayHeader *)(pBlock)) 601 | #define ZRP_DYNAMICARRAY_GET_BUFFER(pBlock) \ 602 | ((void *)&((struct ZrpDynamicArrayHeader *)(pBlock))[1]) 603 | #define ZRP_DYNAMICARRAY_GET_CONST_BLOCK(pBuffer) \ 604 | ((const void *)&((const struct ZrpDynamicArrayHeader *)pBuffer)[-1]) 605 | #define ZRP_DYNAMICARRAY_GET_CONST_HEADER(pBlock) \ 606 | ((const struct ZrpDynamicArrayHeader *)(pBlock)) 607 | 608 | #define ZRP_DYNAMICARRAY_DEFINE_MAX_CAPACITY(name, type) \ 609 | static const size_t zrpMax##name##Capacity \ 610 | = (((size_t)-1 - sizeof(struct ZrpDynamicArrayHeader)) \ 611 | / sizeof(type)); 612 | 613 | #define ZRP_DYNAMICARRAY_DEFINE_CREATE_FUNCTION(name, type) \ 614 | ZRP_MAYBE_UNUSED ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus zrCreate##name( \ 615 | type **ppArray, ZrSize size) \ 616 | { \ 617 | enum ZrStatus status; \ 618 | void *pBlock; \ 619 | \ 620 | ZR_ASSERT(ppArray != NULL); \ 621 | \ 622 | pBlock = NULL; \ 623 | \ 624 | status = zrpDynamicArrayEnsureHasEnoughCapacity( \ 625 | &pBlock, 0, (size_t)size, zrpMax##name##Capacity, sizeof(type)); \ 626 | if (status != ZR_SUCCESS) { \ 627 | ZRP_LOG_ERROR("failed to reserve a large enough capacity for the " \ 628 | "type ‘" #type "’ (requested capacity: %zu)\n", \ 629 | (size_t)size); \ 630 | return status; \ 631 | } \ 632 | \ 633 | ZR_ASSERT(pBlock != NULL); \ 634 | \ 635 | ZRP_DYNAMICARRAY_GET_HEADER(pBlock)->size = (size_t)size; \ 636 | ZRP_DYNAMICARRAY_GET_HEADER(pBlock)->capacity = (size_t)size; \ 637 | *ppArray = (type *)ZRP_DYNAMICARRAY_GET_BUFFER(pBlock); \ 638 | return ZR_SUCCESS; \ 639 | } 640 | 641 | #define ZRP_DYNAMICARRAY_DEFINE_DESTROY_FUNCTION(name, type) \ 642 | ZRP_MAYBE_UNUSED ZRP_DYNAMICARRAY_LINKAGE void zrDestroy##name( \ 643 | type *pArray) \ 644 | { \ 645 | if (pArray == NULL) { \ 646 | return; \ 647 | } \ 648 | \ 649 | ZR_FREE(ZRP_DYNAMICARRAY_GET_BLOCK(pArray)); \ 650 | } 651 | 652 | #define ZRP_DYNAMICARRAY_DEFINE_GET_SIZE_FUNCTION(name, type) \ 653 | ZRP_MAYBE_UNUSED ZRP_DYNAMICARRAY_LINKAGE void zrGet##name##Size( \ 654 | ZrSize *pSize, const type *pArray) \ 655 | { \ 656 | ZR_ASSERT(pArray != NULL); \ 657 | \ 658 | *pSize = (ZrSize)ZRP_DYNAMICARRAY_GET_CONST_HEADER( \ 659 | ZRP_DYNAMICARRAY_GET_CONST_BLOCK(pArray)) \ 660 | ->size; \ 661 | } 662 | 663 | #define ZRP_DYNAMICARRAY_DEFINE_GET_CAPACITY_FUNCTION(name, type) \ 664 | ZRP_MAYBE_UNUSED ZRP_DYNAMICARRAY_LINKAGE void zrGet##name##Capacity( \ 665 | ZrSize *pCapacity, const type *pArray) \ 666 | { \ 667 | ZR_ASSERT(pArray != NULL); \ 668 | \ 669 | *pCapacity = (ZrSize)ZRP_DYNAMICARRAY_GET_CONST_HEADER( \ 670 | ZRP_DYNAMICARRAY_GET_CONST_BLOCK(pArray)) \ 671 | ->capacity; \ 672 | } 673 | 674 | #define ZRP_DYNAMICARRAY_DEFINE_GET_MAX_CAPACITY_FUNCTION(name, type) \ 675 | ZRP_MAYBE_UNUSED ZRP_DYNAMICARRAY_LINKAGE void zrGet##name##MaxCapacity( \ 676 | ZrSize *pMaxCapacity) \ 677 | { \ 678 | *pMaxCapacity = zrpMax##name##Capacity; \ 679 | } 680 | 681 | #define ZRP_DYNAMICARRAY_DEFINE_RESIZE_FUNCTION(name, type) \ 682 | ZRP_MAYBE_UNUSED ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus zrResize##name( \ 683 | type **ppArray, ZrSize size) \ 684 | { \ 685 | enum ZrStatus status; \ 686 | void *pBlock; \ 687 | \ 688 | ZR_ASSERT(ppArray != NULL); \ 689 | ZR_ASSERT(*ppArray != NULL); \ 690 | \ 691 | pBlock = ZRP_DYNAMICARRAY_GET_BLOCK(*ppArray); \ 692 | \ 693 | status = zrpDynamicArrayEnsureHasEnoughCapacity( \ 694 | &pBlock, \ 695 | ZRP_DYNAMICARRAY_GET_HEADER(pBlock)->capacity, \ 696 | (size_t)size, \ 697 | zrpMax##name##Capacity, \ 698 | sizeof(type)); \ 699 | if (status != ZR_SUCCESS) { \ 700 | ZRP_LOG_ERROR("failed to reserve a large enough capacity for the " \ 701 | "type ‘" #type "’ (requested capacity: %zu)\n", \ 702 | (size_t)size); \ 703 | return status; \ 704 | } \ 705 | \ 706 | ZR_ASSERT(pBlock != NULL); \ 707 | \ 708 | ZRP_DYNAMICARRAY_GET_HEADER(pBlock)->size = (size_t)size; \ 709 | *ppArray = (type *)ZRP_DYNAMICARRAY_GET_BUFFER(pBlock); \ 710 | return ZR_SUCCESS; \ 711 | } 712 | 713 | #define ZRP_DYNAMICARRAY_DEFINE_RESERVE_FUNCTION(name, type) \ 714 | ZRP_MAYBE_UNUSED ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus zrReserve##name( \ 715 | type **ppArray, ZrSize capacity) \ 716 | { \ 717 | enum ZrStatus status; \ 718 | void *pBlock; \ 719 | \ 720 | ZR_ASSERT(ppArray != NULL); \ 721 | ZR_ASSERT(*ppArray != NULL); \ 722 | \ 723 | pBlock = ZRP_DYNAMICARRAY_GET_BLOCK(*ppArray); \ 724 | \ 725 | status = zrpDynamicArrayEnsureHasEnoughCapacity( \ 726 | &pBlock, \ 727 | ZRP_DYNAMICARRAY_GET_HEADER(pBlock)->capacity, \ 728 | (size_t)capacity, \ 729 | zrpMax##name##Capacity, \ 730 | sizeof(type)); \ 731 | if (status != ZR_SUCCESS) { \ 732 | ZRP_LOG_ERROR("failed to reserve a large enough capacity for the " \ 733 | "type ‘" #type "’ (requested capacity: %zu)\n", \ 734 | (size_t)capacity); \ 735 | return status; \ 736 | } \ 737 | \ 738 | ZR_ASSERT(pBlock != NULL); \ 739 | \ 740 | *ppArray = (type *)ZRP_DYNAMICARRAY_GET_BUFFER(pBlock); \ 741 | return ZR_SUCCESS; \ 742 | } 743 | 744 | #define ZRP_DYNAMICARRAY_DEFINE_EXTEND_FUNCTION(name, type) \ 745 | ZRP_MAYBE_UNUSED ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus zrExtend##name( \ 746 | type **ppSlice, type **ppArray, ZrSize position, ZrSize size) \ 747 | { \ 748 | enum ZrStatus status; \ 749 | void *pBlock; \ 750 | \ 751 | ZR_ASSERT(ppArray != NULL); \ 752 | ZR_ASSERT(*ppArray != NULL); \ 753 | \ 754 | pBlock = ZRP_DYNAMICARRAY_GET_BLOCK(*ppArray); \ 755 | \ 756 | if (position > ZRP_DYNAMICARRAY_GET_HEADER(pBlock)->size) { \ 757 | position = (ZrSize)ZRP_DYNAMICARRAY_GET_HEADER(pBlock)->size; \ 758 | } \ 759 | \ 760 | status = zrpDynamicArrayEnsureHasEnoughCapacity( \ 761 | &pBlock, \ 762 | ZRP_DYNAMICARRAY_GET_HEADER(pBlock)->capacity, \ 763 | ZRP_DYNAMICARRAY_GET_HEADER(pBlock)->size + (size_t)size, \ 764 | zrpMax##name##Capacity, \ 765 | sizeof(type)); \ 766 | if (status != ZR_SUCCESS) { \ 767 | ZRP_LOG_ERROR( \ 768 | "failed to reserve a large enough capacity for the " \ 769 | "type ‘" #type "’ (requested capacity: %zu)\n", \ 770 | ZRP_DYNAMICARRAY_GET_HEADER(pBlock)->size + (size_t)size); \ 771 | return status; \ 772 | } \ 773 | \ 774 | ZR_ASSERT(pBlock != NULL); \ 775 | \ 776 | *ppArray = (type *)ZRP_DYNAMICARRAY_GET_BUFFER(pBlock); \ 777 | \ 778 | memmove(&(*ppArray)[(size_t)position + (size_t)size], \ 779 | &(*ppArray)[(size_t)position], \ 780 | sizeof(type) \ 781 | * (ZRP_DYNAMICARRAY_GET_HEADER(pBlock)->size \ 782 | - (size_t)position)); \ 783 | \ 784 | if (ppSlice != NULL) { \ 785 | *ppSlice = &(*ppArray)[position]; \ 786 | } \ 787 | \ 788 | ZRP_DYNAMICARRAY_GET_HEADER(pBlock)->size += (size_t)size; \ 789 | return ZR_SUCCESS; \ 790 | } 791 | 792 | #define ZRP_DYNAMICARRAY_DEFINE_EXTEND_FRONT_FUNCTION(name, type) \ 793 | ZRP_MAYBE_UNUSED ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus \ 794 | zrExtend##name##Front(type **ppSlice, type **ppArray, ZrSize size) \ 795 | { \ 796 | return zrExtend##name(ppSlice, ppArray, 0, size); \ 797 | } 798 | 799 | #define ZRP_DYNAMICARRAY_DEFINE_EXTEND_BACK_FUNCTION(name, type) \ 800 | ZRP_MAYBE_UNUSED ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus \ 801 | zrExtend##name##Back(type **ppSlice, type **ppArray, ZrSize size) \ 802 | { \ 803 | return zrExtend##name(ppSlice, \ 804 | ppArray, \ 805 | (ZrSize)ZRP_DYNAMICARRAY_GET_HEADER( \ 806 | ZRP_DYNAMICARRAY_GET_BLOCK(*ppArray)) \ 807 | ->size, \ 808 | size); \ 809 | } 810 | 811 | #define ZRP_DYNAMICARRAY_DEFINE_INSERT_FUNCTION(name, type) \ 812 | ZRP_MAYBE_UNUSED ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus zrInsert##name( \ 813 | type **ppArray, ZrSize position, ZrSize size, const type *pValues) \ 814 | { \ 815 | enum ZrStatus status; \ 816 | type *pSlice; \ 817 | \ 818 | ZR_ASSERT(ppArray != NULL); \ 819 | ZR_ASSERT(*ppArray != NULL); \ 820 | ZR_ASSERT(pValues != NULL); \ 821 | \ 822 | status = zrExtend##name(&pSlice, ppArray, position, size); \ 823 | if (status != ZR_SUCCESS) { \ 824 | ZRP_LOG_ERROR("failed to extend the array\n"); \ 825 | return status; \ 826 | } \ 827 | \ 828 | memcpy(pSlice, pValues, sizeof(type) * (size_t)size); \ 829 | return ZR_SUCCESS; \ 830 | } 831 | 832 | #define ZRP_DYNAMICARRAY_DEFINE_INSERT_FRONT_FUNCTION(name, type) \ 833 | ZRP_MAYBE_UNUSED ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus \ 834 | zrInsert##name##Front( \ 835 | type **ppArray, ZrSize size, const type *pValues) \ 836 | { \ 837 | return zrInsert##name(ppArray, 0, size, pValues); \ 838 | } 839 | 840 | #define ZRP_DYNAMICARRAY_DEFINE_INSERT_BACK_FUNCTION(name, type) \ 841 | ZRP_MAYBE_UNUSED ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus \ 842 | zrInsert##name##Back(type **ppArray, ZrSize size, const type *pValues) \ 843 | { \ 844 | return zrInsert##name(ppArray, (ZrSize)-1, size, pValues); \ 845 | } 846 | 847 | #define ZRP_DYNAMICARRAY_DEFINE_PUSH_FUNCTION(name, type) \ 848 | ZRP_MAYBE_UNUSED ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus zrPush##name( \ 849 | type **ppArray, ZrSize position, type value) \ 850 | { \ 851 | enum ZrStatus status; \ 852 | type *pSlice; \ 853 | \ 854 | ZR_ASSERT(ppArray != NULL); \ 855 | ZR_ASSERT(*ppArray != NULL); \ 856 | \ 857 | status = zrExtend##name(&pSlice, ppArray, position, 1); \ 858 | if (status != ZR_SUCCESS) { \ 859 | ZRP_LOG_ERROR("failed to extend the array\n"); \ 860 | return status; \ 861 | } \ 862 | \ 863 | *pSlice = value; \ 864 | return ZR_SUCCESS; \ 865 | } 866 | 867 | #define ZRP_DYNAMICARRAY_DEFINE_PUSH_FRONT_FUNCTION(name, type) \ 868 | ZRP_MAYBE_UNUSED ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus \ 869 | zrPush##name##Front(type **ppArray, type value) \ 870 | { \ 871 | return zrPush##name(ppArray, 0, value); \ 872 | } 873 | 874 | #define ZRP_DYNAMICARRAY_DEFINE_PUSH_BACK_FUNCTION(name, type) \ 875 | ZRP_MAYBE_UNUSED ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus \ 876 | zrPush##name##Back(type **ppArray, type value) \ 877 | { \ 878 | return zrPush##name(ppArray, (ZrSize)-1, value); \ 879 | } 880 | 881 | #define ZRP_DYNAMICARRAY_DEFINE_TRIM_FUNCTION(name, type) \ 882 | ZRP_MAYBE_UNUSED ZRP_DYNAMICARRAY_LINKAGE void zrTrim##name( \ 883 | type *pArray, ZrSize position, ZrSize size) \ 884 | { \ 885 | void *pBlock; \ 886 | \ 887 | ZR_ASSERT(pArray != NULL); \ 888 | \ 889 | pBlock = ZRP_DYNAMICARRAY_GET_BLOCK(pArray); \ 890 | \ 891 | if (position >= ZRP_DYNAMICARRAY_GET_HEADER(pBlock)->size) { \ 892 | return; \ 893 | } \ 894 | \ 895 | if (size > ZRP_DYNAMICARRAY_GET_HEADER(pBlock)->size - position) { \ 896 | size = ZRP_DYNAMICARRAY_GET_HEADER(pBlock)->size - position; \ 897 | } \ 898 | \ 899 | memmove(&pArray[position], \ 900 | &pArray[position + size], \ 901 | sizeof(type) * (size_t)size); \ 902 | ZRP_DYNAMICARRAY_GET_HEADER(pBlock)->size -= (size_t)size; \ 903 | } 904 | 905 | #define ZRP_DYNAMICARRAY_DEFINE_TRIM_FRONT_FUNCTION(name, type) \ 906 | ZRP_MAYBE_UNUSED ZRP_DYNAMICARRAY_LINKAGE void zrTrim##name##Front( \ 907 | type *pArray, ZrSize size) \ 908 | { \ 909 | zrTrim##name(pArray, 0, size); \ 910 | } 911 | 912 | #define ZRP_DYNAMICARRAY_DEFINE_TRIM_BACK_FUNCTION(name, type) \ 913 | ZRP_MAYBE_UNUSED ZRP_DYNAMICARRAY_LINKAGE void zrTrim##name##Back( \ 914 | type *pArray, ZrSize size) \ 915 | { \ 916 | zrTrim##name(pArray, (ZrSize)-1, size); \ 917 | } 918 | 919 | #undef ZR_MAKE_DYNAMIC_ARRAY 920 | #define ZR_MAKE_DYNAMIC_ARRAY(name, type) \ 921 | ZRP_DYNAMICARRAY_DEFINE_MAX_CAPACITY(name, type) \ 922 | ZRP_DYNAMICARRAY_DEFINE_CREATE_FUNCTION(name, type) \ 923 | ZRP_DYNAMICARRAY_DEFINE_DESTROY_FUNCTION(name, type) \ 924 | ZRP_DYNAMICARRAY_DEFINE_GET_SIZE_FUNCTION(name, type) \ 925 | ZRP_DYNAMICARRAY_DEFINE_GET_CAPACITY_FUNCTION(name, type) \ 926 | ZRP_DYNAMICARRAY_DEFINE_GET_MAX_CAPACITY_FUNCTION(name, type) \ 927 | ZRP_DYNAMICARRAY_DEFINE_RESIZE_FUNCTION(name, type) \ 928 | ZRP_DYNAMICARRAY_DEFINE_RESERVE_FUNCTION(name, type) \ 929 | ZRP_DYNAMICARRAY_DEFINE_EXTEND_FUNCTION(name, type) \ 930 | ZRP_DYNAMICARRAY_DEFINE_EXTEND_FRONT_FUNCTION(name, type) \ 931 | ZRP_DYNAMICARRAY_DEFINE_EXTEND_BACK_FUNCTION(name, type) \ 932 | ZRP_DYNAMICARRAY_DEFINE_INSERT_FUNCTION(name, type) \ 933 | ZRP_DYNAMICARRAY_DEFINE_INSERT_FRONT_FUNCTION(name, type) \ 934 | ZRP_DYNAMICARRAY_DEFINE_INSERT_BACK_FUNCTION(name, type) \ 935 | ZRP_DYNAMICARRAY_DEFINE_PUSH_FUNCTION(name, type) \ 936 | ZRP_DYNAMICARRAY_DEFINE_PUSH_FRONT_FUNCTION(name, type) \ 937 | ZRP_DYNAMICARRAY_DEFINE_PUSH_BACK_FUNCTION(name, type) \ 938 | ZRP_DYNAMICARRAY_DEFINE_TRIM_FUNCTION(name, type) \ 939 | ZRP_DYNAMICARRAY_DEFINE_TRIM_FRONT_FUNCTION(name, type) \ 940 | ZRP_DYNAMICARRAY_DEFINE_TRIM_BACK_FUNCTION(name, type) 941 | 942 | struct ZrpDynamicArrayHeader { 943 | size_t size; 944 | size_t capacity; 945 | }; 946 | 947 | ZRP_MAYBE_UNUSED static void 948 | zrpDynamicArrayGetNewCapacity(size_t *pNewCapacity, 949 | size_t current, 950 | size_t requested, 951 | size_t max) 952 | { 953 | *pNewCapacity = current + current / 2 + 1; 954 | if (*pNewCapacity < current) { 955 | *pNewCapacity = max; 956 | return; 957 | } 958 | 959 | if (*pNewCapacity < requested) { 960 | *pNewCapacity = requested; 961 | } 962 | } 963 | 964 | ZRP_MAYBE_UNUSED static enum ZrStatus 965 | zrpDynamicArrayEnsureHasEnoughCapacity(void **ppBlock, 966 | size_t currentCapacity, 967 | size_t requestedCapacity, 968 | size_t maxCapacity, 969 | size_t elementSize) 970 | { 971 | void *pBlock; 972 | size_t newCapacity; 973 | 974 | ZR_ASSERT(ppBlock != NULL); 975 | ZR_ASSERT(elementSize > 0); 976 | 977 | if (requestedCapacity > maxCapacity) { 978 | ZRP_LOG_TRACE("the requested capacity is too large\n"); 979 | return ZR_ERROR_MAX_SIZE_EXCEEDED; 980 | } 981 | 982 | if (*ppBlock != NULL && currentCapacity >= requestedCapacity) { 983 | return ZR_SUCCESS; 984 | } 985 | 986 | zrpDynamicArrayGetNewCapacity( 987 | &newCapacity, currentCapacity, requestedCapacity, maxCapacity); 988 | ZR_ASSERT(newCapacity >= requestedCapacity); 989 | ZR_ASSERT(newCapacity <= maxCapacity); 990 | 991 | pBlock = ZR_REALLOC( 992 | *ppBlock, 993 | sizeof(struct ZrpDynamicArrayHeader) + elementSize * newCapacity); 994 | if (pBlock == NULL) { 995 | ZRP_LOG_TRACE("failed to reallocate the block\n"); 996 | return ZR_ERROR_ALLOCATION; 997 | } 998 | 999 | ZRP_DYNAMICARRAY_GET_HEADER(pBlock)->capacity = newCapacity; 1000 | *ppBlock = pBlock; 1001 | return ZR_SUCCESS; 1002 | } 1003 | 1004 | #endif /* ZRP_DYNAMICARRAY_IMPLEMENTATION_DEFINED */ 1005 | #endif /* ZR_DEFINE_IMPLEMENTATION */ 1006 | -------------------------------------------------------------------------------- /include/zero/logger.h: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2018 Christopher Crouzet 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | #ifndef ZERO_LOGGER_H 26 | #define ZERO_LOGGER_H 27 | 28 | #include 29 | 30 | #define ZR_LOGGER_MAJOR_VERSION 0 31 | #define ZR_LOGGER_MINOR_VERSION 1 32 | #define ZR_LOGGER_PATCH_VERSION 1 33 | 34 | #ifndef ZRP_PLATFORM_DEFINED 35 | #define ZRP_PLATFORM_DEFINED 36 | #if defined(_WIN32) 37 | #define ZRP_PLATFORM_WINDOWS 38 | #elif defined(__unix__) || defined(__APPLE__) 39 | #define ZRP_PLATFORM_UNIX 40 | #if defined(__APPLE__) 41 | #define ZRP_PLATFORM_DARWIN 42 | #if TARGET_OS_IPHONE == 1 43 | #define ZRP_PLATFORM_IOS 44 | #elif TARGET_OS_MAC == 1 45 | #define ZRP_PLATFORM_MACOS 46 | #endif 47 | #elif defined(__linux__) 48 | #define ZRP_PLATFORM_LINUX 49 | #endif 50 | #endif 51 | #endif /* ZRP_PLATFORM_DEFINED */ 52 | 53 | #if defined(ZR_LOGGER_SPECIFY_INTERNAL_LINKAGE) \ 54 | || defined(ZR_SPECIFY_INTERNAL_LINKAGE) 55 | #define ZRP_LOGGER_LINKAGE static 56 | #elif defined(__cplusplus) 57 | #define ZRP_LOGGER_LINKAGE extern "C" 58 | #else 59 | #define ZRP_LOGGER_LINKAGE extern 60 | #endif 61 | 62 | #ifndef ZRP_LOGLEVEL_DEFINED 63 | #define ZRP_LOGLEVEL_DEFINED 64 | 65 | enum ZrLogLevel { 66 | ZR_LOG_LEVEL_ERROR = 0, 67 | ZR_LOG_LEVEL_WARNING = 1, 68 | ZR_LOG_LEVEL_INFO = 2, 69 | ZR_LOG_LEVEL_TRACE = 3, 70 | ZR_LOG_LEVEL_DEBUG = 4 71 | }; 72 | 73 | #endif /* ZRP_LOGLEVEL_DEFINED */ 74 | 75 | ZRP_LOGGER_LINKAGE void 76 | zrLog(enum ZrLogLevel level, 77 | const char *pFile, 78 | int line, 79 | const char *pFormat, 80 | ...); 81 | 82 | ZRP_LOGGER_LINKAGE void 83 | zrLogVaList(enum ZrLogLevel level, 84 | const char *pFile, 85 | int line, 86 | const char *pFormat, 87 | va_list args); 88 | 89 | #endif /* ZERO_LOGGER_H */ 90 | 91 | #ifdef ZR_DEFINE_IMPLEMENTATION 92 | #ifndef ZRP_LOGGER_IMPLEMENTATION_DEFINED 93 | #define ZRP_LOGGER_IMPLEMENTATION_DEFINED 94 | 95 | #include 96 | #include 97 | #include 98 | 99 | #ifndef ZR_ASSERT 100 | #include 101 | #define ZR_ASSERT assert 102 | #endif /* ZR_ASSERT */ 103 | 104 | #ifndef ZRP_UNUSED_DEFINED 105 | #define ZRP_UNUSED_DEFINED 106 | #ifdef __GNUC__ 107 | #define ZRP_MAYBE_UNUSED __attribute__((unused)) 108 | #else 109 | #define ZRP_MAYBE_UNUSED 110 | #endif 111 | #endif /* ZRP_UNUSED_DEFINED */ 112 | 113 | #ifndef ZRP_LOGGER_DEFINED 114 | #define ZRP_LOGGER_DEFINED 115 | 116 | #if !defined(ZR_DISABLE_LOG_STYLING) && defined(ZRP_PLATFORM_UNIX) \ 117 | && defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 1 118 | #include 119 | #define ZRP_LOGGER_LOG_STYLING 1 120 | #else 121 | #define ZRP_LOGGER_LOG_STYLING 0 122 | #endif 123 | 124 | #if ZRP_LOGGER_LOG_STYLING 125 | enum ZrpLoggerStyle { 126 | ZRP_LOGGER_STYLE_RESET = 0, 127 | ZRP_LOGGER_STYLE_BLACK = 1, 128 | ZRP_LOGGER_STYLE_RED = 2, 129 | ZRP_LOGGER_STYLE_GREEN = 3, 130 | ZRP_LOGGER_STYLE_YELLOW = 4, 131 | ZRP_LOGGER_STYLE_BLUE = 5, 132 | ZRP_LOGGER_STYLE_MAGENTA = 6, 133 | ZRP_LOGGER_STYLE_CYAN = 7, 134 | ZRP_LOGGER_STYLE_BRIGHT_BLACK = 8, 135 | ZRP_LOGGER_STYLE_BRIGHT_RED = 9, 136 | ZRP_LOGGER_STYLE_BRIGHT_GREEN = 10, 137 | ZRP_LOGGER_STYLE_BRIGHT_YELLOW = 11, 138 | ZRP_LOGGER_STYLE_BRIGHT_BLUE = 12, 139 | ZRP_LOGGER_STYLE_BRIGHT_MAGENTA = 13, 140 | ZRP_LOGGER_STYLE_BRIGHT_CYAN = 14 141 | }; 142 | #endif /* ZRP_LOGGER_LOG_STYLING */ 143 | 144 | static void 145 | zrpLoggerGetLogLevelName(const char **ppName, enum ZrLogLevel level) 146 | { 147 | ZR_ASSERT(ppName != NULL); 148 | 149 | switch (level) { 150 | case ZR_LOG_LEVEL_ERROR: 151 | *ppName = "error"; 152 | return; 153 | case ZR_LOG_LEVEL_WARNING: 154 | *ppName = "warning"; 155 | return; 156 | case ZR_LOG_LEVEL_INFO: 157 | *ppName = "info"; 158 | return; 159 | case ZR_LOG_LEVEL_TRACE: 160 | *ppName = "trace"; 161 | return; 162 | case ZR_LOG_LEVEL_DEBUG: 163 | *ppName = "debug"; 164 | return; 165 | default: 166 | ZR_ASSERT(0); 167 | } 168 | } 169 | 170 | #if ZRP_LOGGER_LOG_STYLING 171 | static void 172 | zrpLoggerGetLogLevelStyle(enum ZrpLoggerStyle *pStyle, enum ZrLogLevel level) 173 | { 174 | ZR_ASSERT(pStyle != NULL); 175 | 176 | switch (level) { 177 | case ZR_LOG_LEVEL_ERROR: 178 | *pStyle = ZRP_LOGGER_STYLE_BRIGHT_RED; 179 | return; 180 | case ZR_LOG_LEVEL_WARNING: 181 | *pStyle = ZRP_LOGGER_STYLE_BRIGHT_YELLOW; 182 | return; 183 | case ZR_LOG_LEVEL_INFO: 184 | *pStyle = ZRP_LOGGER_STYLE_BRIGHT_GREEN; 185 | return; 186 | case ZR_LOG_LEVEL_TRACE: 187 | *pStyle = ZRP_LOGGER_STYLE_BRIGHT_CYAN; 188 | return; 189 | case ZR_LOG_LEVEL_DEBUG: 190 | *pStyle = ZRP_LOGGER_STYLE_BRIGHT_MAGENTA; 191 | return; 192 | default: 193 | ZR_ASSERT(0); 194 | }; 195 | } 196 | 197 | static void 198 | zrpLoggerGetStyleAnsiCode(const char **ppCode, enum ZrpLoggerStyle style) 199 | { 200 | ZR_ASSERT(ppCode != NULL); 201 | 202 | switch (style) { 203 | case ZRP_LOGGER_STYLE_RESET: 204 | *ppCode = "\x1b[0m"; 205 | return; 206 | case ZRP_LOGGER_STYLE_BLACK: 207 | *ppCode = "\x1b[30m"; 208 | return; 209 | case ZRP_LOGGER_STYLE_RED: 210 | *ppCode = "\x1b[31m"; 211 | return; 212 | case ZRP_LOGGER_STYLE_GREEN: 213 | *ppCode = "\x1b[32m"; 214 | return; 215 | case ZRP_LOGGER_STYLE_YELLOW: 216 | *ppCode = "\x1b[33m"; 217 | return; 218 | case ZRP_LOGGER_STYLE_BLUE: 219 | *ppCode = "\x1b[34m"; 220 | return; 221 | case ZRP_LOGGER_STYLE_MAGENTA: 222 | *ppCode = "\x1b[35m"; 223 | return; 224 | case ZRP_LOGGER_STYLE_CYAN: 225 | *ppCode = "\x1b[36m"; 226 | return; 227 | case ZRP_LOGGER_STYLE_BRIGHT_BLACK: 228 | *ppCode = "\x1b[1;30m"; 229 | return; 230 | case ZRP_LOGGER_STYLE_BRIGHT_RED: 231 | *ppCode = "\x1b[1;31m"; 232 | return; 233 | case ZRP_LOGGER_STYLE_BRIGHT_GREEN: 234 | *ppCode = "\x1b[1;32m"; 235 | return; 236 | case ZRP_LOGGER_STYLE_BRIGHT_YELLOW: 237 | *ppCode = "\x1b[1;33m"; 238 | return; 239 | case ZRP_LOGGER_STYLE_BRIGHT_BLUE: 240 | *ppCode = "\x1b[1;34m"; 241 | return; 242 | case ZRP_LOGGER_STYLE_BRIGHT_MAGENTA: 243 | *ppCode = "\x1b[1;35m"; 244 | return; 245 | case ZRP_LOGGER_STYLE_BRIGHT_CYAN: 246 | *ppCode = "\x1b[1;36m"; 247 | return; 248 | default: 249 | ZR_ASSERT(0); 250 | } 251 | } 252 | #endif /* ZRP_LOGGER_LOG_STYLING */ 253 | 254 | ZRP_MAYBE_UNUSED static void 255 | zrpLoggerLogVaList(enum ZrLogLevel level, 256 | const char *pFile, 257 | int line, 258 | const char *pFormat, 259 | va_list args) 260 | { 261 | const char *pLevelName; 262 | const char *pLevelStyleStart; 263 | const char *pLevelStyleEnd; 264 | 265 | ZR_ASSERT(pFile != NULL); 266 | ZR_ASSERT(pFormat != NULL); 267 | 268 | zrpLoggerGetLogLevelName(&pLevelName, level); 269 | 270 | #if ZRP_LOGGER_LOG_STYLING 271 | if (isatty(fileno(stderr))) { 272 | enum ZrpLoggerStyle levelStyle; 273 | 274 | zrpLoggerGetLogLevelStyle(&levelStyle, level); 275 | zrpLoggerGetStyleAnsiCode(&pLevelStyleStart, levelStyle); 276 | zrpLoggerGetStyleAnsiCode(&pLevelStyleEnd, ZRP_LOGGER_STYLE_RESET); 277 | } else { 278 | pLevelStyleStart = pLevelStyleEnd = ""; 279 | } 280 | #else 281 | pLevelStyleStart = pLevelStyleEnd = ""; 282 | #endif /* ZRP_LOGGER_LOG_STYLING */ 283 | 284 | fprintf(stderr, 285 | "%s:%d: %s%s%s: ", 286 | pFile, 287 | line, 288 | pLevelStyleStart, 289 | pLevelName, 290 | pLevelStyleEnd); 291 | vfprintf(stderr, pFormat, args); 292 | } 293 | 294 | ZRP_MAYBE_UNUSED static void 295 | zrpLoggerLog(enum ZrLogLevel level, 296 | const char *pFile, 297 | int line, 298 | const char *pFormat, 299 | ...) 300 | { 301 | va_list args; 302 | 303 | ZR_ASSERT(pFile != NULL); 304 | ZR_ASSERT(pFormat != NULL); 305 | 306 | va_start(args, pFormat); 307 | zrpLoggerLogVaList(level, pFile, line, pFormat, args); 308 | va_end(args); 309 | } 310 | 311 | #endif /* ZRP_LOGGER_DEFINED */ 312 | 313 | ZRP_MAYBE_UNUSED ZRP_LOGGER_LINKAGE void 314 | zrLog(enum ZrLogLevel level, 315 | const char *pFile, 316 | int line, 317 | const char *pFormat, 318 | ...) 319 | { 320 | va_list args; 321 | 322 | ZR_ASSERT(pFile != NULL); 323 | ZR_ASSERT(pFormat != NULL); 324 | 325 | va_start(args, pFormat); 326 | zrpLoggerLogVaList(level, pFile, line, pFormat, args); 327 | va_end(args); 328 | } 329 | 330 | ZRP_MAYBE_UNUSED ZRP_LOGGER_LINKAGE void 331 | zrLogVaList(enum ZrLogLevel level, 332 | const char *pFile, 333 | int line, 334 | const char *pFormat, 335 | va_list args) 336 | { 337 | ZR_ASSERT(pFile != NULL); 338 | ZR_ASSERT(pFormat != NULL); 339 | 340 | zrpLoggerLogVaList(level, pFile, line, pFormat, args); 341 | } 342 | 343 | #endif /* ZRP_LOGGER_IMPLEMENTATION_DEFINED */ 344 | #endif /* ZR_DEFINE_IMPLEMENTATION */ 345 | -------------------------------------------------------------------------------- /include/zero/timer.h: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2018 Christopher Crouzet 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | #ifndef ZERO_TIMER_H 26 | #define ZERO_TIMER_H 27 | 28 | #define ZR_TIMER_MAJOR_VERSION 0 29 | #define ZR_TIMER_MINOR_VERSION 1 30 | #define ZR_TIMER_PATCH_VERSION 0 31 | 32 | #ifndef ZRP_ARCH_DEFINED 33 | #define ZRP_ARCH_DEFINED 34 | #if defined(__x86_64__) || defined(_M_X64) 35 | #define ZRP_ARCH_X86_64 36 | #elif defined(__i386) || defined(_M_IX86) 37 | #define ZRP_ARCH_X86_32 38 | #elif defined(__itanium__) || defined(_M_IA64) 39 | #define ZRP_ARCH_ITANIUM_64 40 | #elif defined(__powerpc64__) || defined(__ppc64__) 41 | #define ZRP_ARCH_POWERPC_64 42 | #elif defined(__powerpc__) || defined(__ppc__) 43 | #define ZRP_ARCH_POWERPC_32 44 | #elif defined(__aarch64__) 45 | #define ZRP_ARCH_ARM_64 46 | #elif defined(__arm__) 47 | #define ZRP_ARCH_ARM_32 48 | #endif 49 | #endif /* ZRP_ARCH_DEFINED */ 50 | 51 | /* 52 | The environment macro represents whether the code is to be generated for a 53 | 32-bit or 64-bit target platform. Some CPUs, such as the x86-64 processors, 54 | allow running code in 32-bit mode if compiled using the -m32 or -mx32 55 | compiler switches, in which case `ZR_ENVIRONMENT` is set to 32. 56 | */ 57 | #ifndef ZR_ENVIRONMENT 58 | #if (!defined(ZRP_ARCH_X86_64) || defined(__ILP32__)) \ 59 | && !defined(ZRP_ARCH_ITANIUM_64) && !defined(ZRP_ARCH_POWERPC_64) \ 60 | && !defined(ZRP_ARCH_ARM_64) 61 | #define ZR_ENVIRONMENT 32 62 | #else 63 | #define ZR_ENVIRONMENT 64 64 | #endif 65 | #ifdef ZR_DEFINE_IMPLEMENTATION 66 | typedef char zrp_invalid_environment_value 67 | [ZR_ENVIRONMENT == 32 || ZR_ENVIRONMENT == 64 ? 1 : -1]; 68 | #endif /* ZR_DEFINE_IMPLEMENTATION */ 69 | #endif /* ZR_ENVIRONMENT */ 70 | 71 | #ifndef ZRP_PLATFORM_DEFINED 72 | #define ZRP_PLATFORM_DEFINED 73 | #if defined(_WIN32) 74 | #define ZRP_PLATFORM_WINDOWS 75 | #elif defined(__unix__) || defined(__APPLE__) 76 | #define ZRP_PLATFORM_UNIX 77 | #if defined(__APPLE__) 78 | #define ZRP_PLATFORM_DARWIN 79 | #if TARGET_OS_IPHONE == 1 80 | #define ZRP_PLATFORM_IOS 81 | #elif TARGET_OS_MAC == 1 82 | #define ZRP_PLATFORM_MACOS 83 | #endif 84 | #elif defined(__linux__) 85 | #define ZRP_PLATFORM_LINUX 86 | #endif 87 | #endif 88 | #endif /* ZRP_PLATFORM_DEFINED */ 89 | 90 | #ifndef ZRP_FIXED_TYPES_DEFINED 91 | #define ZRP_FIXED_TYPES_DEFINED 92 | #ifdef ZR_USE_STD_FIXED_TYPES 93 | #include 94 | typedef int8_t ZrInt8; 95 | typedef uint8_t ZrUint8; 96 | typedef int16_t ZrInt16; 97 | typedef uint16_t ZrUint16; 98 | typedef int32_t ZrInt32; 99 | typedef uint32_t ZrUint32; 100 | typedef int64_t ZrInt64; 101 | typedef uint64_t ZrUint64; 102 | #else 103 | /* 104 | The focus here is on the common data models, that is ILP32 (most recent 105 | 32-bit systems), LP64 (Unix-like systems), and LLP64 (Windows). All of these 106 | models have the `char` type set to 8 bits, `short` to 16 bits, `int` to 107 | 32 bits, and `long long` to 64 bits. 108 | */ 109 | #ifdef ZR_INT8 110 | typedef ZR_INT8 ZrInt8; 111 | #else 112 | typedef char ZrInt8; 113 | #endif 114 | #ifdef ZR_UINT8 115 | typedef ZR_UINT8 ZrUint8; 116 | #else 117 | typedef unsigned char ZrUint8; 118 | #endif 119 | #ifdef ZR_INT16 120 | typedef ZR_INT16 ZrInt16; 121 | #else 122 | typedef short ZrInt16; 123 | #endif 124 | #ifdef ZR_UINT16 125 | typedef ZR_UINT16 ZrUint16; 126 | #else 127 | typedef unsigned short ZrUint16; 128 | #endif 129 | #ifdef ZR_INT32 130 | typedef ZR_INT32 ZrInt32; 131 | #else 132 | typedef int ZrInt32; 133 | #endif 134 | #ifdef ZR_UINT32 135 | typedef ZR_UINT32 ZrUint32; 136 | #else 137 | typedef unsigned int ZrUint32; 138 | #endif 139 | #ifdef ZR_INT64 140 | typedef ZR_INT64 ZrInt64; 141 | #else 142 | typedef long long ZrInt64; 143 | #endif 144 | #ifdef ZR_UINT64 145 | typedef ZR_UINT64 ZrUint64; 146 | #else 147 | typedef unsigned long long ZrUint64; 148 | #endif 149 | #endif /* ZR_USE_STD_FIXED_TYPES */ 150 | #ifdef ZR_DEFINE_IMPLEMENTATION 151 | typedef char zrp_invalid_int8_type[sizeof(ZrInt8) == 1 ? 1 : -1]; 152 | typedef char zrp_invalid_uint8_type[sizeof(ZrUint8) == 1 ? 1 : -1]; 153 | typedef char zrp_invalid_int16_type[sizeof(ZrInt16) == 2 ? 1 : -1]; 154 | typedef char zrp_invalid_uint16_type[sizeof(ZrUint16) == 2 ? 1 : -1]; 155 | typedef char zrp_invalid_int32_type[sizeof(ZrInt32) == 4 ? 1 : -1]; 156 | typedef char zrp_invalid_uint32_type[sizeof(ZrUint32) == 4 ? 1 : -1]; 157 | typedef char zrp_invalid_int64_type[sizeof(ZrInt64) == 8 ? 1 : -1]; 158 | typedef char zrp_invalid_uint64_type[sizeof(ZrUint64) == 8 ? 1 : -1]; 159 | #endif /* ZR_DEFINE_IMPLEMENTATION */ 160 | #endif /* ZRP_FIXED_TYPES_DEFINED */ 161 | 162 | #ifndef ZRP_BASIC_TYPES_DEFINED 163 | #define ZRP_BASIC_TYPES_DEFINED 164 | #ifdef ZR_USE_STD_BASIC_TYPES 165 | #include 166 | typedef size_t ZrSize; 167 | #else 168 | /* 169 | The C standard provides no guarantees about the size of the type `size_t`, 170 | and some exotic platforms will in fact provide original values, but this 171 | should cover most of the use cases. 172 | */ 173 | #ifdef ZR_SIZE_TYPE 174 | typedef ZR_SIZE_TYPE ZrSize; 175 | #elif ZR_ENVIRONMENT == 32 176 | typedef ZrUint32 ZrSize; 177 | #else 178 | typedef ZrUint64 ZrSize; 179 | #endif 180 | #endif 181 | #ifdef ZR_DEFINE_IMPLEMENTATION 182 | typedef char 183 | zrp_invalid_size_type[sizeof(ZrSize) == sizeof sizeof(void *) ? 1 : -1]; 184 | #endif /* ZR_DEFINE_IMPLEMENTATION */ 185 | #endif /* ZRP_BASIC_TYPES_DEFINED */ 186 | 187 | #ifndef ZRP_STATUS_DEFINED 188 | #define ZRP_STATUS_DEFINED 189 | enum ZrStatus { 190 | ZR_SUCCESS = 0, 191 | ZR_ERROR = -1, 192 | ZR_ERROR_ALLOCATION = -2, 193 | ZR_ERROR_MAX_SIZE_EXCEEDED = -3 194 | }; 195 | #endif /* ZRP_STATUS_DEFINED */ 196 | 197 | #if defined(ZR_TIMER_SPECIFY_INTERNAL_LINKAGE) \ 198 | || defined(ZR_SPECIFY_INTERNAL_LINKAGE) 199 | #define ZRP_TIMER_LINKAGE static 200 | #elif defined(__cplusplus) 201 | #define ZRP_TIMER_LINKAGE extern "C" 202 | #else 203 | #define ZRP_TIMER_LINKAGE extern 204 | #endif 205 | 206 | #define ZR_TIMER_TICKS_PER_SECOND 1000000000ull 207 | 208 | struct ZrCpuTimes { 209 | ZrUint64 user; 210 | ZrUint64 system; 211 | }; 212 | 213 | ZRP_TIMER_LINKAGE enum ZrStatus 214 | zrGetRealTime(ZrUint64 *pTime); 215 | 216 | ZRP_TIMER_LINKAGE enum ZrStatus 217 | zrGetCpuTimes(struct ZrCpuTimes *pTimes); 218 | 219 | #endif /* ZERO_TIMER_H */ 220 | 221 | #ifdef ZR_DEFINE_IMPLEMENTATION 222 | #ifndef ZRP_TIMER_IMPLEMENTATION_DEFINED 223 | #define ZRP_TIMER_IMPLEMENTATION_DEFINED 224 | 225 | #include 226 | #include 227 | #include 228 | 229 | #ifndef ZR_ASSERT 230 | #include 231 | #define ZR_ASSERT assert 232 | #endif /* ZR_ASSERT */ 233 | 234 | #ifndef ZRP_UNUSED_DEFINED 235 | #define ZRP_UNUSED_DEFINED 236 | #ifdef __GNUC__ 237 | #define ZRP_MAYBE_UNUSED __attribute__((unused)) 238 | #else 239 | #define ZRP_MAYBE_UNUSED 240 | #endif 241 | #endif /* ZRP_UNUSED_DEFINED */ 242 | 243 | #ifndef ZRP_LOGGING_DEFINED 244 | #define ZRP_LOGGING_DEFINED 245 | 246 | #if defined(ZR_SET_LOGGING_LEVEL_DEBUG) 247 | #define ZRP_LOGGING_LEVEL ZR_LOG_LEVEL_DEBUG 248 | #elif defined(ZR_SET_LOGGING_LEVEL_TRACE) 249 | #define ZRP_LOGGING_LEVEL ZR_LOG_LEVEL_TRACE 250 | #elif defined(ZR_SET_LOGGING_LEVEL_INFO) 251 | #define ZRP_LOGGING_LEVEL ZR_LOG_LEVEL_INFO 252 | #elif defined(ZR_SET_LOGGING_LEVEL_WARNING) 253 | #define ZRP_LOGGING_LEVEL ZR_LOG_LEVEL_WARNING 254 | #elif defined(ZR_SET_LOGGING_LEVEL_ERROR) 255 | #define ZRP_LOGGING_LEVEL ZR_LOG_LEVEL_ERROR 256 | #elif defined(ZR_ENABLE_DEBUGGING) \ 257 | || (!defined(ZR_DISABLE_DEBUGGING) \ 258 | && (defined(DEBUG) || !defined(NDEBUG))) 259 | #define ZRP_LOGGING_LEVEL ZR_LOG_LEVEL_DEBUG 260 | #else 261 | #define ZRP_LOGGING_LEVEL ZR_LOG_LEVEL_WARNING 262 | #endif 263 | 264 | #ifdef ZR_DISABLE_LOGGING 265 | #define ZRP_LOGGING 0 266 | #else 267 | #define ZRP_LOGGING 1 268 | #endif /* ZR_DISABLE_LOGGING */ 269 | 270 | #ifndef ZR_LOG 271 | #define ZR_LOG(level, ...) \ 272 | do { \ 273 | if (ZRP_LOGGING && level <= ZRP_LOGGING_LEVEL) { \ 274 | zrpLoggerLog(level, __FILE__, __LINE__, __VA_ARGS__); \ 275 | } \ 276 | } while (0) 277 | #endif /* ZR_LOG */ 278 | 279 | #define ZRP_LOG_DEBUG(...) ZR_LOG(ZR_LOG_LEVEL_DEBUG, __VA_ARGS__) 280 | 281 | #define ZRP_LOG_TRACE(...) ZR_LOG(ZR_LOG_LEVEL_TRACE, __VA_ARGS__) 282 | 283 | #define ZRP_LOG_INFO(...) ZR_LOG(ZR_LOG_LEVEL_INFO, __VA_ARGS__) 284 | 285 | #define ZRP_LOG_WARNING(...) ZR_LOG(ZR_LOG_LEVEL_WARNING, __VA_ARGS__) 286 | 287 | #define ZRP_LOG_ERROR(...) ZR_LOG(ZR_LOG_LEVEL_ERROR, __VA_ARGS__) 288 | 289 | #endif /* ZRP_LOGGING_DEFINED */ 290 | 291 | #ifndef ZRP_LOGLEVEL_DEFINED 292 | #define ZRP_LOGLEVEL_DEFINED 293 | 294 | enum ZrLogLevel { 295 | ZR_LOG_LEVEL_ERROR = 0, 296 | ZR_LOG_LEVEL_WARNING = 1, 297 | ZR_LOG_LEVEL_INFO = 2, 298 | ZR_LOG_LEVEL_TRACE = 3, 299 | ZR_LOG_LEVEL_DEBUG = 4 300 | }; 301 | 302 | #endif /* ZRP_LOGLEVEL_DEFINED */ 303 | 304 | #ifndef ZRP_LOGGER_DEFINED 305 | #define ZRP_LOGGER_DEFINED 306 | 307 | #if !defined(ZR_DISABLE_LOG_STYLING) && defined(ZRP_PLATFORM_UNIX) \ 308 | && defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 1 309 | #include 310 | #define ZRP_LOGGER_LOG_STYLING 1 311 | #else 312 | #define ZRP_LOGGER_LOG_STYLING 0 313 | #endif 314 | 315 | #if ZRP_LOGGER_LOG_STYLING 316 | enum ZrpLoggerStyle { 317 | ZRP_LOGGER_STYLE_RESET = 0, 318 | ZRP_LOGGER_STYLE_BLACK = 1, 319 | ZRP_LOGGER_STYLE_RED = 2, 320 | ZRP_LOGGER_STYLE_GREEN = 3, 321 | ZRP_LOGGER_STYLE_YELLOW = 4, 322 | ZRP_LOGGER_STYLE_BLUE = 5, 323 | ZRP_LOGGER_STYLE_MAGENTA = 6, 324 | ZRP_LOGGER_STYLE_CYAN = 7, 325 | ZRP_LOGGER_STYLE_BRIGHT_BLACK = 8, 326 | ZRP_LOGGER_STYLE_BRIGHT_RED = 9, 327 | ZRP_LOGGER_STYLE_BRIGHT_GREEN = 10, 328 | ZRP_LOGGER_STYLE_BRIGHT_YELLOW = 11, 329 | ZRP_LOGGER_STYLE_BRIGHT_BLUE = 12, 330 | ZRP_LOGGER_STYLE_BRIGHT_MAGENTA = 13, 331 | ZRP_LOGGER_STYLE_BRIGHT_CYAN = 14 332 | }; 333 | #endif /* ZRP_LOGGER_LOG_STYLING */ 334 | 335 | static void 336 | zrpLoggerGetLogLevelName(const char **ppName, enum ZrLogLevel level) 337 | { 338 | ZR_ASSERT(ppName != NULL); 339 | 340 | switch (level) { 341 | case ZR_LOG_LEVEL_ERROR: 342 | *ppName = "error"; 343 | return; 344 | case ZR_LOG_LEVEL_WARNING: 345 | *ppName = "warning"; 346 | return; 347 | case ZR_LOG_LEVEL_INFO: 348 | *ppName = "info"; 349 | return; 350 | case ZR_LOG_LEVEL_TRACE: 351 | *ppName = "trace"; 352 | return; 353 | case ZR_LOG_LEVEL_DEBUG: 354 | *ppName = "debug"; 355 | return; 356 | default: 357 | ZR_ASSERT(0); 358 | } 359 | } 360 | 361 | #if ZRP_LOGGER_LOG_STYLING 362 | static void 363 | zrpLoggerGetLogLevelStyle(enum ZrpLoggerStyle *pStyle, enum ZrLogLevel level) 364 | { 365 | ZR_ASSERT(pStyle != NULL); 366 | 367 | switch (level) { 368 | case ZR_LOG_LEVEL_ERROR: 369 | *pStyle = ZRP_LOGGER_STYLE_BRIGHT_RED; 370 | return; 371 | case ZR_LOG_LEVEL_WARNING: 372 | *pStyle = ZRP_LOGGER_STYLE_BRIGHT_YELLOW; 373 | return; 374 | case ZR_LOG_LEVEL_INFO: 375 | *pStyle = ZRP_LOGGER_STYLE_BRIGHT_GREEN; 376 | return; 377 | case ZR_LOG_LEVEL_TRACE: 378 | *pStyle = ZRP_LOGGER_STYLE_BRIGHT_CYAN; 379 | return; 380 | case ZR_LOG_LEVEL_DEBUG: 381 | *pStyle = ZRP_LOGGER_STYLE_BRIGHT_MAGENTA; 382 | return; 383 | default: 384 | ZR_ASSERT(0); 385 | }; 386 | } 387 | 388 | static void 389 | zrpLoggerGetStyleAnsiCode(const char **ppCode, enum ZrpLoggerStyle style) 390 | { 391 | ZR_ASSERT(ppCode != NULL); 392 | 393 | switch (style) { 394 | case ZRP_LOGGER_STYLE_RESET: 395 | *ppCode = "\x1b[0m"; 396 | return; 397 | case ZRP_LOGGER_STYLE_BLACK: 398 | *ppCode = "\x1b[30m"; 399 | return; 400 | case ZRP_LOGGER_STYLE_RED: 401 | *ppCode = "\x1b[31m"; 402 | return; 403 | case ZRP_LOGGER_STYLE_GREEN: 404 | *ppCode = "\x1b[32m"; 405 | return; 406 | case ZRP_LOGGER_STYLE_YELLOW: 407 | *ppCode = "\x1b[33m"; 408 | return; 409 | case ZRP_LOGGER_STYLE_BLUE: 410 | *ppCode = "\x1b[34m"; 411 | return; 412 | case ZRP_LOGGER_STYLE_MAGENTA: 413 | *ppCode = "\x1b[35m"; 414 | return; 415 | case ZRP_LOGGER_STYLE_CYAN: 416 | *ppCode = "\x1b[36m"; 417 | return; 418 | case ZRP_LOGGER_STYLE_BRIGHT_BLACK: 419 | *ppCode = "\x1b[1;30m"; 420 | return; 421 | case ZRP_LOGGER_STYLE_BRIGHT_RED: 422 | *ppCode = "\x1b[1;31m"; 423 | return; 424 | case ZRP_LOGGER_STYLE_BRIGHT_GREEN: 425 | *ppCode = "\x1b[1;32m"; 426 | return; 427 | case ZRP_LOGGER_STYLE_BRIGHT_YELLOW: 428 | *ppCode = "\x1b[1;33m"; 429 | return; 430 | case ZRP_LOGGER_STYLE_BRIGHT_BLUE: 431 | *ppCode = "\x1b[1;34m"; 432 | return; 433 | case ZRP_LOGGER_STYLE_BRIGHT_MAGENTA: 434 | *ppCode = "\x1b[1;35m"; 435 | return; 436 | case ZRP_LOGGER_STYLE_BRIGHT_CYAN: 437 | *ppCode = "\x1b[1;36m"; 438 | return; 439 | default: 440 | ZR_ASSERT(0); 441 | } 442 | } 443 | #endif /* ZRP_LOGGER_LOG_STYLING */ 444 | 445 | ZRP_MAYBE_UNUSED static void 446 | zrpLoggerLogVaList(enum ZrLogLevel level, 447 | const char *pFile, 448 | int line, 449 | const char *pFormat, 450 | va_list args) 451 | { 452 | const char *pLevelName; 453 | const char *pLevelStyleStart; 454 | const char *pLevelStyleEnd; 455 | 456 | ZR_ASSERT(pFile != NULL); 457 | ZR_ASSERT(pFormat != NULL); 458 | 459 | zrpLoggerGetLogLevelName(&pLevelName, level); 460 | 461 | #if ZRP_LOGGER_LOG_STYLING 462 | if (isatty(fileno(stderr))) { 463 | enum ZrpLoggerStyle levelStyle; 464 | 465 | zrpLoggerGetLogLevelStyle(&levelStyle, level); 466 | zrpLoggerGetStyleAnsiCode(&pLevelStyleStart, levelStyle); 467 | zrpLoggerGetStyleAnsiCode(&pLevelStyleEnd, ZRP_LOGGER_STYLE_RESET); 468 | } else { 469 | pLevelStyleStart = pLevelStyleEnd = ""; 470 | } 471 | #else 472 | pLevelStyleStart = pLevelStyleEnd = ""; 473 | #endif /* ZRP_LOGGER_LOG_STYLING */ 474 | 475 | fprintf(stderr, 476 | "%s:%d: %s%s%s: ", 477 | pFile, 478 | line, 479 | pLevelStyleStart, 480 | pLevelName, 481 | pLevelStyleEnd); 482 | vfprintf(stderr, pFormat, args); 483 | } 484 | 485 | ZRP_MAYBE_UNUSED static void 486 | zrpLoggerLog(enum ZrLogLevel level, 487 | const char *pFile, 488 | int line, 489 | const char *pFormat, 490 | ...) 491 | { 492 | va_list args; 493 | 494 | ZR_ASSERT(pFile != NULL); 495 | ZR_ASSERT(pFormat != NULL); 496 | 497 | va_start(args, pFormat); 498 | zrpLoggerLogVaList(level, pFile, line, pFormat, args); 499 | va_end(args); 500 | } 501 | 502 | #endif /* ZRP_LOGGER_DEFINED */ 503 | 504 | #if defined(ZRP_PLATFORM_WINDOWS) 505 | #define WIN32_LEAN_AND_MEAN 506 | #include 507 | #elif defined(ZRP_PLATFORM_DARWIN) 508 | #include 509 | #include 510 | #elif defined(ZRP_PLATFORM_UNIX) 511 | #include 512 | #if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309L 513 | #include 514 | #define ZRP_TIMER_USE_CLOCK_GETTIME 515 | #if defined(CLOCK_MONOTONIC_RAW) 516 | #define ZRP_TIMER_CLOCK_ID CLOCK_MONOTONIC_RAW 517 | #elif defined(CLOCK_MONOTONIC) 518 | #define ZRP_TIMER_CLOCK_ID CLOCK_MONOTONIC 519 | #else 520 | #define ZRP_TIMER_CLOCK_ID CLOCK_REALTIME 521 | #endif 522 | #else 523 | #include 524 | #endif 525 | #else 526 | typedef char zrp_timer_unsupported_platform[-1]; 527 | #endif 528 | 529 | /* 530 | In some cases, tick values are casted to 64-bit floating-points in order 531 | to prevent (unlikely) integer overflows during some arithmetic operations. 532 | This effectively reducse the precision of the ticks having a value greater 533 | than 2^53, which corresponds to approximatively 104 days. 534 | */ 535 | 536 | ZRP_MAYBE_UNUSED ZRP_TIMER_LINKAGE enum ZrStatus 537 | zrGetRealTime(ZrUint64 *pTime) 538 | { 539 | ZR_ASSERT(pTime != NULL); 540 | 541 | #if defined(ZRP_PLATFORM_WINDOWS) 542 | { 543 | static double timeToNano; 544 | LARGE_INTEGER time; 545 | 546 | if (timeToNano == 0.0) { 547 | LARGE_INTEGER frequency; 548 | 549 | if (!QueryPerformanceFrequency(&frequency)) { 550 | ZRP_LOG_ERROR("failed to retrieve the time's frequency\n"); 551 | return ZR_ERROR; 552 | } 553 | 554 | timeToNano = (double)ZR_TIMER_TICKS_PER_SECOND / frequency.QuadPart; 555 | } 556 | 557 | if (!QueryPerformanceCounter(&time)) { 558 | ZRP_LOG_ERROR("failed to retrieve the current time\n"); 559 | return ZR_ERROR; 560 | } 561 | 562 | *pTime = time.QuadPart * timeToNano; 563 | return ZR_SUCCESS; 564 | } 565 | #elif defined(ZRP_PLATFORM_DARWIN) 566 | /* 567 | Since Darwin 5.2, `clock_gettime()` can return high resolution times 568 | with the `CLOCK_UPTIME_RAW` clock but it internally only calls 569 | `mach_absolute_time()` with the overhead of converting the result into 570 | the `timespec` format. 571 | */ 572 | { 573 | static double timeToNano; 574 | 575 | if (timeToNano == 0.0) { 576 | mach_timebase_info_data_t info; 577 | 578 | if (mach_timebase_info(&info) != KERN_SUCCESS) { 579 | ZRP_LOG_ERROR("failed to retrieve the current time\n"); 580 | return ZR_ERROR; 581 | } 582 | 583 | timeToNano = (double)info.numer / info.denom; 584 | } 585 | 586 | *pTime = mach_absolute_time() * timeToNano; 587 | return ZR_SUCCESS; 588 | } 589 | #elif defined(ZRP_PLATFORM_UNIX) 590 | #if defined(ZRP_TIMER_USE_CLOCK_GETTIME) 591 | { 592 | struct timespec time; 593 | 594 | if (clock_gettime(ZRP_TIMER_CLOCK_ID, &time) != 0) { 595 | ZRP_LOG_ERROR("failed to retrieve the current time\n"); 596 | return ZR_ERROR; 597 | } 598 | 599 | *pTime = (ZrUint64)time.tv_sec * 1000000000ull + (ZrUint64)time.tv_nsec; 600 | return ZR_SUCCESS; 601 | } 602 | #else 603 | { 604 | struct timeval time; 605 | 606 | if (gettimeofday(&time, NULL) != 0) { 607 | ZRP_LOG_ERROR("failed to retrieve the current time\n"); 608 | return ZR_ERROR; 609 | } 610 | 611 | *pTime = (ZrUint64)time.tv_sec * 1000000000ull 612 | + (ZrUint64)time.tv_usec * 1000ull; 613 | return ZR_SUCCESS; 614 | } 615 | #endif 616 | #endif 617 | 618 | ZRP_LOG_ERROR("platform not supported\n"); 619 | return ZR_ERROR; 620 | } 621 | 622 | ZRP_MAYBE_UNUSED ZRP_TIMER_LINKAGE enum ZrStatus 623 | zrGetCpuTimes(struct ZrCpuTimes *pTimes) 624 | { 625 | ZR_ASSERT(pTimes != NULL); 626 | 627 | #if defined(ZRP_PLATFORM_WINDOWS) 628 | { 629 | FILETIME creationTime; 630 | FILETIME exitTime; 631 | FILETIME kernelTime; 632 | FILETIME userTime; 633 | ULARGE_INTEGER time; 634 | 635 | if (!GetProcessTimes(GetCurrentProcess(), 636 | &creationTime, 637 | &exitTime, 638 | &kernelTime, 639 | &userTime)) { 640 | ZRP_LOG_ERROR("failed to retrieve the current CPU times\n"); 641 | return ZR_ERROR; 642 | } 643 | 644 | time.LowPart = userTime.dwLowDateTime; 645 | time.HighPart = userTime.dwHighDateTime; 646 | *pTimes->user = time.QuadPart * 100ull; 647 | 648 | time.LowPart = kernelTime.dwLowDateTime; 649 | time.HighPart = kernelTime.dwHighDateTime; 650 | *pTimes->system = time.QuadPart * 100ull; 651 | } 652 | #elif defined(ZRP_PLATFORM_UNIX) 653 | { 654 | struct rusage usage; 655 | 656 | if (getrusage(RUSAGE_SELF, &usage)) { 657 | ZRP_LOG_ERROR("failed to retrieve the current CPU times\n"); 658 | return ZR_ERROR; 659 | } 660 | 661 | pTimes->user = (ZrUint64)usage.ru_utime.tv_sec * 1000000000ull 662 | + (ZrUint64)usage.ru_utime.tv_usec * 1000ull; 663 | pTimes->system = (ZrUint64)usage.ru_stime.tv_sec * 1000000000ull 664 | + (ZrUint64)usage.ru_stime.tv_usec * 1000ull; 665 | return ZR_SUCCESS; 666 | } 667 | #endif 668 | 669 | ZRP_LOG_ERROR("platform not supported\n"); 670 | return ZR_ERROR; 671 | } 672 | 673 | #endif /* ZRP_TIMER_IMPLEMENTATION_DEFINED */ 674 | #endif /* ZR_DEFINE_IMPLEMENTATION */ 675 | -------------------------------------------------------------------------------- /src/allocator.h.tpl: -------------------------------------------------------------------------------- 1 | /* @include "partials/license.h" */ 2 | 3 | #ifndef ZERO_ALLOCATOR_H 4 | #define ZERO_ALLOCATOR_H 5 | 6 | #define ZR_ALLOCATOR_MAJOR_VERSION 0 7 | #define ZR_ALLOCATOR_MINOR_VERSION 1 8 | #define ZR_ALLOCATOR_PATCH_VERSION 1 9 | 10 | /* @include "partials/environment.h" */ 11 | /* @include "partials/platform.h" */ 12 | /* @include "partials/types.h" */ 13 | 14 | #if defined(ZR_ALLOCATOR_SPECIFY_INTERNAL_LINKAGE) \ 15 | || defined(ZR_SPECIFY_INTERNAL_LINKAGE) 16 | #define ZRP_ALLOCATOR_LINKAGE static 17 | #elif defined(__cplusplus) 18 | #define ZRP_ALLOCATOR_LINKAGE extern "C" 19 | #else 20 | #define ZRP_ALLOCATOR_LINKAGE extern 21 | #endif 22 | 23 | ZRP_ALLOCATOR_LINKAGE void * 24 | zrAllocate(ZrSize size); 25 | 26 | ZRP_ALLOCATOR_LINKAGE void * 27 | zrReallocate(void *pOriginal, ZrSize size); 28 | 29 | ZRP_ALLOCATOR_LINKAGE void 30 | zrFree(const void *pMemory); 31 | 32 | ZRP_ALLOCATOR_LINKAGE void * 33 | zrAllocateAligned(ZrSize size, ZrSize alignment); 34 | 35 | ZRP_ALLOCATOR_LINKAGE void * 36 | zrReallocateAligned(void *pOriginal, ZrSize size, ZrSize alignment); 37 | 38 | ZRP_ALLOCATOR_LINKAGE void 39 | zrFreeAligned(const void *pMemory); 40 | 41 | #endif /* ZERO_ALLOCATOR_H */ 42 | 43 | #ifdef ZR_DEFINE_IMPLEMENTATION 44 | #ifndef ZRP_ALLOCATOR_IMPLEMENTATION_DEFINED 45 | #define ZRP_ALLOCATOR_IMPLEMENTATION_DEFINED 46 | 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | 53 | #ifndef ZR_ASSERT 54 | #include 55 | #define ZR_ASSERT assert 56 | #endif /* ZR_ASSERT */ 57 | 58 | #ifndef ZR_MALLOC 59 | #include 60 | #define ZR_MALLOC malloc 61 | #endif /* ZR_MALLOC */ 62 | 63 | #ifndef ZR_REALLOC 64 | #include 65 | #define ZR_REALLOC realloc 66 | #endif /* ZR_REALLOC */ 67 | 68 | #ifndef ZR_FREE 69 | #include 70 | #define ZR_FREE free 71 | #endif /* ZR_FREE */ 72 | 73 | /* @include "partials/unused.h" */ 74 | /* @include "partials/logging.h" */ 75 | /* @include "partials/loglevel.h" */ 76 | /* @include "partials/logger.h" */ 77 | 78 | #if defined(ZR_ALLOCATOR_ENABLE_DEBUGGING) || defined(ZR_ENABLE_DEBUGGING) 79 | #define ZRP_ALLOCATOR_DEBUGGING 1 80 | #else 81 | #define ZRP_ALLOCATOR_DEBUGGING 0 82 | #endif 83 | 84 | #define ZRP_ALLOCATOR_CAST_CONST(type, x) (type)(uintptr_t)(x) 85 | 86 | #ifdef __cplusplus 87 | template 88 | struct ZrpAllocatorAlignmentOfHelper { 89 | char first; 90 | T second; 91 | }; 92 | #define ZRP_ALLOCATOR_GET_ALIGNMENT_OF(type) \ 93 | offsetof(ZrpAllocatorAlignmentOfHelper, second) 94 | #else 95 | #define ZRP_ALLOCATOR_GET_ALIGNMENT_OF(type) \ 96 | offsetof( \ 97 | struct { \ 98 | char first; \ 99 | type second; \ 100 | }, \ 101 | second) 102 | #endif /* __cplusplus */ 103 | 104 | #define ZRP_ALLOCATOR_IS_POWER_OF_TWO(x) \ 105 | (((x) == ((x) & -(x))) && (x)) 106 | 107 | /* 108 | The aligned allocator works by allocating a block of larger size than 109 | requested to hold some necessary bookkeeping and some padding space to 110 | secure the desired alignment. 111 | 112 | block user pointer 113 | / / 114 | +---------+--------+------+---------+ 115 | | padding | header | size | padding | 116 | +---------+--------+------+---------+ 117 | \ \ 118 | 0 offset 119 | 120 | The sum of the front and back paddings equals `alignment - 1`, and the 121 | pointer returned to the user is located at a distance of `offset` from 122 | the beginning of the block. 123 | */ 124 | 125 | #define ZRP_ALLOCATOR_GET_ALIGNED_BLOCK(pBuffer, offset) \ 126 | (void *)((unsigned char *)(pBuffer) - (offset)) 127 | #define ZRP_ALLOCATOR_GET_ALIGNED_HEADER(pBuffer) \ 128 | ((struct ZrpAllocatorAlignedHeader *)(pBuffer))[-1] 129 | #define ZRP_ALLOCATOR_GET_ALIGNED_BUFFER(pBlock, alignment) \ 130 | (void *)((uintptr_t)((unsigned char *)(pBlock) + (alignment)-1 \ 131 | + sizeof(struct ZrpAllocatorAlignedHeader)) \ 132 | & ~(uintptr_t)((alignment)-1)) 133 | 134 | #define ZRP_ALLOCATOR_GET_ALIGNED_BLOCK_SIZE(size, alignment) \ 135 | (size) + (alignment)-1 + sizeof(struct ZrpAllocatorAlignedHeader) 136 | 137 | struct ZrpAllocatorAlignedHeader { 138 | ptrdiff_t offset; 139 | size_t size; 140 | #if ZRP_ALLOCATOR_DEBUGGING 141 | size_t alignment; 142 | #endif /* ZRP_ALLOCATOR_DEBUGGING */ 143 | }; 144 | 145 | typedef char zrp_allocator_invalid_aligned_header_alignment 146 | [ZRP_ALLOCATOR_IS_POWER_OF_TWO( 147 | ZRP_ALLOCATOR_GET_ALIGNMENT_OF(struct ZrpAllocatorAlignedHeader)) 148 | ? 1 149 | : -1]; 150 | typedef char zrp_allocator_invalid_void_pointer_alignment 151 | [ZRP_ALLOCATOR_IS_POWER_OF_TWO(sizeof(void *)) ? 1 : -1]; 152 | 153 | /* 154 | Any power of two alignment requested for the user pointer that is greater or 155 | equal to this minimum value is guaranteed to be a multiple of 156 | `sizeof(void *)`, thus conforming to the requirement of `posix_memalign()`, 157 | and is also guaranteed to provide correct alignment for the block header. 158 | */ 159 | static const size_t zrpAllocatorMinAlignment 160 | = ZRP_ALLOCATOR_GET_ALIGNMENT_OF(struct ZrpAllocatorAlignedHeader) 161 | > sizeof(void *) 162 | ? ZRP_ALLOCATOR_GET_ALIGNMENT_OF(struct ZrpAllocatorAlignedHeader) 163 | : sizeof(void *); 164 | 165 | ZRP_MAYBE_UNUSED static int 166 | zrpAllocatorIsPowerOfTwo(size_t x) 167 | { 168 | /* Verify exactly one bit is set. */ 169 | return (x == (x & -x)) && x; 170 | } 171 | 172 | ZRP_MAYBE_UNUSED ZRP_ALLOCATOR_LINKAGE void * 173 | zrAllocate(ZrSize size) 174 | { 175 | if (size == 0) { 176 | ZRP_LOG_INFO("allocation called with a size of 0\n"); 177 | return NULL; 178 | } 179 | 180 | return ZR_MALLOC((size_t)size); 181 | } 182 | 183 | ZRP_MAYBE_UNUSED ZRP_ALLOCATOR_LINKAGE void * 184 | zrReallocate(void *pOriginal, ZrSize size) 185 | { 186 | if (pOriginal == NULL) { 187 | return zrAllocate(size); 188 | } 189 | 190 | if (size == 0) { 191 | ZRP_LOG_INFO("reallocation called with a size of 0\n"); 192 | zrFree(pOriginal); 193 | return NULL; 194 | } 195 | 196 | return ZR_REALLOC(pOriginal, (size_t)size); 197 | } 198 | 199 | ZRP_MAYBE_UNUSED ZRP_ALLOCATOR_LINKAGE void 200 | zrFree(const void *pMemory) 201 | { 202 | ZR_FREE(ZRP_ALLOCATOR_CAST_CONST(void *, pMemory)); 203 | } 204 | 205 | ZRP_MAYBE_UNUSED ZRP_ALLOCATOR_LINKAGE void * 206 | zrAllocateAligned(ZrSize size, ZrSize alignment) 207 | { 208 | void *pBuffer; 209 | void *pBlock; 210 | struct ZrpAllocatorAlignedHeader *pHeader; 211 | 212 | ZR_ASSERT(zrpAllocatorIsPowerOfTwo((size_t)alignment)); 213 | 214 | if (size == 0) { 215 | ZRP_LOG_INFO("allocation called with a size of 0\n"); 216 | return NULL; 217 | } 218 | 219 | if (alignment < zrpAllocatorMinAlignment) { 220 | alignment = (ZrSize)zrpAllocatorMinAlignment; 221 | } 222 | 223 | pBlock = ZR_MALLOC( 224 | (size_t)ZRP_ALLOCATOR_GET_ALIGNED_BLOCK_SIZE(size, alignment)); 225 | if (pBlock == NULL) { 226 | ZRP_LOG_ERROR("failed to allocate the block\n"); 227 | return NULL; 228 | } 229 | 230 | pBuffer = ZRP_ALLOCATOR_GET_ALIGNED_BUFFER(pBlock, alignment); 231 | 232 | pHeader = &ZRP_ALLOCATOR_GET_ALIGNED_HEADER(pBuffer); 233 | pHeader->offset = (unsigned char *)pBuffer - (unsigned char *)pBlock; 234 | pHeader->size = (size_t)size; 235 | #if ZRP_ALLOCATOR_DEBUGGING 236 | pHeader->alignment = (size_t)alignment; 237 | #endif /* ZRP_ALLOCATOR_DEBUGGING */ 238 | 239 | return pBuffer; 240 | } 241 | 242 | ZRP_MAYBE_UNUSED ZRP_ALLOCATOR_LINKAGE void * 243 | zrReallocateAligned(void *pOriginal, ZrSize size, ZrSize alignment) 244 | { 245 | void *pBuffer; 246 | struct ZrpAllocatorAlignedHeader originalHeader; 247 | void *pOriginalBlock; 248 | void *pBlock; 249 | struct ZrpAllocatorAlignedHeader *pHeader; 250 | 251 | ZR_ASSERT(zrpAllocatorIsPowerOfTwo((size_t)alignment)); 252 | 253 | if (pOriginal == NULL) { 254 | return zrAllocateAligned(size, alignment); 255 | } 256 | 257 | if (size == 0) { 258 | ZRP_LOG_INFO("reallocation called with a size of 0\n"); 259 | zrFreeAligned(pOriginal); 260 | return NULL; 261 | } 262 | 263 | if (alignment < zrpAllocatorMinAlignment) { 264 | alignment = (ZrSize)zrpAllocatorMinAlignment; 265 | } 266 | 267 | originalHeader = ZRP_ALLOCATOR_GET_ALIGNED_HEADER(pOriginal); 268 | #if ZRP_ALLOCATOR_DEBUGGING 269 | ZR_ASSERT(alignment == originalHeader.alignment); 270 | #endif /* ZRP_ALLOCATOR_DEBUGGING */ 271 | 272 | pOriginalBlock 273 | = ZRP_ALLOCATOR_GET_ALIGNED_BLOCK(pOriginal, originalHeader.offset); 274 | pBlock = ZR_REALLOC( 275 | pOriginalBlock, 276 | (size_t)ZRP_ALLOCATOR_GET_ALIGNED_BLOCK_SIZE(size, alignment)); 277 | if (pBlock == NULL) { 278 | ZRP_LOG_ERROR("failed to allocate the block\n"); 279 | return NULL; 280 | } 281 | 282 | if (pBlock == pOriginalBlock) { 283 | /* `realloc()` expanded the block in place. */ 284 | ZRP_ALLOCATOR_GET_ALIGNED_HEADER(pOriginal).size = (size_t)size; 285 | return pOriginal; 286 | } 287 | 288 | pBuffer = ZRP_ALLOCATOR_GET_ALIGNED_BUFFER(pBlock, alignment); 289 | 290 | pHeader = &ZRP_ALLOCATOR_GET_ALIGNED_HEADER(pBuffer); 291 | pHeader->offset = (unsigned char *)pBuffer - (unsigned char *)pBlock; 292 | pHeader->size = (size_t)size; 293 | 294 | if (pHeader->offset == originalHeader.offset) { 295 | /* 296 | `realloc()` allocated a new block that is still correctly 297 | aligned. 298 | */ 299 | return pBuffer; 300 | } 301 | 302 | memmove(pBuffer, 303 | (void *)((unsigned char *)pBlock + originalHeader.offset), 304 | originalHeader.size); 305 | 306 | return pBuffer; 307 | } 308 | 309 | ZRP_MAYBE_UNUSED ZRP_ALLOCATOR_LINKAGE void 310 | zrFreeAligned(const void *pMemory) 311 | { 312 | struct ZrpAllocatorAlignedHeader *pHeader; 313 | 314 | if (pMemory == NULL) { 315 | return; 316 | } 317 | 318 | pHeader = &ZRP_ALLOCATOR_GET_ALIGNED_HEADER( 319 | ZRP_ALLOCATOR_CAST_CONST(void *, pMemory)); 320 | ZR_FREE(ZRP_ALLOCATOR_GET_ALIGNED_BLOCK( 321 | ZRP_ALLOCATOR_CAST_CONST(void *, pMemory), pHeader->offset)); 322 | } 323 | 324 | #endif /* ZRP_ALLOCATOR_IMPLEMENTATION_DEFINED */ 325 | #endif /* ZR_DEFINE_IMPLEMENTATION */ 326 | -------------------------------------------------------------------------------- /src/dynamicarray.h.tpl: -------------------------------------------------------------------------------- 1 | /* @include "partials/license.h" */ 2 | 3 | #ifndef ZERO_DYNAMICARRAY_H 4 | #define ZERO_DYNAMICARRAY_H 5 | 6 | #define ZR_DYNAMICARRAY_MAJOR_VERSION 0 7 | #define ZR_DYNAMICARRAY_MINOR_VERSION 1 8 | #define ZR_DYNAMICARRAY_PATCH_VERSION 1 9 | 10 | /* @include "partials/environment.h" */ 11 | /* @include "partials/platform.h" */ 12 | /* @include "partials/types.h" */ 13 | 14 | /* @include "partials/status.h" */ 15 | 16 | #if defined(ZR_DYNAMICARRAY_SPECIFY_INTERNAL_LINKAGE) \ 17 | || defined(ZR_SPECIFY_INTERNAL_LINKAGE) 18 | #define ZRP_DYNAMICARRAY_LINKAGE static 19 | #elif defined(__cplusplus) 20 | #define ZRP_DYNAMICARRAY_LINKAGE extern "C" 21 | #else 22 | #define ZRP_DYNAMICARRAY_LINKAGE extern 23 | #endif 24 | 25 | #define ZRP_DYNAMICARRAY_DECLARE_CREATE_FUNCTION(name, type) \ 26 | ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus zrCreate##name(type **ppArray, \ 27 | ZrSize size) 28 | 29 | #define ZRP_DYNAMICARRAY_DECLARE_DESTROY_FUNCTION(name, type) \ 30 | ZRP_DYNAMICARRAY_LINKAGE void zrDestroy##name(type *pArray) 31 | 32 | #define ZRP_DYNAMICARRAY_DECLARE_GET_SIZE_FUNCTION(name, type) \ 33 | ZRP_DYNAMICARRAY_LINKAGE void zrGet##name##Size(const type *pArray, \ 34 | ZrSize *pSize) 35 | 36 | #define ZRP_DYNAMICARRAY_DECLARE_GET_CAPACITY_FUNCTION(name, type) \ 37 | ZRP_DYNAMICARRAY_LINKAGE void zrGet##name##Capacity(const type *pArray, \ 38 | ZrSize *pCapacity) 39 | 40 | #define ZRP_DYNAMICARRAY_DECLARE_GET_MAX_CAPACITY_FUNCTION(name, type) \ 41 | ZRP_DYNAMICARRAY_LINKAGE void zrGet##name##MaxCapacity(const type *pArray, \ 42 | ZrSize *pCapacity) 43 | 44 | #define ZRP_DYNAMICARRAY_DECLARE_RESIZE_FUNCTION(name, type) \ 45 | ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus zrResize##name(type **ppArray, \ 46 | ZrSize size) 47 | 48 | #define ZRP_DYNAMICARRAY_DECLARE_RESERVE_FUNCTION(name, type) \ 49 | ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus zrReserve##name(type **ppArray, \ 50 | ZrSize capacity) 51 | 52 | #define ZRP_DYNAMICARRAY_DECLARE_EXTEND_FUNCTION(name, type) \ 53 | ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus zrExtend##name( \ 54 | type **ppSlice, type **ppArray, ZrSize position, ZrSize size) 55 | 56 | #define ZRP_DYNAMICARRAY_DECLARE_EXTEND_FRONT_FUNCTION(name, type) \ 57 | ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus zrExtend##name##Front( \ 58 | type **ppSlice, type **ppArray, ZrSize size) 59 | 60 | #define ZRP_DYNAMICARRAY_DECLARE_EXTEND_BACK_FUNCTION(name, type) \ 61 | ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus zrExtend##name##Back( \ 62 | type **ppSlice, type **ppArray, ZrSize size) 63 | 64 | #define ZRP_DYNAMICARRAY_DECLARE_INSERT_FUNCTION(name, type) \ 65 | ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus zrInsert##name( \ 66 | type **ppArray, ZrSize position, ZrSize size, const type *pValues) 67 | 68 | #define ZRP_DYNAMICARRAY_DECLARE_INSERT_FRONT_FUNCTION(name, type) \ 69 | ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus zrInsert##name##Front( \ 70 | type **ppArray, ZrSize size, const type *pValues) 71 | 72 | #define ZRP_DYNAMICARRAY_DECLARE_INSERT_BACK_FUNCTION(name, type) \ 73 | ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus zrInsert##name##Back( \ 74 | type **ppArray, ZrSize size, const type *pValues) 75 | 76 | #define ZRP_DYNAMICARRAY_DECLARE_PUSH_FUNCTION(name, type) \ 77 | ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus zrPush##name( \ 78 | type **ppArray, ZrSize position, type value) 79 | 80 | #define ZRP_DYNAMICARRAY_DECLARE_PUSH_FRONT_FUNCTION(name, type) \ 81 | ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus zrPush##name##Front(type **ppArray, \ 82 | type value) 83 | 84 | #define ZRP_DYNAMICARRAY_DECLARE_PUSH_BACK_FUNCTION(name, type) \ 85 | ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus zrPush##name##Back(type **ppArray, \ 86 | type value) 87 | 88 | #define ZRP_DYNAMICARRAY_DECLARE_TRIM_FUNCTION(name, type) \ 89 | ZRP_DYNAMICARRAY_LINKAGE void zrTrim##name( \ 90 | type *pArray, ZrSize position, ZrSize size) 91 | 92 | #define ZRP_DYNAMICARRAY_DECLARE_TRIM_FRONT_FUNCTION(name, type) \ 93 | ZRP_DYNAMICARRAY_LINKAGE void zrTrim##name##Front(type *pArray, ZrSize size) 94 | 95 | #define ZRP_DYNAMICARRAY_DECLARE_TRIM_BACK_FUNCTION(name, type) \ 96 | ZRP_DYNAMICARRAY_LINKAGE void zrTrim##name##Back(type *pArray, ZrSize size) 97 | 98 | #define ZR_MAKE_DYNAMIC_ARRAY(name, type) \ 99 | ZRP_DYNAMICARRAY_DECLARE_MAX_CAPACITY(name, type) \ 100 | ZRP_DYNAMICARRAY_DECLARE_CREATE_FUNCTION(name, type) \ 101 | ZRP_DYNAMICARRAY_DECLARE_DESTROY_FUNCTION(name, type) \ 102 | ZRP_DYNAMICARRAY_DECLARE_GET_SIZE_FUNCTION(name, type) \ 103 | ZRP_DYNAMICARRAY_DECLARE_GET_CAPACITY_FUNCTION(name, type) \ 104 | ZRP_DYNAMICARRAY_DECLARE_GET_MAX_CAPACITY_FUNCTION(name, type) \ 105 | ZRP_DYNAMICARRAY_DECLARE_RESIZE_FUNCTION(name, type) \ 106 | ZRP_DYNAMICARRAY_DECLARE_RESERVE_FUNCTION(name, type) \ 107 | ZRP_DYNAMICARRAY_DECLARE_EXTEND_FUNCTION(name, type) \ 108 | ZRP_DYNAMICARRAY_DECLARE_EXTEND_FRONT_FUNCTION(name, type) \ 109 | ZRP_DYNAMICARRAY_DECLARE_EXTEND_BACK_FUNCTION(name, type) \ 110 | ZRP_DYNAMICARRAY_DECLARE_INSERT_FUNCTION(name, type) \ 111 | ZRP_DYNAMICARRAY_DECLARE_INSERT_FRONT_FUNCTION(name, type) \ 112 | ZRP_DYNAMICARRAY_DECLARE_INSERT_BACK_FUNCTION(name, type) \ 113 | ZRP_DYNAMICARRAY_DECLARE_PUSH_FUNCTION(name, type) \ 114 | ZRP_DYNAMICARRAY_DECLARE_PUSH_FRONT_FUNCTION(name, type) \ 115 | ZRP_DYNAMICARRAY_DECLARE_PUSH_BACK_FUNCTION(name, type) \ 116 | ZRP_DYNAMICARRAY_DECLARE_TRIM_FUNCTION(name, type) \ 117 | ZRP_DYNAMICARRAY_DECLARE_TRIM_FRONT_FUNCTION(name, type) \ 118 | ZRP_DYNAMICARRAY_DECLARE_TRIM_BACK_FUNCTION(name, type) 119 | 120 | #endif /* ZERO_DYNAMICARRAY_H */ 121 | 122 | #ifdef ZR_DEFINE_IMPLEMENTATION 123 | #ifndef ZRP_DYNAMICARRAY_IMPLEMENTATION_DEFINED 124 | #define ZRP_DYNAMICARRAY_IMPLEMENTATION_DEFINED 125 | 126 | #include 127 | #include 128 | #include 129 | #include 130 | 131 | #ifndef ZR_ASSERT 132 | #include 133 | #define ZR_ASSERT assert 134 | #endif /* ZR_ASSERT */ 135 | 136 | #ifndef ZR_REALLOC 137 | #include 138 | #define ZR_REALLOC realloc 139 | #endif /* ZR_REALLOC */ 140 | 141 | #ifndef ZR_FREE 142 | #include 143 | #define ZR_FREE free 144 | #endif /* ZR_FREE */ 145 | 146 | /* @include "partials/unused.h" */ 147 | /* @include "partials/logging.h" */ 148 | /* @include "partials/loglevel.h" */ 149 | /* @include "partials/logger.h" */ 150 | 151 | #define ZRP_DYNAMICARRAY_GET_BLOCK(pBuffer) \ 152 | ((void *)&((struct ZrpDynamicArrayHeader *)(pBuffer))[-1]) 153 | #define ZRP_DYNAMICARRAY_GET_HEADER(pBlock) \ 154 | ((struct ZrpDynamicArrayHeader *)(pBlock)) 155 | #define ZRP_DYNAMICARRAY_GET_BUFFER(pBlock) \ 156 | ((void *)&((struct ZrpDynamicArrayHeader *)(pBlock))[1]) 157 | #define ZRP_DYNAMICARRAY_GET_CONST_BLOCK(pBuffer) \ 158 | ((const void *)&((const struct ZrpDynamicArrayHeader *)pBuffer)[-1]) 159 | #define ZRP_DYNAMICARRAY_GET_CONST_HEADER(pBlock) \ 160 | ((const struct ZrpDynamicArrayHeader *)(pBlock)) 161 | 162 | #define ZRP_DYNAMICARRAY_DEFINE_MAX_CAPACITY(name, type) \ 163 | static const size_t zrpMax##name##Capacity \ 164 | = (((size_t)-1 - sizeof(struct ZrpDynamicArrayHeader)) \ 165 | / sizeof(type)); 166 | 167 | #define ZRP_DYNAMICARRAY_DEFINE_CREATE_FUNCTION(name, type) \ 168 | ZRP_MAYBE_UNUSED ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus zrCreate##name( \ 169 | type **ppArray, ZrSize size) \ 170 | { \ 171 | enum ZrStatus status; \ 172 | void *pBlock; \ 173 | \ 174 | ZR_ASSERT(ppArray != NULL); \ 175 | \ 176 | pBlock = NULL; \ 177 | \ 178 | status = zrpDynamicArrayEnsureHasEnoughCapacity( \ 179 | &pBlock, 0, (size_t)size, zrpMax##name##Capacity, sizeof(type)); \ 180 | if (status != ZR_SUCCESS) { \ 181 | ZRP_LOG_ERROR("failed to reserve a large enough capacity for the " \ 182 | "type ‘" #type "’ (requested capacity: %zu)\n", \ 183 | (size_t)size); \ 184 | return status; \ 185 | } \ 186 | \ 187 | ZR_ASSERT(pBlock != NULL); \ 188 | \ 189 | ZRP_DYNAMICARRAY_GET_HEADER(pBlock)->size = (size_t)size; \ 190 | ZRP_DYNAMICARRAY_GET_HEADER(pBlock)->capacity = (size_t)size; \ 191 | *ppArray = (type *)ZRP_DYNAMICARRAY_GET_BUFFER(pBlock); \ 192 | return ZR_SUCCESS; \ 193 | } 194 | 195 | #define ZRP_DYNAMICARRAY_DEFINE_DESTROY_FUNCTION(name, type) \ 196 | ZRP_MAYBE_UNUSED ZRP_DYNAMICARRAY_LINKAGE void zrDestroy##name( \ 197 | type *pArray) \ 198 | { \ 199 | if (pArray == NULL) { \ 200 | return; \ 201 | } \ 202 | \ 203 | ZR_FREE(ZRP_DYNAMICARRAY_GET_BLOCK(pArray)); \ 204 | } 205 | 206 | #define ZRP_DYNAMICARRAY_DEFINE_GET_SIZE_FUNCTION(name, type) \ 207 | ZRP_MAYBE_UNUSED ZRP_DYNAMICARRAY_LINKAGE void zrGet##name##Size( \ 208 | ZrSize *pSize, const type *pArray) \ 209 | { \ 210 | ZR_ASSERT(pArray != NULL); \ 211 | \ 212 | *pSize = (ZrSize)ZRP_DYNAMICARRAY_GET_CONST_HEADER( \ 213 | ZRP_DYNAMICARRAY_GET_CONST_BLOCK(pArray)) \ 214 | ->size; \ 215 | } 216 | 217 | #define ZRP_DYNAMICARRAY_DEFINE_GET_CAPACITY_FUNCTION(name, type) \ 218 | ZRP_MAYBE_UNUSED ZRP_DYNAMICARRAY_LINKAGE void zrGet##name##Capacity( \ 219 | ZrSize *pCapacity, const type *pArray) \ 220 | { \ 221 | ZR_ASSERT(pArray != NULL); \ 222 | \ 223 | *pCapacity = (ZrSize)ZRP_DYNAMICARRAY_GET_CONST_HEADER( \ 224 | ZRP_DYNAMICARRAY_GET_CONST_BLOCK(pArray)) \ 225 | ->capacity; \ 226 | } 227 | 228 | #define ZRP_DYNAMICARRAY_DEFINE_GET_MAX_CAPACITY_FUNCTION(name, type) \ 229 | ZRP_MAYBE_UNUSED ZRP_DYNAMICARRAY_LINKAGE void zrGet##name##MaxCapacity( \ 230 | ZrSize *pMaxCapacity) \ 231 | { \ 232 | *pMaxCapacity = zrpMax##name##Capacity; \ 233 | } 234 | 235 | #define ZRP_DYNAMICARRAY_DEFINE_RESIZE_FUNCTION(name, type) \ 236 | ZRP_MAYBE_UNUSED ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus zrResize##name( \ 237 | type **ppArray, ZrSize size) \ 238 | { \ 239 | enum ZrStatus status; \ 240 | void *pBlock; \ 241 | \ 242 | ZR_ASSERT(ppArray != NULL); \ 243 | ZR_ASSERT(*ppArray != NULL); \ 244 | \ 245 | pBlock = ZRP_DYNAMICARRAY_GET_BLOCK(*ppArray); \ 246 | \ 247 | status = zrpDynamicArrayEnsureHasEnoughCapacity( \ 248 | &pBlock, \ 249 | ZRP_DYNAMICARRAY_GET_HEADER(pBlock)->capacity, \ 250 | (size_t)size, \ 251 | zrpMax##name##Capacity, \ 252 | sizeof(type)); \ 253 | if (status != ZR_SUCCESS) { \ 254 | ZRP_LOG_ERROR("failed to reserve a large enough capacity for the " \ 255 | "type ‘" #type "’ (requested capacity: %zu)\n", \ 256 | (size_t)size); \ 257 | return status; \ 258 | } \ 259 | \ 260 | ZR_ASSERT(pBlock != NULL); \ 261 | \ 262 | ZRP_DYNAMICARRAY_GET_HEADER(pBlock)->size = (size_t)size; \ 263 | *ppArray = (type *)ZRP_DYNAMICARRAY_GET_BUFFER(pBlock); \ 264 | return ZR_SUCCESS; \ 265 | } 266 | 267 | #define ZRP_DYNAMICARRAY_DEFINE_RESERVE_FUNCTION(name, type) \ 268 | ZRP_MAYBE_UNUSED ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus zrReserve##name( \ 269 | type **ppArray, ZrSize capacity) \ 270 | { \ 271 | enum ZrStatus status; \ 272 | void *pBlock; \ 273 | \ 274 | ZR_ASSERT(ppArray != NULL); \ 275 | ZR_ASSERT(*ppArray != NULL); \ 276 | \ 277 | pBlock = ZRP_DYNAMICARRAY_GET_BLOCK(*ppArray); \ 278 | \ 279 | status = zrpDynamicArrayEnsureHasEnoughCapacity( \ 280 | &pBlock, \ 281 | ZRP_DYNAMICARRAY_GET_HEADER(pBlock)->capacity, \ 282 | (size_t)capacity, \ 283 | zrpMax##name##Capacity, \ 284 | sizeof(type)); \ 285 | if (status != ZR_SUCCESS) { \ 286 | ZRP_LOG_ERROR("failed to reserve a large enough capacity for the " \ 287 | "type ‘" #type "’ (requested capacity: %zu)\n", \ 288 | (size_t)capacity); \ 289 | return status; \ 290 | } \ 291 | \ 292 | ZR_ASSERT(pBlock != NULL); \ 293 | \ 294 | *ppArray = (type *)ZRP_DYNAMICARRAY_GET_BUFFER(pBlock); \ 295 | return ZR_SUCCESS; \ 296 | } 297 | 298 | #define ZRP_DYNAMICARRAY_DEFINE_EXTEND_FUNCTION(name, type) \ 299 | ZRP_MAYBE_UNUSED ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus zrExtend##name( \ 300 | type **ppSlice, type **ppArray, ZrSize position, ZrSize size) \ 301 | { \ 302 | enum ZrStatus status; \ 303 | void *pBlock; \ 304 | \ 305 | ZR_ASSERT(ppArray != NULL); \ 306 | ZR_ASSERT(*ppArray != NULL); \ 307 | \ 308 | pBlock = ZRP_DYNAMICARRAY_GET_BLOCK(*ppArray); \ 309 | \ 310 | if (position > ZRP_DYNAMICARRAY_GET_HEADER(pBlock)->size) { \ 311 | position = (ZrSize)ZRP_DYNAMICARRAY_GET_HEADER(pBlock)->size; \ 312 | } \ 313 | \ 314 | status = zrpDynamicArrayEnsureHasEnoughCapacity( \ 315 | &pBlock, \ 316 | ZRP_DYNAMICARRAY_GET_HEADER(pBlock)->capacity, \ 317 | ZRP_DYNAMICARRAY_GET_HEADER(pBlock)->size + (size_t)size, \ 318 | zrpMax##name##Capacity, \ 319 | sizeof(type)); \ 320 | if (status != ZR_SUCCESS) { \ 321 | ZRP_LOG_ERROR( \ 322 | "failed to reserve a large enough capacity for the " \ 323 | "type ‘" #type "’ (requested capacity: %zu)\n", \ 324 | ZRP_DYNAMICARRAY_GET_HEADER(pBlock)->size + (size_t)size); \ 325 | return status; \ 326 | } \ 327 | \ 328 | ZR_ASSERT(pBlock != NULL); \ 329 | \ 330 | *ppArray = (type *)ZRP_DYNAMICARRAY_GET_BUFFER(pBlock); \ 331 | \ 332 | memmove(&(*ppArray)[(size_t)position + (size_t)size], \ 333 | &(*ppArray)[(size_t)position], \ 334 | sizeof(type) \ 335 | * (ZRP_DYNAMICARRAY_GET_HEADER(pBlock)->size \ 336 | - (size_t)position)); \ 337 | \ 338 | if (ppSlice != NULL) { \ 339 | *ppSlice = &(*ppArray)[position]; \ 340 | } \ 341 | \ 342 | ZRP_DYNAMICARRAY_GET_HEADER(pBlock)->size += (size_t)size; \ 343 | return ZR_SUCCESS; \ 344 | } 345 | 346 | #define ZRP_DYNAMICARRAY_DEFINE_EXTEND_FRONT_FUNCTION(name, type) \ 347 | ZRP_MAYBE_UNUSED ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus \ 348 | zrExtend##name##Front(type **ppSlice, type **ppArray, ZrSize size) \ 349 | { \ 350 | return zrExtend##name(ppSlice, ppArray, 0, size); \ 351 | } 352 | 353 | #define ZRP_DYNAMICARRAY_DEFINE_EXTEND_BACK_FUNCTION(name, type) \ 354 | ZRP_MAYBE_UNUSED ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus \ 355 | zrExtend##name##Back(type **ppSlice, type **ppArray, ZrSize size) \ 356 | { \ 357 | return zrExtend##name(ppSlice, \ 358 | ppArray, \ 359 | (ZrSize)ZRP_DYNAMICARRAY_GET_HEADER( \ 360 | ZRP_DYNAMICARRAY_GET_BLOCK(*ppArray)) \ 361 | ->size, \ 362 | size); \ 363 | } 364 | 365 | #define ZRP_DYNAMICARRAY_DEFINE_INSERT_FUNCTION(name, type) \ 366 | ZRP_MAYBE_UNUSED ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus zrInsert##name( \ 367 | type **ppArray, ZrSize position, ZrSize size, const type *pValues) \ 368 | { \ 369 | enum ZrStatus status; \ 370 | type *pSlice; \ 371 | \ 372 | ZR_ASSERT(ppArray != NULL); \ 373 | ZR_ASSERT(*ppArray != NULL); \ 374 | ZR_ASSERT(pValues != NULL); \ 375 | \ 376 | status = zrExtend##name(&pSlice, ppArray, position, size); \ 377 | if (status != ZR_SUCCESS) { \ 378 | ZRP_LOG_ERROR("failed to extend the array\n"); \ 379 | return status; \ 380 | } \ 381 | \ 382 | memcpy(pSlice, pValues, sizeof(type) * (size_t)size); \ 383 | return ZR_SUCCESS; \ 384 | } 385 | 386 | #define ZRP_DYNAMICARRAY_DEFINE_INSERT_FRONT_FUNCTION(name, type) \ 387 | ZRP_MAYBE_UNUSED ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus \ 388 | zrInsert##name##Front( \ 389 | type **ppArray, ZrSize size, const type *pValues) \ 390 | { \ 391 | return zrInsert##name(ppArray, 0, size, pValues); \ 392 | } 393 | 394 | #define ZRP_DYNAMICARRAY_DEFINE_INSERT_BACK_FUNCTION(name, type) \ 395 | ZRP_MAYBE_UNUSED ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus \ 396 | zrInsert##name##Back(type **ppArray, ZrSize size, const type *pValues) \ 397 | { \ 398 | return zrInsert##name(ppArray, (ZrSize)-1, size, pValues); \ 399 | } 400 | 401 | #define ZRP_DYNAMICARRAY_DEFINE_PUSH_FUNCTION(name, type) \ 402 | ZRP_MAYBE_UNUSED ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus zrPush##name( \ 403 | type **ppArray, ZrSize position, type value) \ 404 | { \ 405 | enum ZrStatus status; \ 406 | type *pSlice; \ 407 | \ 408 | ZR_ASSERT(ppArray != NULL); \ 409 | ZR_ASSERT(*ppArray != NULL); \ 410 | \ 411 | status = zrExtend##name(&pSlice, ppArray, position, 1); \ 412 | if (status != ZR_SUCCESS) { \ 413 | ZRP_LOG_ERROR("failed to extend the array\n"); \ 414 | return status; \ 415 | } \ 416 | \ 417 | *pSlice = value; \ 418 | return ZR_SUCCESS; \ 419 | } 420 | 421 | #define ZRP_DYNAMICARRAY_DEFINE_PUSH_FRONT_FUNCTION(name, type) \ 422 | ZRP_MAYBE_UNUSED ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus \ 423 | zrPush##name##Front(type **ppArray, type value) \ 424 | { \ 425 | return zrPush##name(ppArray, 0, value); \ 426 | } 427 | 428 | #define ZRP_DYNAMICARRAY_DEFINE_PUSH_BACK_FUNCTION(name, type) \ 429 | ZRP_MAYBE_UNUSED ZRP_DYNAMICARRAY_LINKAGE enum ZrStatus \ 430 | zrPush##name##Back(type **ppArray, type value) \ 431 | { \ 432 | return zrPush##name(ppArray, (ZrSize)-1, value); \ 433 | } 434 | 435 | #define ZRP_DYNAMICARRAY_DEFINE_TRIM_FUNCTION(name, type) \ 436 | ZRP_MAYBE_UNUSED ZRP_DYNAMICARRAY_LINKAGE void zrTrim##name( \ 437 | type *pArray, ZrSize position, ZrSize size) \ 438 | { \ 439 | void *pBlock; \ 440 | \ 441 | ZR_ASSERT(pArray != NULL); \ 442 | \ 443 | pBlock = ZRP_DYNAMICARRAY_GET_BLOCK(pArray); \ 444 | \ 445 | if (position >= ZRP_DYNAMICARRAY_GET_HEADER(pBlock)->size) { \ 446 | return; \ 447 | } \ 448 | \ 449 | if (size > ZRP_DYNAMICARRAY_GET_HEADER(pBlock)->size - position) { \ 450 | size = ZRP_DYNAMICARRAY_GET_HEADER(pBlock)->size - position; \ 451 | } \ 452 | \ 453 | memmove(&pArray[position], \ 454 | &pArray[position + size], \ 455 | sizeof(type) * (size_t)size); \ 456 | ZRP_DYNAMICARRAY_GET_HEADER(pBlock)->size -= (size_t)size; \ 457 | } 458 | 459 | #define ZRP_DYNAMICARRAY_DEFINE_TRIM_FRONT_FUNCTION(name, type) \ 460 | ZRP_MAYBE_UNUSED ZRP_DYNAMICARRAY_LINKAGE void zrTrim##name##Front( \ 461 | type *pArray, ZrSize size) \ 462 | { \ 463 | zrTrim##name(pArray, 0, size); \ 464 | } 465 | 466 | #define ZRP_DYNAMICARRAY_DEFINE_TRIM_BACK_FUNCTION(name, type) \ 467 | ZRP_MAYBE_UNUSED ZRP_DYNAMICARRAY_LINKAGE void zrTrim##name##Back( \ 468 | type *pArray, ZrSize size) \ 469 | { \ 470 | zrTrim##name(pArray, (ZrSize)-1, size); \ 471 | } 472 | 473 | #undef ZR_MAKE_DYNAMIC_ARRAY 474 | #define ZR_MAKE_DYNAMIC_ARRAY(name, type) \ 475 | ZRP_DYNAMICARRAY_DEFINE_MAX_CAPACITY(name, type) \ 476 | ZRP_DYNAMICARRAY_DEFINE_CREATE_FUNCTION(name, type) \ 477 | ZRP_DYNAMICARRAY_DEFINE_DESTROY_FUNCTION(name, type) \ 478 | ZRP_DYNAMICARRAY_DEFINE_GET_SIZE_FUNCTION(name, type) \ 479 | ZRP_DYNAMICARRAY_DEFINE_GET_CAPACITY_FUNCTION(name, type) \ 480 | ZRP_DYNAMICARRAY_DEFINE_GET_MAX_CAPACITY_FUNCTION(name, type) \ 481 | ZRP_DYNAMICARRAY_DEFINE_RESIZE_FUNCTION(name, type) \ 482 | ZRP_DYNAMICARRAY_DEFINE_RESERVE_FUNCTION(name, type) \ 483 | ZRP_DYNAMICARRAY_DEFINE_EXTEND_FUNCTION(name, type) \ 484 | ZRP_DYNAMICARRAY_DEFINE_EXTEND_FRONT_FUNCTION(name, type) \ 485 | ZRP_DYNAMICARRAY_DEFINE_EXTEND_BACK_FUNCTION(name, type) \ 486 | ZRP_DYNAMICARRAY_DEFINE_INSERT_FUNCTION(name, type) \ 487 | ZRP_DYNAMICARRAY_DEFINE_INSERT_FRONT_FUNCTION(name, type) \ 488 | ZRP_DYNAMICARRAY_DEFINE_INSERT_BACK_FUNCTION(name, type) \ 489 | ZRP_DYNAMICARRAY_DEFINE_PUSH_FUNCTION(name, type) \ 490 | ZRP_DYNAMICARRAY_DEFINE_PUSH_FRONT_FUNCTION(name, type) \ 491 | ZRP_DYNAMICARRAY_DEFINE_PUSH_BACK_FUNCTION(name, type) \ 492 | ZRP_DYNAMICARRAY_DEFINE_TRIM_FUNCTION(name, type) \ 493 | ZRP_DYNAMICARRAY_DEFINE_TRIM_FRONT_FUNCTION(name, type) \ 494 | ZRP_DYNAMICARRAY_DEFINE_TRIM_BACK_FUNCTION(name, type) 495 | 496 | struct ZrpDynamicArrayHeader { 497 | size_t size; 498 | size_t capacity; 499 | }; 500 | 501 | ZRP_MAYBE_UNUSED static void 502 | zrpDynamicArrayGetNewCapacity(size_t *pNewCapacity, 503 | size_t current, 504 | size_t requested, 505 | size_t max) 506 | { 507 | *pNewCapacity = current + current / 2 + 1; 508 | if (*pNewCapacity < current) { 509 | *pNewCapacity = max; 510 | return; 511 | } 512 | 513 | if (*pNewCapacity < requested) { 514 | *pNewCapacity = requested; 515 | } 516 | } 517 | 518 | ZRP_MAYBE_UNUSED static enum ZrStatus 519 | zrpDynamicArrayEnsureHasEnoughCapacity(void **ppBlock, 520 | size_t currentCapacity, 521 | size_t requestedCapacity, 522 | size_t maxCapacity, 523 | size_t elementSize) 524 | { 525 | void *pBlock; 526 | size_t newCapacity; 527 | 528 | ZR_ASSERT(ppBlock != NULL); 529 | ZR_ASSERT(elementSize > 0); 530 | 531 | if (requestedCapacity > maxCapacity) { 532 | ZRP_LOG_TRACE("the requested capacity is too large\n"); 533 | return ZR_ERROR_MAX_SIZE_EXCEEDED; 534 | } 535 | 536 | if (*ppBlock != NULL && currentCapacity >= requestedCapacity) { 537 | return ZR_SUCCESS; 538 | } 539 | 540 | zrpDynamicArrayGetNewCapacity( 541 | &newCapacity, currentCapacity, requestedCapacity, maxCapacity); 542 | ZR_ASSERT(newCapacity >= requestedCapacity); 543 | ZR_ASSERT(newCapacity <= maxCapacity); 544 | 545 | pBlock = ZR_REALLOC( 546 | *ppBlock, 547 | sizeof(struct ZrpDynamicArrayHeader) + elementSize * newCapacity); 548 | if (pBlock == NULL) { 549 | ZRP_LOG_TRACE("failed to reallocate the block\n"); 550 | return ZR_ERROR_ALLOCATION; 551 | } 552 | 553 | ZRP_DYNAMICARRAY_GET_HEADER(pBlock)->capacity = newCapacity; 554 | *ppBlock = pBlock; 555 | return ZR_SUCCESS; 556 | } 557 | 558 | #endif /* ZRP_DYNAMICARRAY_IMPLEMENTATION_DEFINED */ 559 | #endif /* ZR_DEFINE_IMPLEMENTATION */ 560 | -------------------------------------------------------------------------------- /src/logger.h.tpl: -------------------------------------------------------------------------------- 1 | /* @include "partials/license.h" */ 2 | 3 | #ifndef ZERO_LOGGER_H 4 | #define ZERO_LOGGER_H 5 | 6 | #include 7 | 8 | #define ZR_LOGGER_MAJOR_VERSION 0 9 | #define ZR_LOGGER_MINOR_VERSION 1 10 | #define ZR_LOGGER_PATCH_VERSION 1 11 | 12 | /* @include "partials/platform.h" */ 13 | 14 | #if defined(ZR_LOGGER_SPECIFY_INTERNAL_LINKAGE) \ 15 | || defined(ZR_SPECIFY_INTERNAL_LINKAGE) 16 | #define ZRP_LOGGER_LINKAGE static 17 | #elif defined(__cplusplus) 18 | #define ZRP_LOGGER_LINKAGE extern "C" 19 | #else 20 | #define ZRP_LOGGER_LINKAGE extern 21 | #endif 22 | 23 | /* @include "partials/loglevel.h" */ 24 | 25 | ZRP_LOGGER_LINKAGE void 26 | zrLog(enum ZrLogLevel level, 27 | const char *pFile, 28 | int line, 29 | const char *pFormat, 30 | ...); 31 | 32 | ZRP_LOGGER_LINKAGE void 33 | zrLogVaList(enum ZrLogLevel level, 34 | const char *pFile, 35 | int line, 36 | const char *pFormat, 37 | va_list args); 38 | 39 | #endif /* ZERO_LOGGER_H */ 40 | 41 | #ifdef ZR_DEFINE_IMPLEMENTATION 42 | #ifndef ZRP_LOGGER_IMPLEMENTATION_DEFINED 43 | #define ZRP_LOGGER_IMPLEMENTATION_DEFINED 44 | 45 | #include 46 | #include 47 | #include 48 | 49 | #ifndef ZR_ASSERT 50 | #include 51 | #define ZR_ASSERT assert 52 | #endif /* ZR_ASSERT */ 53 | 54 | /* @include "partials/unused.h" */ 55 | /* @include "partials/logger.h" */ 56 | 57 | ZRP_MAYBE_UNUSED ZRP_LOGGER_LINKAGE void 58 | zrLog(enum ZrLogLevel level, 59 | const char *pFile, 60 | int line, 61 | const char *pFormat, 62 | ...) 63 | { 64 | va_list args; 65 | 66 | ZR_ASSERT(pFile != NULL); 67 | ZR_ASSERT(pFormat != NULL); 68 | 69 | va_start(args, pFormat); 70 | zrpLoggerLogVaList(level, pFile, line, pFormat, args); 71 | va_end(args); 72 | } 73 | 74 | ZRP_MAYBE_UNUSED ZRP_LOGGER_LINKAGE void 75 | zrLogVaList(enum ZrLogLevel level, 76 | const char *pFile, 77 | int line, 78 | const char *pFormat, 79 | va_list args) 80 | { 81 | ZR_ASSERT(pFile != NULL); 82 | ZR_ASSERT(pFormat != NULL); 83 | 84 | zrpLoggerLogVaList(level, pFile, line, pFormat, args); 85 | } 86 | 87 | #endif /* ZRP_LOGGER_IMPLEMENTATION_DEFINED */ 88 | #endif /* ZR_DEFINE_IMPLEMENTATION */ 89 | -------------------------------------------------------------------------------- /src/partials/environment.h: -------------------------------------------------------------------------------- 1 | #ifndef ZRP_ARCH_DEFINED 2 | #define ZRP_ARCH_DEFINED 3 | #if defined(__x86_64__) || defined(_M_X64) 4 | #define ZRP_ARCH_X86_64 5 | #elif defined(__i386) || defined(_M_IX86) 6 | #define ZRP_ARCH_X86_32 7 | #elif defined(__itanium__) || defined(_M_IA64) 8 | #define ZRP_ARCH_ITANIUM_64 9 | #elif defined(__powerpc64__) || defined(__ppc64__) 10 | #define ZRP_ARCH_POWERPC_64 11 | #elif defined(__powerpc__) || defined(__ppc__) 12 | #define ZRP_ARCH_POWERPC_32 13 | #elif defined(__aarch64__) 14 | #define ZRP_ARCH_ARM_64 15 | #elif defined(__arm__) 16 | #define ZRP_ARCH_ARM_32 17 | #endif 18 | #endif /* ZRP_ARCH_DEFINED */ 19 | 20 | /* 21 | The environment macro represents whether the code is to be generated for a 22 | 32-bit or 64-bit target platform. Some CPUs, such as the x86-64 processors, 23 | allow running code in 32-bit mode if compiled using the -m32 or -mx32 24 | compiler switches, in which case `ZR_ENVIRONMENT` is set to 32. 25 | */ 26 | #ifndef ZR_ENVIRONMENT 27 | #if (!defined(ZRP_ARCH_X86_64) || defined(__ILP32__)) \ 28 | && !defined(ZRP_ARCH_ITANIUM_64) && !defined(ZRP_ARCH_POWERPC_64) \ 29 | && !defined(ZRP_ARCH_ARM_64) 30 | #define ZR_ENVIRONMENT 32 31 | #else 32 | #define ZR_ENVIRONMENT 64 33 | #endif 34 | #ifdef ZR_DEFINE_IMPLEMENTATION 35 | typedef char zrp_invalid_environment_value 36 | [ZR_ENVIRONMENT == 32 || ZR_ENVIRONMENT == 64 ? 1 : -1]; 37 | #endif /* ZR_DEFINE_IMPLEMENTATION */ 38 | #endif /* ZR_ENVIRONMENT */ 39 | -------------------------------------------------------------------------------- /src/partials/license.h: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2018 Christopher Crouzet 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | -------------------------------------------------------------------------------- /src/partials/logger.h: -------------------------------------------------------------------------------- 1 | #ifndef ZRP_LOGGER_DEFINED 2 | #define ZRP_LOGGER_DEFINED 3 | 4 | #if !defined(ZR_DISABLE_LOG_STYLING) && defined(ZRP_PLATFORM_UNIX) \ 5 | && defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 1 6 | #include 7 | #define ZRP_LOGGER_LOG_STYLING 1 8 | #else 9 | #define ZRP_LOGGER_LOG_STYLING 0 10 | #endif 11 | 12 | #if ZRP_LOGGER_LOG_STYLING 13 | enum ZrpLoggerStyle { 14 | ZRP_LOGGER_STYLE_RESET = 0, 15 | ZRP_LOGGER_STYLE_BLACK = 1, 16 | ZRP_LOGGER_STYLE_RED = 2, 17 | ZRP_LOGGER_STYLE_GREEN = 3, 18 | ZRP_LOGGER_STYLE_YELLOW = 4, 19 | ZRP_LOGGER_STYLE_BLUE = 5, 20 | ZRP_LOGGER_STYLE_MAGENTA = 6, 21 | ZRP_LOGGER_STYLE_CYAN = 7, 22 | ZRP_LOGGER_STYLE_BRIGHT_BLACK = 8, 23 | ZRP_LOGGER_STYLE_BRIGHT_RED = 9, 24 | ZRP_LOGGER_STYLE_BRIGHT_GREEN = 10, 25 | ZRP_LOGGER_STYLE_BRIGHT_YELLOW = 11, 26 | ZRP_LOGGER_STYLE_BRIGHT_BLUE = 12, 27 | ZRP_LOGGER_STYLE_BRIGHT_MAGENTA = 13, 28 | ZRP_LOGGER_STYLE_BRIGHT_CYAN = 14 29 | }; 30 | #endif /* ZRP_LOGGER_LOG_STYLING */ 31 | 32 | static void 33 | zrpLoggerGetLogLevelName(const char **ppName, enum ZrLogLevel level) 34 | { 35 | ZR_ASSERT(ppName != NULL); 36 | 37 | switch (level) { 38 | case ZR_LOG_LEVEL_ERROR: 39 | *ppName = "error"; 40 | return; 41 | case ZR_LOG_LEVEL_WARNING: 42 | *ppName = "warning"; 43 | return; 44 | case ZR_LOG_LEVEL_INFO: 45 | *ppName = "info"; 46 | return; 47 | case ZR_LOG_LEVEL_TRACE: 48 | *ppName = "trace"; 49 | return; 50 | case ZR_LOG_LEVEL_DEBUG: 51 | *ppName = "debug"; 52 | return; 53 | default: 54 | ZR_ASSERT(0); 55 | } 56 | } 57 | 58 | #if ZRP_LOGGER_LOG_STYLING 59 | static void 60 | zrpLoggerGetLogLevelStyle(enum ZrpLoggerStyle *pStyle, enum ZrLogLevel level) 61 | { 62 | ZR_ASSERT(pStyle != NULL); 63 | 64 | switch (level) { 65 | case ZR_LOG_LEVEL_ERROR: 66 | *pStyle = ZRP_LOGGER_STYLE_BRIGHT_RED; 67 | return; 68 | case ZR_LOG_LEVEL_WARNING: 69 | *pStyle = ZRP_LOGGER_STYLE_BRIGHT_YELLOW; 70 | return; 71 | case ZR_LOG_LEVEL_INFO: 72 | *pStyle = ZRP_LOGGER_STYLE_BRIGHT_GREEN; 73 | return; 74 | case ZR_LOG_LEVEL_TRACE: 75 | *pStyle = ZRP_LOGGER_STYLE_BRIGHT_CYAN; 76 | return; 77 | case ZR_LOG_LEVEL_DEBUG: 78 | *pStyle = ZRP_LOGGER_STYLE_BRIGHT_MAGENTA; 79 | return; 80 | default: 81 | ZR_ASSERT(0); 82 | }; 83 | } 84 | 85 | static void 86 | zrpLoggerGetStyleAnsiCode(const char **ppCode, enum ZrpLoggerStyle style) 87 | { 88 | ZR_ASSERT(ppCode != NULL); 89 | 90 | switch (style) { 91 | case ZRP_LOGGER_STYLE_RESET: 92 | *ppCode = "\x1b[0m"; 93 | return; 94 | case ZRP_LOGGER_STYLE_BLACK: 95 | *ppCode = "\x1b[30m"; 96 | return; 97 | case ZRP_LOGGER_STYLE_RED: 98 | *ppCode = "\x1b[31m"; 99 | return; 100 | case ZRP_LOGGER_STYLE_GREEN: 101 | *ppCode = "\x1b[32m"; 102 | return; 103 | case ZRP_LOGGER_STYLE_YELLOW: 104 | *ppCode = "\x1b[33m"; 105 | return; 106 | case ZRP_LOGGER_STYLE_BLUE: 107 | *ppCode = "\x1b[34m"; 108 | return; 109 | case ZRP_LOGGER_STYLE_MAGENTA: 110 | *ppCode = "\x1b[35m"; 111 | return; 112 | case ZRP_LOGGER_STYLE_CYAN: 113 | *ppCode = "\x1b[36m"; 114 | return; 115 | case ZRP_LOGGER_STYLE_BRIGHT_BLACK: 116 | *ppCode = "\x1b[1;30m"; 117 | return; 118 | case ZRP_LOGGER_STYLE_BRIGHT_RED: 119 | *ppCode = "\x1b[1;31m"; 120 | return; 121 | case ZRP_LOGGER_STYLE_BRIGHT_GREEN: 122 | *ppCode = "\x1b[1;32m"; 123 | return; 124 | case ZRP_LOGGER_STYLE_BRIGHT_YELLOW: 125 | *ppCode = "\x1b[1;33m"; 126 | return; 127 | case ZRP_LOGGER_STYLE_BRIGHT_BLUE: 128 | *ppCode = "\x1b[1;34m"; 129 | return; 130 | case ZRP_LOGGER_STYLE_BRIGHT_MAGENTA: 131 | *ppCode = "\x1b[1;35m"; 132 | return; 133 | case ZRP_LOGGER_STYLE_BRIGHT_CYAN: 134 | *ppCode = "\x1b[1;36m"; 135 | return; 136 | default: 137 | ZR_ASSERT(0); 138 | } 139 | } 140 | #endif /* ZRP_LOGGER_LOG_STYLING */ 141 | 142 | ZRP_MAYBE_UNUSED static void 143 | zrpLoggerLogVaList(enum ZrLogLevel level, 144 | const char *pFile, 145 | int line, 146 | const char *pFormat, 147 | va_list args) 148 | { 149 | const char *pLevelName; 150 | const char *pLevelStyleStart; 151 | const char *pLevelStyleEnd; 152 | 153 | ZR_ASSERT(pFile != NULL); 154 | ZR_ASSERT(pFormat != NULL); 155 | 156 | zrpLoggerGetLogLevelName(&pLevelName, level); 157 | 158 | #if ZRP_LOGGER_LOG_STYLING 159 | if (isatty(fileno(stderr))) { 160 | enum ZrpLoggerStyle levelStyle; 161 | 162 | zrpLoggerGetLogLevelStyle(&levelStyle, level); 163 | zrpLoggerGetStyleAnsiCode(&pLevelStyleStart, levelStyle); 164 | zrpLoggerGetStyleAnsiCode(&pLevelStyleEnd, ZRP_LOGGER_STYLE_RESET); 165 | } else { 166 | pLevelStyleStart = pLevelStyleEnd = ""; 167 | } 168 | #else 169 | pLevelStyleStart = pLevelStyleEnd = ""; 170 | #endif /* ZRP_LOGGER_LOG_STYLING */ 171 | 172 | fprintf(stderr, 173 | "%s:%d: %s%s%s: ", 174 | pFile, 175 | line, 176 | pLevelStyleStart, 177 | pLevelName, 178 | pLevelStyleEnd); 179 | vfprintf(stderr, pFormat, args); 180 | } 181 | 182 | ZRP_MAYBE_UNUSED static void 183 | zrpLoggerLog(enum ZrLogLevel level, 184 | const char *pFile, 185 | int line, 186 | const char *pFormat, 187 | ...) 188 | { 189 | va_list args; 190 | 191 | ZR_ASSERT(pFile != NULL); 192 | ZR_ASSERT(pFormat != NULL); 193 | 194 | va_start(args, pFormat); 195 | zrpLoggerLogVaList(level, pFile, line, pFormat, args); 196 | va_end(args); 197 | } 198 | 199 | #endif /* ZRP_LOGGER_DEFINED */ 200 | -------------------------------------------------------------------------------- /src/partials/logging.h: -------------------------------------------------------------------------------- 1 | #ifndef ZRP_LOGGING_DEFINED 2 | #define ZRP_LOGGING_DEFINED 3 | 4 | #if defined(ZR_SET_LOGGING_LEVEL_DEBUG) 5 | #define ZRP_LOGGING_LEVEL ZR_LOG_LEVEL_DEBUG 6 | #elif defined(ZR_SET_LOGGING_LEVEL_TRACE) 7 | #define ZRP_LOGGING_LEVEL ZR_LOG_LEVEL_TRACE 8 | #elif defined(ZR_SET_LOGGING_LEVEL_INFO) 9 | #define ZRP_LOGGING_LEVEL ZR_LOG_LEVEL_INFO 10 | #elif defined(ZR_SET_LOGGING_LEVEL_WARNING) 11 | #define ZRP_LOGGING_LEVEL ZR_LOG_LEVEL_WARNING 12 | #elif defined(ZR_SET_LOGGING_LEVEL_ERROR) 13 | #define ZRP_LOGGING_LEVEL ZR_LOG_LEVEL_ERROR 14 | #elif defined(ZR_ENABLE_DEBUGGING) \ 15 | || (!defined(ZR_DISABLE_DEBUGGING) \ 16 | && (defined(DEBUG) || !defined(NDEBUG))) 17 | #define ZRP_LOGGING_LEVEL ZR_LOG_LEVEL_DEBUG 18 | #else 19 | #define ZRP_LOGGING_LEVEL ZR_LOG_LEVEL_WARNING 20 | #endif 21 | 22 | #ifdef ZR_DISABLE_LOGGING 23 | #define ZRP_LOGGING 0 24 | #else 25 | #define ZRP_LOGGING 1 26 | #endif /* ZR_DISABLE_LOGGING */ 27 | 28 | #ifndef ZR_LOG 29 | #define ZR_LOG(level, ...) \ 30 | do { \ 31 | if (ZRP_LOGGING && level <= ZRP_LOGGING_LEVEL) { \ 32 | zrpLoggerLog(level, __FILE__, __LINE__, __VA_ARGS__); \ 33 | } \ 34 | } while (0) 35 | #endif /* ZR_LOG */ 36 | 37 | #define ZRP_LOG_DEBUG(...) ZR_LOG(ZR_LOG_LEVEL_DEBUG, __VA_ARGS__) 38 | 39 | #define ZRP_LOG_TRACE(...) ZR_LOG(ZR_LOG_LEVEL_TRACE, __VA_ARGS__) 40 | 41 | #define ZRP_LOG_INFO(...) ZR_LOG(ZR_LOG_LEVEL_INFO, __VA_ARGS__) 42 | 43 | #define ZRP_LOG_WARNING(...) ZR_LOG(ZR_LOG_LEVEL_WARNING, __VA_ARGS__) 44 | 45 | #define ZRP_LOG_ERROR(...) ZR_LOG(ZR_LOG_LEVEL_ERROR, __VA_ARGS__) 46 | 47 | #endif /* ZRP_LOGGING_DEFINED */ 48 | -------------------------------------------------------------------------------- /src/partials/loglevel.h: -------------------------------------------------------------------------------- 1 | #ifndef ZRP_LOGLEVEL_DEFINED 2 | #define ZRP_LOGLEVEL_DEFINED 3 | 4 | enum ZrLogLevel { 5 | ZR_LOG_LEVEL_ERROR = 0, 6 | ZR_LOG_LEVEL_WARNING = 1, 7 | ZR_LOG_LEVEL_INFO = 2, 8 | ZR_LOG_LEVEL_TRACE = 3, 9 | ZR_LOG_LEVEL_DEBUG = 4 10 | }; 11 | 12 | #endif /* ZRP_LOGLEVEL_DEFINED */ 13 | -------------------------------------------------------------------------------- /src/partials/platform.h: -------------------------------------------------------------------------------- 1 | #ifndef ZRP_PLATFORM_DEFINED 2 | #define ZRP_PLATFORM_DEFINED 3 | #if defined(_WIN32) 4 | #define ZRP_PLATFORM_WINDOWS 5 | #elif defined(__unix__) || defined(__APPLE__) 6 | #define ZRP_PLATFORM_UNIX 7 | #if defined(__APPLE__) 8 | #define ZRP_PLATFORM_DARWIN 9 | #if TARGET_OS_IPHONE == 1 10 | #define ZRP_PLATFORM_IOS 11 | #elif TARGET_OS_MAC == 1 12 | #define ZRP_PLATFORM_MACOS 13 | #endif 14 | #elif defined(__linux__) 15 | #define ZRP_PLATFORM_LINUX 16 | #endif 17 | #endif 18 | #endif /* ZRP_PLATFORM_DEFINED */ 19 | -------------------------------------------------------------------------------- /src/partials/status.h: -------------------------------------------------------------------------------- 1 | #ifndef ZRP_STATUS_DEFINED 2 | #define ZRP_STATUS_DEFINED 3 | enum ZrStatus { 4 | ZR_SUCCESS = 0, 5 | ZR_ERROR = -1, 6 | ZR_ERROR_ALLOCATION = -2, 7 | ZR_ERROR_MAX_SIZE_EXCEEDED = -3 8 | }; 9 | #endif /* ZRP_STATUS_DEFINED */ 10 | -------------------------------------------------------------------------------- /src/partials/types.h: -------------------------------------------------------------------------------- 1 | #ifndef ZRP_FIXED_TYPES_DEFINED 2 | #define ZRP_FIXED_TYPES_DEFINED 3 | #ifdef ZR_USE_STD_FIXED_TYPES 4 | #include 5 | typedef int8_t ZrInt8; 6 | typedef uint8_t ZrUint8; 7 | typedef int16_t ZrInt16; 8 | typedef uint16_t ZrUint16; 9 | typedef int32_t ZrInt32; 10 | typedef uint32_t ZrUint32; 11 | typedef int64_t ZrInt64; 12 | typedef uint64_t ZrUint64; 13 | #else 14 | /* 15 | The focus here is on the common data models, that is ILP32 (most recent 16 | 32-bit systems), LP64 (Unix-like systems), and LLP64 (Windows). All of these 17 | models have the `char` type set to 8 bits, `short` to 16 bits, `int` to 18 | 32 bits, and `long long` to 64 bits. 19 | */ 20 | #ifdef ZR_INT8 21 | typedef ZR_INT8 ZrInt8; 22 | #else 23 | typedef char ZrInt8; 24 | #endif 25 | #ifdef ZR_UINT8 26 | typedef ZR_UINT8 ZrUint8; 27 | #else 28 | typedef unsigned char ZrUint8; 29 | #endif 30 | #ifdef ZR_INT16 31 | typedef ZR_INT16 ZrInt16; 32 | #else 33 | typedef short ZrInt16; 34 | #endif 35 | #ifdef ZR_UINT16 36 | typedef ZR_UINT16 ZrUint16; 37 | #else 38 | typedef unsigned short ZrUint16; 39 | #endif 40 | #ifdef ZR_INT32 41 | typedef ZR_INT32 ZrInt32; 42 | #else 43 | typedef int ZrInt32; 44 | #endif 45 | #ifdef ZR_UINT32 46 | typedef ZR_UINT32 ZrUint32; 47 | #else 48 | typedef unsigned int ZrUint32; 49 | #endif 50 | #ifdef ZR_INT64 51 | typedef ZR_INT64 ZrInt64; 52 | #else 53 | typedef long long ZrInt64; 54 | #endif 55 | #ifdef ZR_UINT64 56 | typedef ZR_UINT64 ZrUint64; 57 | #else 58 | typedef unsigned long long ZrUint64; 59 | #endif 60 | #endif /* ZR_USE_STD_FIXED_TYPES */ 61 | #ifdef ZR_DEFINE_IMPLEMENTATION 62 | typedef char zrp_invalid_int8_type[sizeof(ZrInt8) == 1 ? 1 : -1]; 63 | typedef char zrp_invalid_uint8_type[sizeof(ZrUint8) == 1 ? 1 : -1]; 64 | typedef char zrp_invalid_int16_type[sizeof(ZrInt16) == 2 ? 1 : -1]; 65 | typedef char zrp_invalid_uint16_type[sizeof(ZrUint16) == 2 ? 1 : -1]; 66 | typedef char zrp_invalid_int32_type[sizeof(ZrInt32) == 4 ? 1 : -1]; 67 | typedef char zrp_invalid_uint32_type[sizeof(ZrUint32) == 4 ? 1 : -1]; 68 | typedef char zrp_invalid_int64_type[sizeof(ZrInt64) == 8 ? 1 : -1]; 69 | typedef char zrp_invalid_uint64_type[sizeof(ZrUint64) == 8 ? 1 : -1]; 70 | #endif /* ZR_DEFINE_IMPLEMENTATION */ 71 | #endif /* ZRP_FIXED_TYPES_DEFINED */ 72 | 73 | #ifndef ZRP_BASIC_TYPES_DEFINED 74 | #define ZRP_BASIC_TYPES_DEFINED 75 | #ifdef ZR_USE_STD_BASIC_TYPES 76 | #include 77 | typedef size_t ZrSize; 78 | #else 79 | /* 80 | The C standard provides no guarantees about the size of the type `size_t`, 81 | and some exotic platforms will in fact provide original values, but this 82 | should cover most of the use cases. 83 | */ 84 | #ifdef ZR_SIZE_TYPE 85 | typedef ZR_SIZE_TYPE ZrSize; 86 | #elif ZR_ENVIRONMENT == 32 87 | typedef ZrUint32 ZrSize; 88 | #else 89 | typedef ZrUint64 ZrSize; 90 | #endif 91 | #endif 92 | #ifdef ZR_DEFINE_IMPLEMENTATION 93 | typedef char 94 | zrp_invalid_size_type[sizeof(ZrSize) == sizeof sizeof(void *) ? 1 : -1]; 95 | #endif /* ZR_DEFINE_IMPLEMENTATION */ 96 | #endif /* ZRP_BASIC_TYPES_DEFINED */ 97 | -------------------------------------------------------------------------------- /src/partials/unused.h: -------------------------------------------------------------------------------- 1 | #ifndef ZRP_UNUSED_DEFINED 2 | #define ZRP_UNUSED_DEFINED 3 | #ifdef __GNUC__ 4 | #define ZRP_MAYBE_UNUSED __attribute__((unused)) 5 | #else 6 | #define ZRP_MAYBE_UNUSED 7 | #endif 8 | #endif /* ZRP_UNUSED_DEFINED */ 9 | -------------------------------------------------------------------------------- /src/timer.h.tpl: -------------------------------------------------------------------------------- 1 | /* @include "partials/license.h" */ 2 | 3 | #ifndef ZERO_TIMER_H 4 | #define ZERO_TIMER_H 5 | 6 | #define ZR_TIMER_MAJOR_VERSION 0 7 | #define ZR_TIMER_MINOR_VERSION 1 8 | #define ZR_TIMER_PATCH_VERSION 0 9 | 10 | /* @include "partials/environment.h" */ 11 | /* @include "partials/platform.h" */ 12 | /* @include "partials/types.h" */ 13 | 14 | /* @include "partials/status.h" */ 15 | 16 | #if defined(ZR_TIMER_SPECIFY_INTERNAL_LINKAGE) \ 17 | || defined(ZR_SPECIFY_INTERNAL_LINKAGE) 18 | #define ZRP_TIMER_LINKAGE static 19 | #elif defined(__cplusplus) 20 | #define ZRP_TIMER_LINKAGE extern "C" 21 | #else 22 | #define ZRP_TIMER_LINKAGE extern 23 | #endif 24 | 25 | #define ZR_TIMER_TICKS_PER_SECOND 1000000000ull 26 | 27 | struct ZrCpuTimes { 28 | ZrUint64 user; 29 | ZrUint64 system; 30 | }; 31 | 32 | ZRP_TIMER_LINKAGE enum ZrStatus 33 | zrGetRealTime(ZrUint64 *pTime); 34 | 35 | ZRP_TIMER_LINKAGE enum ZrStatus 36 | zrGetCpuTimes(struct ZrCpuTimes *pTimes); 37 | 38 | #endif /* ZERO_TIMER_H */ 39 | 40 | #ifdef ZR_DEFINE_IMPLEMENTATION 41 | #ifndef ZRP_TIMER_IMPLEMENTATION_DEFINED 42 | #define ZRP_TIMER_IMPLEMENTATION_DEFINED 43 | 44 | #include 45 | #include 46 | #include 47 | 48 | #ifndef ZR_ASSERT 49 | #include 50 | #define ZR_ASSERT assert 51 | #endif /* ZR_ASSERT */ 52 | 53 | /* @include "partials/unused.h" */ 54 | /* @include "partials/logging.h" */ 55 | /* @include "partials/loglevel.h" */ 56 | /* @include "partials/logger.h" */ 57 | 58 | #if defined(ZRP_PLATFORM_WINDOWS) 59 | #define WIN32_LEAN_AND_MEAN 60 | #include 61 | #elif defined(ZRP_PLATFORM_DARWIN) 62 | #include 63 | #include 64 | #elif defined(ZRP_PLATFORM_UNIX) 65 | #include 66 | #if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309L 67 | #include 68 | #define ZRP_TIMER_USE_CLOCK_GETTIME 69 | #if defined(CLOCK_MONOTONIC_RAW) 70 | #define ZRP_TIMER_CLOCK_ID CLOCK_MONOTONIC_RAW 71 | #elif defined(CLOCK_MONOTONIC) 72 | #define ZRP_TIMER_CLOCK_ID CLOCK_MONOTONIC 73 | #else 74 | #define ZRP_TIMER_CLOCK_ID CLOCK_REALTIME 75 | #endif 76 | #else 77 | #include 78 | #endif 79 | #else 80 | typedef char zrp_timer_unsupported_platform[-1]; 81 | #endif 82 | 83 | /* 84 | In some cases, tick values are casted to 64-bit floating-points in order 85 | to prevent (unlikely) integer overflows during some arithmetic operations. 86 | This effectively reducse the precision of the ticks having a value greater 87 | than 2^53, which corresponds to approximatively 104 days. 88 | */ 89 | 90 | ZRP_MAYBE_UNUSED ZRP_TIMER_LINKAGE enum ZrStatus 91 | zrGetRealTime(ZrUint64 *pTime) 92 | { 93 | ZR_ASSERT(pTime != NULL); 94 | 95 | #if defined(ZRP_PLATFORM_WINDOWS) 96 | { 97 | static double timeToNano; 98 | LARGE_INTEGER time; 99 | 100 | if (timeToNano == 0.0) { 101 | LARGE_INTEGER frequency; 102 | 103 | if (!QueryPerformanceFrequency(&frequency)) { 104 | ZRP_LOG_ERROR("failed to retrieve the time's frequency\n"); 105 | return ZR_ERROR; 106 | } 107 | 108 | timeToNano = (double)ZR_TIMER_TICKS_PER_SECOND / frequency.QuadPart; 109 | } 110 | 111 | if (!QueryPerformanceCounter(&time)) { 112 | ZRP_LOG_ERROR("failed to retrieve the current time\n"); 113 | return ZR_ERROR; 114 | } 115 | 116 | *pTime = time.QuadPart * timeToNano; 117 | return ZR_SUCCESS; 118 | } 119 | #elif defined(ZRP_PLATFORM_DARWIN) 120 | /* 121 | Since Darwin 5.2, `clock_gettime()` can return high resolution times 122 | with the `CLOCK_UPTIME_RAW` clock but it internally only calls 123 | `mach_absolute_time()` with the overhead of converting the result into 124 | the `timespec` format. 125 | */ 126 | { 127 | static double timeToNano; 128 | 129 | if (timeToNano == 0.0) { 130 | mach_timebase_info_data_t info; 131 | 132 | if (mach_timebase_info(&info) != KERN_SUCCESS) { 133 | ZRP_LOG_ERROR("failed to retrieve the current time\n"); 134 | return ZR_ERROR; 135 | } 136 | 137 | timeToNano = (double)info.numer / info.denom; 138 | } 139 | 140 | *pTime = mach_absolute_time() * timeToNano; 141 | return ZR_SUCCESS; 142 | } 143 | #elif defined(ZRP_PLATFORM_UNIX) 144 | #if defined(ZRP_TIMER_USE_CLOCK_GETTIME) 145 | { 146 | struct timespec time; 147 | 148 | if (clock_gettime(ZRP_TIMER_CLOCK_ID, &time) != 0) { 149 | ZRP_LOG_ERROR("failed to retrieve the current time\n"); 150 | return ZR_ERROR; 151 | } 152 | 153 | *pTime = (ZrUint64)time.tv_sec * 1000000000ull + (ZrUint64)time.tv_nsec; 154 | return ZR_SUCCESS; 155 | } 156 | #else 157 | { 158 | struct timeval time; 159 | 160 | if (gettimeofday(&time, NULL) != 0) { 161 | ZRP_LOG_ERROR("failed to retrieve the current time\n"); 162 | return ZR_ERROR; 163 | } 164 | 165 | *pTime = (ZrUint64)time.tv_sec * 1000000000ull 166 | + (ZrUint64)time.tv_usec * 1000ull; 167 | return ZR_SUCCESS; 168 | } 169 | #endif 170 | #endif 171 | 172 | ZRP_LOG_ERROR("platform not supported\n"); 173 | return ZR_ERROR; 174 | } 175 | 176 | ZRP_MAYBE_UNUSED ZRP_TIMER_LINKAGE enum ZrStatus 177 | zrGetCpuTimes(struct ZrCpuTimes *pTimes) 178 | { 179 | ZR_ASSERT(pTimes != NULL); 180 | 181 | #if defined(ZRP_PLATFORM_WINDOWS) 182 | { 183 | FILETIME creationTime; 184 | FILETIME exitTime; 185 | FILETIME kernelTime; 186 | FILETIME userTime; 187 | ULARGE_INTEGER time; 188 | 189 | if (!GetProcessTimes(GetCurrentProcess(), 190 | &creationTime, 191 | &exitTime, 192 | &kernelTime, 193 | &userTime)) { 194 | ZRP_LOG_ERROR("failed to retrieve the current CPU times\n"); 195 | return ZR_ERROR; 196 | } 197 | 198 | time.LowPart = userTime.dwLowDateTime; 199 | time.HighPart = userTime.dwHighDateTime; 200 | *pTimes->user = time.QuadPart * 100ull; 201 | 202 | time.LowPart = kernelTime.dwLowDateTime; 203 | time.HighPart = kernelTime.dwHighDateTime; 204 | *pTimes->system = time.QuadPart * 100ull; 205 | } 206 | #elif defined(ZRP_PLATFORM_UNIX) 207 | { 208 | struct rusage usage; 209 | 210 | if (getrusage(RUSAGE_SELF, &usage)) { 211 | ZRP_LOG_ERROR("failed to retrieve the current CPU times\n"); 212 | return ZR_ERROR; 213 | } 214 | 215 | pTimes->user = (ZrUint64)usage.ru_utime.tv_sec * 1000000000ull 216 | + (ZrUint64)usage.ru_utime.tv_usec * 1000ull; 217 | pTimes->system = (ZrUint64)usage.ru_stime.tv_sec * 1000000000ull 218 | + (ZrUint64)usage.ru_stime.tv_usec * 1000ull; 219 | return ZR_SUCCESS; 220 | } 221 | #endif 222 | 223 | ZRP_LOG_ERROR("platform not supported\n"); 224 | return ZR_ERROR; 225 | } 226 | 227 | #endif /* ZRP_TIMER_IMPLEMENTATION_DEFINED */ 228 | #endif /* ZR_DEFINE_IMPLEMENTATION */ 229 | -------------------------------------------------------------------------------- /tools/build/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define ZR_OPENING_COMMENT_TAG "/*" 10 | #define ZR_OPENING_COMMENT_TAG_LENGTH 2 11 | #define ZR_CLOSING_COMMENT_TAG "*/" 12 | #define ZR_CLOSING_COMMENT_TAG_LENGTH 2 13 | 14 | #ifdef _WIN32 15 | #define ZR_PATH_SEPARATOR '\\' 16 | #else 17 | #define ZR_PATH_SEPARATOR '/' 18 | #endif 19 | 20 | typedef enum ZrDirectiveType { ZR_DIRECTIVE_TYPE_INCLUDE = 0 } ZrDirectiveType; 21 | 22 | typedef struct ZrDirective ZrDirective; 23 | 24 | typedef struct ZrIncludeDirectiveData { 25 | char path[512]; 26 | char *pBuffer; 27 | size_t bufferSize; 28 | } ZrIncludeDirectiveData; 29 | 30 | struct ZrDirective { 31 | size_t pos; 32 | size_t length; 33 | ZrDirectiveType type; 34 | void *pData; 35 | ZrDirective *pNext; 36 | }; 37 | 38 | static void 39 | zrDestroyBuffer(char *pBuffer) 40 | { 41 | free(pBuffer); 42 | } 43 | 44 | static int 45 | zrCreateBufferFromFile(const char *pPath, size_t *pSize, void **ppBuffer) 46 | { 47 | int out; 48 | FILE *pFile; 49 | long size; 50 | 51 | assert(pPath != NULL); 52 | assert(pSize != NULL); 53 | assert(ppBuffer != NULL); 54 | 55 | out = 0; 56 | 57 | pFile = fopen(pPath, "re"); 58 | if (pFile == NULL) { 59 | fprintf(stderr, "could not open the file '%s'\n", pPath); 60 | out = 1; 61 | goto exit; 62 | } 63 | 64 | fseek(pFile, 0, SEEK_END); 65 | size = ftell(pFile); 66 | fseek(pFile, 0, SEEK_SET); 67 | 68 | *ppBuffer = malloc((size_t)size); 69 | 70 | if (fread(*ppBuffer, 1, (size_t)size, pFile) != (size_t)size) { 71 | fprintf(stderr, "could not read the file '%s'\n", pPath); 72 | out = 1; 73 | goto buffer_undo; 74 | } 75 | 76 | *pSize = (size_t)size; 77 | 78 | goto cleanup; 79 | 80 | buffer_undo: 81 | zrDestroyBuffer(*ppBuffer); 82 | 83 | cleanup: 84 | if (fclose(pFile) == EOF) { 85 | fprintf(stderr, "could not close the file '%s'\n", pPath); 86 | out = 1; 87 | } 88 | 89 | exit: 90 | return out; 91 | } 92 | 93 | static int 94 | zrWriteFile(const char *pPath, size_t size, const char *pBuffer) 95 | { 96 | int out; 97 | FILE *pFile; 98 | 99 | assert(pPath != NULL); 100 | assert(pBuffer != NULL); 101 | 102 | out = 0; 103 | 104 | pFile = fopen(pPath, "we"); 105 | if (pFile == NULL) { 106 | fprintf(stderr, "could not open the file '%s'\n", pPath); 107 | out = 1; 108 | goto exit; 109 | } 110 | 111 | if (fwrite(pBuffer, 1, size, pFile) != size) { 112 | fprintf(stderr, "could not write the file '%s'\n", pPath); 113 | out = 1; 114 | goto cleanup; 115 | } 116 | 117 | cleanup: 118 | if (fclose(pFile) == EOF) { 119 | fprintf(stderr, "could not close the file '%s'\n", pPath); 120 | out = 1; 121 | } 122 | 123 | exit: 124 | return out; 125 | } 126 | 127 | static const char * 128 | zrSkipSpaces(const char *pBuffer, const char *pEnd) 129 | { 130 | assert(pBuffer != NULL); 131 | assert(pEnd != NULL); 132 | 133 | while (pBuffer < pEnd && isspace(*pBuffer)) { 134 | ++pBuffer; 135 | } 136 | 137 | return pBuffer; 138 | } 139 | 140 | static size_t 141 | zrGetWordLength(const char *pBuffer, const char *pEnd) 142 | { 143 | const char *pCursor; 144 | 145 | assert(pBuffer != NULL); 146 | assert(pEnd != NULL); 147 | 148 | pCursor = pBuffer; 149 | while (pCursor < pEnd && isalnum(*pCursor)) { 150 | ++pCursor; 151 | } 152 | 153 | return (size_t)(pCursor - pBuffer); 154 | } 155 | 156 | static size_t 157 | zrGetStringLength(const char *pBuffer, const char *pEnd) 158 | { 159 | const char *pCursor; 160 | 161 | assert(pBuffer != NULL); 162 | assert(pEnd != NULL); 163 | 164 | pCursor = pBuffer; 165 | if (pCursor == pEnd || *pCursor != '"') { 166 | return (size_t)-1; 167 | } 168 | 169 | ++pCursor; 170 | while (pCursor < pEnd && *pCursor != '"') { 171 | ++pCursor; 172 | } 173 | 174 | if (pCursor == pEnd || *pCursor != '"') { 175 | return (size_t)-1; 176 | } 177 | 178 | return (size_t)(pCursor - pBuffer) - 1; 179 | } 180 | 181 | static void 182 | zrDestroyIncludeDirectiveData(ZrIncludeDirectiveData *pData) 183 | { 184 | if (pData == NULL) { 185 | return; 186 | } 187 | 188 | zrDestroyBuffer(pData->pBuffer); 189 | free(pData); 190 | } 191 | 192 | static int 193 | zrCreateIncludeDirectiveData(const char *pBufferFront, 194 | const char *pBufferBack, 195 | const char *pBasePath, 196 | ZrIncludeDirectiveData **ppData) 197 | { 198 | int out; 199 | size_t length; 200 | size_t baseLength; 201 | char *pCursor; 202 | 203 | assert(pBufferFront != NULL); 204 | assert(pBufferBack != NULL); 205 | assert(ppData != NULL); 206 | 207 | out = 0; 208 | *ppData = (ZrIncludeDirectiveData *)malloc(sizeof(ZrIncludeDirectiveData)); 209 | 210 | pBufferFront = zrSkipSpaces(pBufferFront, pBufferBack); 211 | length = zrGetStringLength(pBufferFront, pBufferBack); 212 | if (length == 0 || length == (size_t)-1) { 213 | out = 1; 214 | goto data_undo; 215 | } 216 | 217 | baseLength = strlen(pBasePath); 218 | assert(baseLength + length < sizeof(*ppData)->path); 219 | pCursor = (*ppData)->path; 220 | 221 | strncpy(pCursor, pBasePath, baseLength); 222 | pCursor += baseLength; 223 | 224 | *pCursor = ZR_PATH_SEPARATOR; 225 | ++pCursor; 226 | 227 | strncpy(pCursor, pBufferFront + 1, length); 228 | pCursor += length; 229 | 230 | *pCursor = '\0'; 231 | 232 | if (zrCreateBufferFromFile((*ppData)->path, 233 | &(*ppData)->bufferSize, 234 | (void **)&(*ppData)->pBuffer)) { 235 | out = 1; 236 | goto data_undo; 237 | } 238 | 239 | goto exit; 240 | 241 | data_undo: 242 | free(*ppData); 243 | 244 | exit: 245 | return out; 246 | } 247 | 248 | static void 249 | zrDestroyDirectives(ZrDirective *pHead) 250 | { 251 | ZrDirective *pCurrent; 252 | 253 | while (pHead != NULL) { 254 | pCurrent = pHead; 255 | pHead = pHead->pNext; 256 | 257 | switch (pCurrent->type) { 258 | case ZR_DIRECTIVE_TYPE_INCLUDE: 259 | zrDestroyIncludeDirectiveData(pCurrent->pData); 260 | break; 261 | default: 262 | break; 263 | } 264 | 265 | free(pCurrent); 266 | } 267 | } 268 | 269 | static int 270 | zrCreateDirectives(const char *pBuffer, 271 | const char *pBasePath, 272 | ZrDirective **ppHead) 273 | { 274 | int out; 275 | ZrDirective *pCurrent; 276 | const char *pBufferStart; 277 | 278 | assert(pBuffer != NULL); 279 | assert(ppHead != NULL); 280 | 281 | out = 0; 282 | *ppHead = pCurrent = NULL; 283 | pBufferStart = pBuffer; 284 | 285 | while (1) { 286 | ZrDirective directive; 287 | const char *pBufferFront; 288 | const char *pBufferBack; 289 | size_t length; 290 | 291 | pBufferFront = strstr(pBufferStart, ZR_OPENING_COMMENT_TAG); 292 | if (pBufferFront == NULL) { 293 | break; 294 | } 295 | 296 | directive.pos = (size_t)(pBufferFront - pBuffer); 297 | 298 | pBufferBack = strstr(pBufferFront, ZR_CLOSING_COMMENT_TAG); 299 | if (pBufferBack == NULL) { 300 | fprintf(stderr, "no matching closing comment tag found\n"); 301 | out = 1; 302 | goto directives_undo; 303 | } 304 | 305 | pBufferStart = pBufferBack + ZR_CLOSING_COMMENT_TAG_LENGTH; 306 | directive.length = (size_t)(pBufferStart - pBufferFront); 307 | pBufferFront += ZR_OPENING_COMMENT_TAG_LENGTH; 308 | 309 | pBufferFront = zrSkipSpaces(pBufferFront, pBufferBack); 310 | if (pBufferFront == pBufferBack || *pBufferFront != '@') { 311 | continue; 312 | } 313 | 314 | ++pBufferFront; 315 | 316 | pBufferFront = zrSkipSpaces(pBufferFront, pBufferBack); 317 | length = zrGetWordLength(pBufferFront, pBufferBack); 318 | if (length == 0 || length == (size_t)-1) { 319 | continue; 320 | } 321 | 322 | if (strncmp(pBufferFront, "include", length) == 0) { 323 | pBufferFront += length; 324 | directive.type = ZR_DIRECTIVE_TYPE_INCLUDE; 325 | if (zrCreateIncludeDirectiveData( 326 | pBufferFront, 327 | pBufferBack, 328 | pBasePath, 329 | (ZrIncludeDirectiveData **)&directive.pData)) { 330 | continue; 331 | } 332 | } else { 333 | continue; 334 | } 335 | 336 | directive.pNext = NULL; 337 | 338 | if (pCurrent == NULL) { 339 | *ppHead = pCurrent = (ZrDirective *)malloc(sizeof *pCurrent); 340 | memcpy(pCurrent, &directive, sizeof *pCurrent); 341 | } else { 342 | ZrDirective *pDirective; 343 | 344 | pDirective = (ZrDirective *)malloc(sizeof *pDirective); 345 | memcpy(pDirective, &directive, sizeof *pDirective); 346 | pCurrent->pNext = pDirective; 347 | pCurrent = pDirective; 348 | } 349 | } 350 | 351 | goto exit; 352 | 353 | directives_undo: 354 | zrDestroyDirectives(*ppHead); 355 | 356 | exit: 357 | return out; 358 | } 359 | 360 | static int 361 | zrProcessIncludeDirectives(const ZrDirective *pHead, 362 | size_t *pBufferSize, 363 | char **ppBuffer) 364 | { 365 | char *pOut; 366 | const ZrDirective *pCurrent; 367 | int doIt; 368 | size_t length; 369 | char *pFrom; 370 | char *pTo; 371 | size_t offset; 372 | 373 | assert(pHead != NULL); 374 | assert(ppBuffer != NULL); 375 | assert(*ppBuffer != NULL); 376 | 377 | doIt = 0; 378 | length = *pBufferSize; 379 | pCurrent = pHead; 380 | while (pCurrent != NULL) { 381 | if (pCurrent->type == ZR_DIRECTIVE_TYPE_INCLUDE) { 382 | doIt = 1; 383 | length += ((ZrIncludeDirectiveData *)pCurrent->pData)->bufferSize 384 | - pCurrent->length; 385 | } 386 | 387 | pCurrent = pCurrent->pNext; 388 | } 389 | if (!doIt) { 390 | return 0; 391 | } 392 | 393 | pFrom = *ppBuffer; 394 | pTo = pOut = (char *)malloc(length); 395 | offset = 0; 396 | pCurrent = pHead; 397 | while (pCurrent != NULL) { 398 | if (pCurrent->type == ZR_DIRECTIVE_TYPE_INCLUDE) { 399 | assert(offset < *pBufferSize); 400 | memcpy(pTo, pFrom + offset, pCurrent->pos - offset); 401 | pTo += pCurrent->pos - offset; 402 | memcpy(pTo, 403 | ((ZrIncludeDirectiveData *)pCurrent->pData)->pBuffer, 404 | ((ZrIncludeDirectiveData *)pCurrent->pData)->bufferSize); 405 | pTo += ((ZrIncludeDirectiveData *)pCurrent->pData)->bufferSize; 406 | offset = pCurrent->pos + pCurrent->length; 407 | } 408 | 409 | pCurrent = pCurrent->pNext; 410 | } 411 | 412 | assert(offset < *pBufferSize); 413 | memcpy(pTo, pFrom + offset, *pBufferSize - offset); 414 | 415 | zrDestroyBuffer(*ppBuffer); 416 | *pBufferSize = length; 417 | *ppBuffer = pOut; 418 | return 0; 419 | } 420 | 421 | static void 422 | zrGetDirectory(const char *pPath, char *pOut) 423 | { 424 | char *pLastSeparator; 425 | 426 | pLastSeparator = strrchr(pPath, ZR_PATH_SEPARATOR); 427 | strncpy(pOut, pPath, (size_t)(pLastSeparator - pPath)); 428 | pOut[pLastSeparator - pPath] = '\0'; 429 | } 430 | 431 | int 432 | main(int argc, char **ppArgv) 433 | { 434 | int out; 435 | char basePath[512]; 436 | char *pBuffer; 437 | size_t bufferSize; 438 | ZrDirective *pDirectives; 439 | 440 | out = 0; 441 | 442 | if (argc != 3) { 443 | fprintf(stderr, "Usage:\n build \n"); 444 | out = 1; 445 | goto exit; 446 | } 447 | 448 | assert(strlen(ppArgv[1]) < sizeof basePath); 449 | zrGetDirectory(ppArgv[1], basePath); 450 | 451 | if (zrCreateBufferFromFile(ppArgv[1], &bufferSize, (void **)&pBuffer)) { 452 | out = 1; 453 | goto exit; 454 | } 455 | 456 | if (zrCreateDirectives(pBuffer, basePath, &pDirectives)) { 457 | out = 1; 458 | goto buffer_cleanup; 459 | } 460 | 461 | if (zrProcessIncludeDirectives(pDirectives, &bufferSize, &pBuffer)) { 462 | out = 1; 463 | goto directives_cleanup; 464 | } 465 | 466 | if (zrWriteFile(ppArgv[2], bufferSize, pBuffer)) { 467 | out = 1; 468 | goto directives_cleanup; 469 | } 470 | 471 | directives_cleanup: 472 | zrDestroyDirectives(pDirectives); 473 | 474 | buffer_cleanup: 475 | zrDestroyBuffer(pBuffer); 476 | 477 | exit: 478 | return out; 479 | } 480 | --------------------------------------------------------------------------------