├── .editorconfig ├── .gitattributes ├── .github └── workflows │ └── main.yml ├── .gitignore ├── 3rdparty ├── .editorconfig ├── catch │ ├── catch_amalgamated.cpp │ └── catch_amalgamated.hpp └── ini │ ├── README.md │ ├── ini.h │ └── ini.md ├── LICENSE ├── README.md ├── include ├── bx │ ├── allocator.h │ ├── bounds.h │ ├── bx.h │ ├── commandline.h │ ├── config.h │ ├── constants.h │ ├── cpu.h │ ├── debug.h │ ├── easing.h │ ├── endian.h │ ├── error.h │ ├── file.h │ ├── filepath.h │ ├── float4x4_t.h │ ├── handlealloc.h │ ├── hash.h │ ├── inline │ │ ├── allocator.inl │ │ ├── bounds.inl │ │ ├── bx.inl │ │ ├── cpu.inl │ │ ├── easing.inl │ │ ├── endian.inl │ │ ├── error.inl │ │ ├── float4x4_t.inl │ │ ├── handlealloc.inl │ │ ├── hash.inl │ │ ├── math.inl │ │ ├── mpscqueue.inl │ │ ├── mutex.inl │ │ ├── os.inl │ │ ├── pixelformat.inl │ │ ├── readerwriter.inl │ │ ├── ringbuffer.inl │ │ ├── rng.inl │ │ ├── simd128_langext.inl │ │ ├── simd128_neon.inl │ │ ├── simd128_ref.inl │ │ ├── simd128_sse.inl │ │ ├── simd128_swizzle.inl │ │ ├── simd256_avx.inl │ │ ├── simd256_ref.inl │ │ ├── simd_ni.inl │ │ ├── sort.inl │ │ ├── spscqueue.inl │ │ ├── string.inl │ │ ├── typetraits.inl │ │ └── uint32_t.inl │ ├── macros.h │ ├── math.h │ ├── mpscqueue.h │ ├── mutex.h │ ├── os.h │ ├── pixelformat.h │ ├── platform.h │ ├── process.h │ ├── readerwriter.h │ ├── ringbuffer.h │ ├── rng.h │ ├── semaphore.h │ ├── settings.h │ ├── simd_t.h │ ├── sort.h │ ├── spscqueue.h │ ├── string.h │ ├── thread.h │ ├── timer.h │ ├── typetraits.h │ ├── uint32_t.h │ └── url.h ├── compat │ ├── freebsd │ │ ├── dirent.h │ │ ├── malloc.h │ │ └── signal.h │ ├── ios │ │ └── malloc.h │ ├── linux │ │ └── sal.h │ ├── mingw │ │ ├── dirent.h │ │ ├── sal.h │ │ ├── salieri.h │ │ ├── specstrings_strict.h │ │ └── specstrings_undef.h │ ├── msvc │ │ └── dirent.h │ └── osx │ │ └── malloc.h └── tinystl │ ├── LICENSE │ ├── allocator.h │ ├── buffer.h │ ├── hash.h │ ├── hash_base.h │ ├── new.h │ ├── stddef.h │ ├── string.h │ ├── string_view.h │ ├── traits.h │ ├── unordered_map.h │ ├── unordered_set.h │ └── vector.h ├── scripts ├── bin2c.lua ├── bx.lua ├── bx.natvis ├── genie.lua ├── tinystl.natvis ├── toolchain.lua └── update_tinystl.sh ├── src ├── allocator.cpp ├── amalgamated.cpp ├── bounds.cpp ├── bx.cpp ├── commandline.cpp ├── crtnone.cpp ├── debug.cpp ├── dtoa.cpp ├── easing.cpp ├── file.cpp ├── filepath.cpp ├── hash.cpp ├── math.cpp ├── mutex.cpp ├── os.cpp ├── process.cpp ├── semaphore.cpp ├── settings.cpp ├── sort.cpp ├── string.cpp ├── thread.cpp ├── timer.cpp └── url.cpp ├── tests ├── allocator_test.cpp ├── atomic_test.cpp ├── cast_test.cpp ├── crt_test.cpp ├── dbg.h ├── easing_test.cpp ├── filepath_test.cpp ├── handle_bench.cpp ├── handle_test.cpp ├── hash_test.cpp ├── macros_test.cpp ├── main_test.cpp ├── math_bench.cpp ├── math_test.cpp ├── os_test.cpp ├── pixelformat_test.cpp ├── queue_test.cpp ├── readerwriter_test.cpp ├── ringbuffer_test.cpp ├── rng_test.cpp ├── run_test.cpp ├── settings_test.cpp ├── simd_bench.cpp ├── simd_test.cpp ├── sort_test.cpp ├── string_test.cpp ├── test.h ├── thread_test.cpp ├── tokenizecmd_test.cpp ├── typetraits_test.cpp ├── uint32_test.cpp ├── unordered_map_nonpod_test.cpp ├── unordered_map_test.cpp ├── unordered_set_copyctor_test.cpp ├── unordered_set_pod_test.cpp ├── unordered_set_test.cpp ├── url_test.cpp ├── vector_complex_test.cpp ├── vector_header_test.cpp ├── vector_nocopy_test.cpp ├── vector_nodefault_test.cpp ├── vector_primitive_test.cpp ├── vector_shrinktofit_test.cpp └── vsnprintf_test.cpp └── tools ├── bin ├── darwin │ ├── bin2c │ ├── genie │ └── ninja ├── linux │ ├── bin2c │ ├── genie │ └── ninja └── windows │ ├── bin2c.exe │ ├── genie.exe │ └── ninja.exe └── bin2c └── bin2c.cpp /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = tab 6 | indent_size = 4 7 | end_of_line = lf 8 | max_line_length = 100 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | max_line_length = 80 15 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.c eol=lf 2 | *.cpp eol=lf 3 | *.h eol=lf 4 | *.sc eol=lf 5 | *.sh eol=lf 6 | *.m eol=lf 7 | *.mm eol=lf 8 | *.md eol=lf 9 | *.lua eol=lf 10 | *.mk eol=lf 11 | makefile eol=lf 12 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | concurrency: 4 | group: ${{ github.ref }} 5 | cancel-in-progress: true 6 | 7 | on: 8 | push: 9 | pull_request: 10 | 11 | jobs: 12 | msvc: 13 | strategy: 14 | fail-fast: true 15 | matrix: 16 | include: [ 17 | { config: Debug, platform: x64, bindir: 'win64_vs2022' }, 18 | { config: Release, platform: x64, bindir: 'win64_vs2022' }, 19 | ] 20 | name: msvc-${{ matrix.config }}-${{ matrix.platform }} 21 | runs-on: windows-2022 22 | steps: 23 | - name: Checkout bx 24 | uses: actions/checkout@v4 25 | with: 26 | repository: bkaradzic/bx 27 | path: bx 28 | - name: Prepare 29 | uses: microsoft/setup-msbuild@v2 30 | - name: Build 31 | shell: cmd 32 | run: | 33 | cd bx 34 | tools\bin\windows\genie.exe vs2022 35 | msbuild ".build/projects/vs2022/bx.sln" /m /v:minimal /p:Configuration=${{ matrix.config }} /p:Platform=${{ matrix.platform }} 36 | - name: Check 37 | shell: cmd 38 | run: | 39 | cd bx 40 | ".build\${{ matrix.bindir }}\bin\bx.test${{ matrix.config }}.exe" -d yes 41 | mingw: 42 | strategy: 43 | fail-fast: true 44 | matrix: 45 | include: [ 46 | { msystem: MINGW64, project: 'mingw-gcc', bindir: 'win64_mingw-gcc' }, 47 | # { msystem: CLANG64, project: 'mingw-clang', bindir: 'win64_mingw-clang' }, 48 | ] 49 | name: mingw-${{ matrix.msystem }} 50 | runs-on: windows-2022 51 | steps: 52 | - name: Checkout bx 53 | uses: actions/checkout@v4 54 | with: 55 | repository: bkaradzic/bx 56 | path: bx 57 | - name: Prepare 58 | uses: msys2/setup-msys2@v2 59 | with: 60 | msystem: ${{ matrix.msystem }} 61 | update: true 62 | install: make 63 | pacboy: cc:p 64 | - name: Build 65 | shell: msys2 {0} 66 | run: | 67 | cd bx 68 | tools/bin/windows/genie.exe --gcc=${{ matrix.project }} gmake 69 | make -R -C .build/projects/gmake-${{ matrix.project }} config=release64 -j$(nproc) AR=ar CC=cc CXX=c++ MINGW=$MINGW_PREFIX 70 | - name: Check 71 | shell: cmd 72 | run: | 73 | cd bx 74 | ".build\${{ matrix.bindir }}\bin\bx.testRelease.exe" -d yes 75 | linux: 76 | strategy: 77 | fail-fast: true 78 | matrix: 79 | include: [ 80 | { config: debug, binsuffix: Debug }, 81 | { config: release, binsuffix: Release }, 82 | ] 83 | name: linux-gcc-${{ matrix.config }}64 84 | runs-on: ubuntu-24.04 85 | steps: 86 | - name: Checkout bx 87 | uses: actions/checkout@v4 88 | with: 89 | repository: bkaradzic/bx 90 | path: bx 91 | - name: Build 92 | run: | 93 | cd bx 94 | tools/bin/linux/genie --gcc=linux-gcc gmake 95 | make -R -C .build/projects/gmake-linux-gcc config=${{ matrix.config }}64 -j$(nproc) 96 | - name: Check 97 | run: | 98 | cd bx 99 | ".build/linux64_gcc/bin/bx.test${{ matrix.binsuffix}}" -d yes 100 | osx: 101 | strategy: 102 | fail-fast: true 103 | matrix: 104 | include: [ 105 | { config: debug, binsuffix: Debug }, 106 | { config: release, binsuffix: Release }, 107 | ] 108 | name: osx-x64-${{ matrix.config }} 109 | runs-on: macos-14 110 | steps: 111 | - name: Checkout bx 112 | uses: actions/checkout@v4 113 | with: 114 | repository: bkaradzic/bx 115 | path: bx 116 | - name: Build 117 | run: | 118 | cd bx 119 | tools/bin/darwin/genie --gcc=osx-x64 gmake 120 | make -C .build/projects/gmake-osx-x64 config=${{ matrix.config }} -j$(sysctl -n hw.physicalcpu) 121 | - name: Check 122 | run: | 123 | cd bx 124 | ".build/osx-x64/bin/bx.test${{ matrix.binsuffix}}" -d yes 125 | emscripten: 126 | strategy: 127 | fail-fast: true 128 | matrix: 129 | include: [ 130 | { config: debug, binsuffix: Debug }, 131 | { config: release, binsuffix: Release }, 132 | ] 133 | name: wasm-${{ matrix.config }} 134 | runs-on: ubuntu-24.04 135 | steps: 136 | - name: Checkout bx 137 | uses: actions/checkout@v4 138 | with: 139 | repository: bkaradzic/bx 140 | path: bx 141 | - uses: mymindstorm/setup-emsdk@v14 142 | - uses: browser-actions/setup-chrome@v1 143 | - name: Build 144 | run: | 145 | cd bx 146 | tools/bin/linux/genie --gcc=wasm gmake 147 | make -C .build/projects/gmake-wasm config=${{ matrix.config }} -j$(nproc) EMSCRIPTEN=$EMSDK/upstream/emscripten 148 | - name: Check 149 | run: | 150 | cd bx 151 | # npx http-server -o .build/wasm/bin/ & chromium http://127.0.0.1:8080/.build/wasm/bin/bx.testRelease.html 152 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .git 2 | .build 3 | .debug 4 | .svn 5 | tags 6 | .DS_Store 7 | .gdb_history 8 | -------------------------------------------------------------------------------- /3rdparty/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [ini/*] 4 | indent_style = space 5 | indent_size = 4 6 | trim_trailing_whitespace = true 7 | -------------------------------------------------------------------------------- /3rdparty/ini/README.md: -------------------------------------------------------------------------------- 1 | https://github.com/mattiasgustavsson/libs/ 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2010-2025 Branimir Karadzic 2 | 3 | Redistribution and use in source and binary forms, with or without modification, 4 | are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this 7 | list of conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 17 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 18 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 20 | OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 21 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 22 | OF THE POSSIBILITY OF SUCH DAMAGE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | bx 2 | == 3 | 4 | Base X-platform library. 5 | 6 | [![GitHub Actions](https://github.com/bkaradzic/bx/actions/workflows/main.yml/badge.svg)](https://github.com/bkaradzic/bx/actions) 7 | [![License](https://img.shields.io/badge/license-BSD--2%20clause-blue.svg)](https://bkaradzic.github.io/bgfx/license.html) 8 | [![Join the chat at https://discord.gg/9eMbv7J](https://img.shields.io/discord/712512073522872352?color=%237289DA&label=bx&logo=discord&logoColor=white)](https://discord.gg/9eMbv7J) 9 | 10 | Goals: 11 | 12 | - Provide OS/runtime/compiler independent core functionality to be able to 13 | write cross-platform applications. 14 | - Compile without C Runtime (CRT) and without C++ Standard Library (STL). 15 | 16 | Contact 17 | ------- 18 | 19 | [@bkaradzic](https://twitter.com/bkaradzic) 20 | 21 | Project page 22 | https://github.com/bkaradzic/bx 23 | 24 | [License (BSD 2-clause)](https://github.com/bkaradzic/bx/blob/master/LICENSE) 25 | ----------------------------------------------------------------------------- 26 | 27 | 28 | 29 | 30 | 31 | Copyright 2010-2025 Branimir Karadzic 32 | 33 | Redistribution and use in source and binary forms, with or without modification, 34 | are permitted provided that the following conditions are met: 35 | 36 | 1. Redistributions of source code must retain the above copyright notice, this 37 | list of conditions and the following disclaimer. 38 | 39 | 2. Redistributions in binary form must reproduce the above copyright notice, 40 | this list of conditions and the following disclaimer in the documentation 41 | and/or other materials provided with the distribution. 42 | 43 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 44 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 45 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 46 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 47 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 48 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 49 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 50 | OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 51 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 52 | OF THE POSSIBILITY OF SUCH DAMAGE. 53 | -------------------------------------------------------------------------------- /include/bx/allocator.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #ifndef BX_ALLOCATOR_H_HEADER_GUARD 7 | #define BX_ALLOCATOR_H_HEADER_GUARD 8 | 9 | #include "bx.h" 10 | #include "uint32_t.h" 11 | 12 | #define BX_NEW(_allocator, _type) BX_PLACEMENT_NEW(bx::alloc(_allocator, sizeof(_type) ), _type) 13 | #define BX_ALIGNED_NEW(_allocator, _type, _align) BX_PLACEMENT_NEW(bx::alloc(_allocator, sizeof(_type), _align), _type) 14 | #define BX_PLACEMENT_NEW(_ptr, _type) ::new(bx::PlacementNew, _ptr) _type 15 | 16 | void* operator new(size_t, bx::PlacementNewTag, void* _ptr); 17 | void operator delete(void*, bx::PlacementNewTag, void*) throw(); 18 | 19 | namespace bx 20 | { 21 | /// Abstract allocator interface. 22 | /// 23 | struct BX_NO_VTABLE AllocatorI 24 | { 25 | /// 26 | virtual ~AllocatorI() = 0; 27 | 28 | /// Allocates, resizes, or frees memory block. 29 | /// 30 | /// @remark 31 | /// - Allocate memory block: _ptr == NULL && size > 0 32 | /// - Resize memory block: _ptr != NULL && size > 0 33 | /// - Free memory block: _ptr != NULL && size == 0 34 | /// 35 | /// @param[in] _ptr If _ptr is NULL new block will be allocated. If _ptr is not-NULL, and 36 | /// _size is not 0, memory block will be resized. 37 | /// @param[in] _size If _ptr is set, and _size is 0, memory will be freed. 38 | /// @param[in] _align Alignment. 39 | /// @param[in] _filePath Debug file path info. 40 | /// @param[in] _line Debug file line info. 41 | /// 42 | virtual void* realloc( 43 | void* _ptr 44 | , size_t _size 45 | , size_t _align 46 | , const char* _filePath 47 | , uint32_t _line 48 | ) = 0; 49 | }; 50 | 51 | /// 52 | class DefaultAllocator : public AllocatorI 53 | { 54 | public: 55 | /// 56 | DefaultAllocator(); 57 | 58 | /// 59 | virtual ~DefaultAllocator(); 60 | 61 | /// 62 | virtual void* realloc( 63 | void* _ptr 64 | , size_t _size 65 | , size_t _align 66 | , const char* _filePath 67 | , uint32_t _line 68 | ) override; 69 | }; 70 | 71 | /// Aligns pointer to nearest next aligned address. _align must be power of two. 72 | void* alignPtr( 73 | void* _ptr 74 | , size_t _extra 75 | , size_t _align = 0 76 | ); 77 | 78 | /// Allocate memory. 79 | void* alloc( 80 | AllocatorI* _allocator 81 | , size_t _size 82 | , size_t _align = 0 83 | , const Location& _location = Location::current() 84 | ); 85 | 86 | /// Free memory. 87 | void free( 88 | AllocatorI* _allocator 89 | , void* _ptr 90 | , size_t _align = 0 91 | , const Location& _location = Location::current() 92 | ); 93 | 94 | /// Resize memory block. 95 | void* realloc( 96 | AllocatorI* _allocator 97 | , void* _ptr 98 | , size_t _size 99 | , size_t _align = 0 100 | , const Location& _location = Location::current() 101 | ); 102 | 103 | /// Allocate memory with specific alignment. 104 | void* alignedAlloc( 105 | AllocatorI* _allocator 106 | , size_t _size 107 | , size_t _align 108 | , const Location& _location = Location::current() 109 | ); 110 | 111 | /// Free memory that was allocated with aligned allocator. 112 | void alignedFree( 113 | AllocatorI* _allocator 114 | , void* _ptr 115 | , size_t /*_align*/ 116 | , const Location& _location = Location::current() 117 | ); 118 | 119 | /// Resize memory block that was allocated with aligned allocator. 120 | void* alignedRealloc( 121 | AllocatorI* _allocator 122 | , void* _ptr 123 | , size_t _size 124 | , size_t _align 125 | , const Location& _location = Location::current() 126 | ); 127 | 128 | /// Delete object with specific allocator. 129 | template 130 | void deleteObject( 131 | AllocatorI* _allocator 132 | , ObjectT* _object 133 | , size_t _align = 0 134 | , const Location& _location = Location::current() 135 | ); 136 | 137 | } // namespace bx 138 | 139 | #include "inline/allocator.inl" 140 | 141 | #endif // BX_ALLOCATOR_H_HEADER_GUARD 142 | -------------------------------------------------------------------------------- /include/bx/commandline.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #ifndef BX_COMMANDLINE_H_HEADER_GUARD 7 | #define BX_COMMANDLINE_H_HEADER_GUARD 8 | 9 | #include "string.h" 10 | 11 | namespace bx 12 | { 13 | /// 14 | StringView tokenizeCommandLine(const StringView& _commandLine, char* _buffer, uint32_t& _bufferSize, int32_t& _argc, char* _argv[], int32_t _maxArgvs, char _term = '\0'); 15 | 16 | /// 17 | class CommandLine 18 | { 19 | public: 20 | /// 21 | CommandLine(int32_t _argc, char const* const* _argv); 22 | 23 | /// 24 | const char* findOption(const char* _long, const char* _default) const; 25 | 26 | /// 27 | const char* findOption(const char _short, const char* _long, const char* _default) const; 28 | 29 | /// 30 | const char* findOption(const char* _long, int32_t _numParams = 1) const; 31 | 32 | /// 33 | const char* findOption(const char _short, const char* _long = NULL, int32_t _numParams = 1) const; 34 | 35 | /// 36 | const char* findOption(int32_t _skip, const char _short, const char* _long = NULL, int32_t _numParams = 1) const; 37 | 38 | /// 39 | bool hasArg(const char _short, const char* _long = NULL) const; 40 | 41 | /// 42 | bool hasArg(const char* _long) const; 43 | 44 | /// 45 | bool hasArg(const char*& _value, const char _short, const char* _long = NULL) const; 46 | 47 | /// 48 | bool hasArg(int32_t& _value, const char _short, const char* _long = NULL) const; 49 | 50 | /// 51 | bool hasArg(uint32_t& _value, const char _short, const char* _long = NULL) const; 52 | 53 | /// 54 | bool hasArg(float& _value, const char _short, const char* _long = NULL) const; 55 | 56 | /// 57 | bool hasArg(double& _value, const char _short, const char* _long = NULL) const; 58 | 59 | /// 60 | bool hasArg(bool& _value, const char _short, const char* _long = NULL) const; 61 | 62 | /// 63 | int32_t getNum() const; 64 | 65 | /// 66 | char const* get(int32_t _idx) const; 67 | 68 | private: 69 | /// 70 | const char* find(int32_t _skip, const char _short, const char* _long, int32_t _numParams) const; 71 | 72 | int32_t m_argc; 73 | char const* const* m_argv; 74 | }; 75 | 76 | } // namespace bx 77 | 78 | #endif /// BX_COMMANDLINE_H_HEADER_GUARD 79 | -------------------------------------------------------------------------------- /include/bx/config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #ifndef BX_CONFIG_H_HEADER_GUARD 7 | #define BX_CONFIG_H_HEADER_GUARD 8 | 9 | #ifndef BX_CONFIG_DEBUG 10 | # error "BX_CONFIG_DEBUG must be defined in build script!" 11 | #endif // BX_CONFIG_DEBUG 12 | 13 | #ifndef BX_CONFIG_ALLOCATOR_DEBUG 14 | # define BX_CONFIG_ALLOCATOR_DEBUG BX_CONFIG_DEBUG 15 | #endif // BX_CONFIG_ALLOCATOR_DEBUG 16 | 17 | #ifndef BX_CONFIG_SUPPORTS_THREADING 18 | # define BX_CONFIG_SUPPORTS_THREADING !(0 \ 19 | || BX_PLATFORM_EMSCRIPTEN \ 20 | ) 21 | #endif // BX_CONFIG_SUPPORTS_THREADING 22 | 23 | #endif // BX_CONFIG_H_HEADER_GUARD 24 | -------------------------------------------------------------------------------- /include/bx/constants.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #ifndef BX_CONSTANTS_H_HEADER_GUARD 7 | #define BX_CONSTANTS_H_HEADER_GUARD 8 | 9 | namespace bx 10 | { 11 | /// Used to return successful execution of a program code. 12 | constexpr int32_t kExitSuccess = 0; 13 | 14 | /// Used to return unsuccessful execution of a program code. 15 | constexpr int32_t kExitFailure = 1; 16 | 17 | /// The ratio of a circle's circumference to its diameter, 18 | constexpr float kPi = 3.1415926535897932384626433832795f; 19 | 20 | /// The ratio of a circle's circumference to its radius. Pi multiplied by 2, or Tau. pi*2 21 | constexpr float kPi2 = 6.2831853071795864769252867665590f; 22 | 23 | /// The reciprocal of kPi. 1/kPi 24 | constexpr float kInvPi = 1.0f/kPi; 25 | 26 | /// The reciprocal of kPi2. 1/kPi2 27 | constexpr float kInvPi2 = 1.0f/kPi2; 28 | 29 | /// Pi divided by two. pi/2 30 | constexpr float kPiHalf = 1.5707963267948966192313216916398f; 31 | 32 | /// Pi divided by four. pi/4 33 | constexpr float kPiQuarter = 0.7853981633974483096156608458199f; 34 | 35 | /// The square root of two. sqrt(2) 36 | constexpr float kSqrt2 = 1.4142135623730950488016887242097f; 37 | 38 | /// ln(10) 39 | constexpr float kLogNat10 = 2.3025850929940456840179914546844f; 40 | 41 | /// The logarithm of the e to base 2. ln(kE) / ln(2) 42 | constexpr float kInvLogNat2 = 1.4426950408889634073599246810019f; 43 | 44 | /// The natural logarithm of the 2. ln(2) 45 | constexpr float kLogNat2 = 0.6931471805599453094172321214582f; 46 | 47 | /// The base of natural logarithms. e(1) 48 | constexpr float kE = 2.7182818284590452353602874713527f; 49 | 50 | /// 51 | constexpr float kNearZero = 1.0f/float(1 << 28); 52 | 53 | /// 54 | constexpr uint8_t kHalfSignNumBits = 1; 55 | constexpr uint8_t kHalfSignBitShift = 15; 56 | constexpr uint16_t kHalfSignMask = UINT16_C(0x8000); 57 | constexpr uint8_t kHalfExponentNumBits = 5; 58 | constexpr uint8_t kHalfExponentBitShift = 10; 59 | constexpr uint16_t kHalfExponentMask = UINT16_C(0x7c00); 60 | constexpr uint32_t kHalfExponentBias = 15; 61 | constexpr uint8_t kHalfMantissaNumBits = 10; 62 | constexpr uint8_t kHalfMantissaBitShift = 0; 63 | constexpr uint16_t kHalfMantissaMask = UINT16_C(0x03ff); 64 | 65 | /// 66 | constexpr uint8_t kFloatSignNumBits = 1; 67 | constexpr uint8_t kFloatSignBitShift = 31; 68 | constexpr uint32_t kFloatSignMask = UINT32_C(0x80000000); 69 | constexpr uint8_t kFloatExponentNumBits = 8; 70 | constexpr uint8_t kFloatExponentBitShift = 23; 71 | constexpr uint32_t kFloatExponentMask = UINT32_C(0x7f800000); 72 | constexpr uint32_t kFloatExponentBias = 127; 73 | constexpr uint8_t kFloatMantissaNumBits = 23; 74 | constexpr uint8_t kFloatMantissaBitShift = 0; 75 | constexpr uint32_t kFloatMantissaMask = UINT32_C(0x007fffff); 76 | 77 | /// Smallest normalized positive floating-point number. 78 | constexpr float kFloatSmallest = 1.175494351e-38f; 79 | 80 | /// Maximum representable floating-point number. 81 | constexpr float kFloatLargest = 3.402823466e+38f; 82 | 83 | /// Floating-point infinity. 84 | // constexpr float kFloatInfinity; 85 | 86 | /// 87 | constexpr uint8_t kDoubleSignNumBits = 1; 88 | constexpr uint8_t kDoubleSignBitShift = 63; 89 | constexpr uint64_t kDoubleSignMask = UINT64_C(0x8000000000000000); 90 | constexpr uint8_t kDoubleExponentNumBits = 11; 91 | constexpr uint8_t kDoubleExponentShift = 52; 92 | constexpr uint64_t kDoubleExponentMask = UINT64_C(0x7ff0000000000000); 93 | constexpr uint32_t kDoubleExponentBias = 1023; 94 | constexpr uint8_t kDoubleMantissaNumBits = 52; 95 | constexpr uint8_t kDoubleMantissaShift = 0; 96 | constexpr uint64_t kDoubleMantissaMask = UINT64_C(0x000fffffffffffff); 97 | 98 | /// Smallest normalized positive double-precision floating-point number. 99 | constexpr double kDoubleSmallest = 2.2250738585072014e-308; 100 | 101 | /// Largest representable double-precision floating-point number. 102 | constexpr double kDoubleLargest = 1.7976931348623158e+308; 103 | 104 | // Double-precision floating-point infinity. 105 | // constexpr double kDoubleInfinity; 106 | 107 | } // namespace bx 108 | 109 | #endif // BX_CONSTANTS_H_HEADER_GUARD 110 | -------------------------------------------------------------------------------- /include/bx/cpu.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #ifndef BX_CPU_H_HEADER_GUARD 7 | #define BX_CPU_H_HEADER_GUARD 8 | 9 | #include "bx.h" 10 | 11 | namespace bx 12 | { 13 | /// 14 | void readBarrier(); 15 | 16 | /// 17 | void writeBarrier(); 18 | 19 | /// 20 | void readWriteBarrier(); 21 | 22 | /// 23 | void memoryBarrier(); 24 | 25 | /// 26 | template 27 | Ty atomicFetchAndAdd(volatile Ty* _ptr, Ty _value); 28 | 29 | /// 30 | template 31 | Ty atomicAddAndFetch(volatile Ty* _ptr, Ty _value); 32 | 33 | /// 34 | template 35 | Ty atomicFetchAndSub(volatile Ty* _ptr, Ty _value); 36 | 37 | /// 38 | template 39 | Ty atomicSubAndFetch(volatile Ty* _ptr, Ty _value); 40 | 41 | /// 42 | template 43 | Ty atomicCompareAndSwap(volatile Ty* _ptr, Ty _old, Ty _new); 44 | 45 | /// 46 | template 47 | Ty atomicFetchTestAndAdd(volatile Ty* _ptr, Ty _test, Ty _value); 48 | 49 | /// 50 | template 51 | Ty atomicFetchTestAndSub(volatile Ty* _ptr, Ty _test, Ty _value); 52 | 53 | /// 54 | template 55 | Ty atomicFetchAndAddsat(volatile Ty* _ptr, Ty _value, Ty _max); 56 | 57 | /// 58 | template 59 | Ty atomicFetchAndSubsat(volatile Ty* _ptr, Ty _value, Ty _min); 60 | 61 | /// 62 | void* atomicExchangePtr(void** _ptr, void* _new); 63 | 64 | } // namespace bx 65 | 66 | #include "inline/cpu.inl" 67 | 68 | #endif // BX_CPU_H_HEADER_GUARD 69 | -------------------------------------------------------------------------------- /include/bx/debug.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #ifndef BX_DEBUG_H_HEADER_GUARD 7 | #define BX_DEBUG_H_HEADER_GUARD 8 | 9 | #include // uint32_t 10 | #include // va_list 11 | 12 | namespace bx 13 | { 14 | class Error; 15 | class StringView; 16 | struct WriterI; 17 | 18 | /// Break in debugger. 19 | /// 20 | void debugBreak(); 21 | 22 | /// Write string to debug output. 23 | /// 24 | /// @param[in] _str Zero terminated string to write. 25 | /// 26 | void debugOutput(const char* _str); 27 | 28 | /// Write string to debug output. 29 | /// 30 | /// @param[in] _str StringView to write. 31 | /// 32 | void debugOutput(const StringView& _str); 33 | 34 | /// Write formatted string to debug output. 35 | /// 36 | void debugPrintfVargs(const char* _format, va_list _argList); 37 | 38 | /// Write formatted string to debug output. 39 | /// 40 | void debugPrintf(const char* _format, ...); 41 | 42 | /// Write hex data into debug output. 43 | /// 44 | void debugPrintfData(const void* _data, uint32_t _size, const char* _format, ...); 45 | 46 | /// Return debug output writer. 47 | /// 48 | /// @returns Debug output writer. 49 | /// 50 | WriterI* getDebugOut(); 51 | 52 | /// Capture current callstack. 53 | /// 54 | /// @param[in] _skip Skip top N stack frames. 55 | /// @param[in] _max Maximum frame to capture. 56 | /// @param[out] _outStack Stack frames array. Must be at least `_max` elements. 57 | /// 58 | /// @returns Number of stack frames captured. 59 | /// 60 | uint32_t getCallStack(uint32_t _skip, uint32_t _max, uintptr_t* _outStack); 61 | 62 | /// Write callstack. 63 | /// 64 | /// @param[in] _writer Writer. 65 | /// @param[in] _stack Callstack. 66 | /// @param[in] _num Number of stack addresses in `_stack` array. 67 | /// @param[out] _err Error. 68 | /// 69 | /// @returns Number of bytes writen to `_writer`. 70 | /// 71 | int32_t writeCallstack(WriterI* _writer, uintptr_t* _stack, uint32_t _num, Error* _err); 72 | 73 | /// Capture call stack, and write it to debug output. 74 | /// 75 | /// @param[in] _skip Skip top N stack frames. 76 | /// 77 | void debugOutputCallstack(uint32_t _skip); 78 | 79 | } // namespace bx 80 | 81 | #endif // BX_DEBUG_H_HEADER_GUARD 82 | -------------------------------------------------------------------------------- /include/bx/endian.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #ifndef BX_ENDIAN_H_HEADER_GUARD 7 | #define BX_ENDIAN_H_HEADER_GUARD 8 | 9 | #include "bx.h" 10 | 11 | namespace bx 12 | { 13 | /// 14 | int16_t endianSwap(int16_t _in); 15 | 16 | /// 17 | uint16_t endianSwap(uint16_t _in); 18 | 19 | /// 20 | int32_t endianSwap(int32_t _in); 21 | 22 | /// 23 | uint32_t endianSwap(uint32_t _in); 24 | 25 | /// 26 | int64_t endianSwap(int64_t _in); 27 | 28 | /// 29 | uint64_t endianSwap(uint64_t _in); 30 | 31 | /// Input argument is encoded as little endian, convert it if necessary 32 | /// depending on host CPU endianness. 33 | template 34 | Ty toLittleEndian(const Ty _in); 35 | 36 | /// Input argument is encoded as big endian, convert it if necessary 37 | /// depending on host CPU endianness. 38 | template 39 | Ty toBigEndian(const Ty _in); 40 | 41 | /// If _littleEndian is true, converts input argument to from little endian 42 | /// to host CPU endiness. 43 | template 44 | Ty toHostEndian(const Ty _in, bool _fromLittleEndian); 45 | 46 | } // namespace bx 47 | 48 | #include "inline/endian.inl" 49 | 50 | #endif // BX_ENDIAN_H_HEADER_GUARD 51 | -------------------------------------------------------------------------------- /include/bx/error.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #ifndef BX_ERROR_H_HEADER_GUARD 7 | #define BX_ERROR_H_HEADER_GUARD 8 | 9 | #include "string.h" 10 | 11 | #define BX_ERROR_SET(_ptr, _result, _msg) \ 12 | BX_MACRO_BLOCK_BEGIN \ 13 | (_ptr)->setError(_result, "" _msg); \ 14 | BX_MACRO_BLOCK_END 15 | 16 | #define BX_ERROR_USE_TEMP_WHEN_NULL(_ptr) \ 17 | const bx::Error tmpError; /* It should not be used directly! */ \ 18 | _ptr = NULL == _ptr ? const_cast(&tmpError) : _ptr 19 | 20 | #define BX_ERROR_SCOPE(_ptr, ...) \ 21 | BX_ERROR_USE_TEMP_WHEN_NULL(_ptr); \ 22 | bx::ErrorScope bxErrorScope(const_cast(&tmpError), "" __VA_ARGS__) 23 | 24 | #define BX_ERROR_RESULT(_err, _code) \ 25 | static_assert(_code != 0, "ErrorCode 0 is reserved!"); \ 26 | static constexpr bx::ErrorResult _err = { _code } 27 | 28 | namespace bx 29 | { 30 | /// 31 | struct ErrorResult 32 | { 33 | uint32_t code; 34 | }; 35 | 36 | /// 37 | class Error 38 | { 39 | BX_CLASS(Error 40 | , NO_COPY 41 | ); 42 | 43 | public: 44 | /// 45 | Error(); 46 | 47 | /// 48 | void reset(); 49 | 50 | /// 51 | void setError(ErrorResult _errorResult, const StringLiteral& _msg, const Location& _location = Location::current() ); 52 | 53 | /// 54 | bool isOk() const; 55 | 56 | /// 57 | ErrorResult get() const; 58 | 59 | /// 60 | const StringLiteral& getMessage() const; 61 | 62 | /// 63 | const Location& getLocation() const; 64 | 65 | /// 66 | bool operator==(const ErrorResult& _rhs) const; 67 | 68 | /// 69 | bool operator!=(const ErrorResult& _rhs) const; 70 | 71 | private: 72 | Location m_location; 73 | StringLiteral m_msg; 74 | uint32_t m_code; 75 | }; 76 | 77 | /// Do nothing even if error is set. 78 | class ErrorIgnore final : public Error 79 | { 80 | public: 81 | /// 82 | operator Error*(); 83 | }; 84 | 85 | /// In debug build assert if error is set. 86 | class ErrorAssert final : public Error 87 | { 88 | public: 89 | /// 90 | ~ErrorAssert(); 91 | 92 | /// 93 | operator Error*(); 94 | }; 95 | 96 | /// Exit application if error is set. 97 | class ErrorFatal final : public Error 98 | { 99 | public: 100 | /// 101 | ~ErrorFatal(); 102 | 103 | /// 104 | operator Error*(); 105 | }; 106 | 107 | /// 108 | class ErrorScope 109 | { 110 | BX_CLASS(ErrorScope 111 | , NO_DEFAULT_CTOR 112 | , NO_COPY 113 | ); 114 | 115 | public: 116 | /// 117 | ErrorScope(Error* _err, const StringLiteral& _name); 118 | 119 | /// 120 | ~ErrorScope(); 121 | 122 | /// 123 | const StringLiteral& getName() const; 124 | 125 | private: 126 | Error* m_err; 127 | const StringLiteral m_name; 128 | }; 129 | 130 | } // namespace bx 131 | 132 | #include "inline/error.inl" 133 | 134 | #endif // BX_ERROR_H_HEADER_GUARD 135 | -------------------------------------------------------------------------------- /include/bx/file.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #ifndef BX_FILE_H_HEADER_GUARD 7 | #define BX_FILE_H_HEADER_GUARD 8 | 9 | #include "filepath.h" 10 | #include "readerwriter.h" 11 | 12 | namespace bx 13 | { 14 | /// Returns standard input reader. 15 | ReaderI* getStdIn(); 16 | 17 | /// Returns standard output writer. 18 | WriterI* getStdOut(); 19 | 20 | /// Returns standard error writer. 21 | WriterI* getStdErr(); 22 | 23 | /// Returns null output writer. 24 | WriterI* getNullOut(); 25 | 26 | /// File reader. 27 | class FileReader : public FileReaderI 28 | { 29 | public: 30 | /// 31 | FileReader(); 32 | 33 | /// 34 | virtual ~FileReader(); 35 | 36 | /// 37 | virtual bool open(const FilePath& _filePath, Error* _err) override; 38 | 39 | /// 40 | virtual void close() override; 41 | 42 | /// 43 | virtual int64_t seek(int64_t _offset = 0, Whence::Enum _whence = Whence::Current) override; 44 | 45 | /// 46 | virtual int32_t read(void* _data, int32_t _size, Error* _err) override; 47 | 48 | private: 49 | BX_ALIGN_DECL(16, uint8_t) m_internal[64]; 50 | }; 51 | 52 | /// File writer. 53 | class FileWriter : public FileWriterI 54 | { 55 | public: 56 | /// 57 | FileWriter(); 58 | 59 | /// 60 | virtual ~FileWriter(); 61 | 62 | /// 63 | virtual bool open(const FilePath& _filePath, bool _append, Error* _err) override; 64 | 65 | /// 66 | virtual void close() override; 67 | 68 | /// 69 | virtual int64_t seek(int64_t _offset = 0, Whence::Enum _whence = Whence::Current) override; 70 | 71 | /// 72 | virtual int32_t write(const void* _data, int32_t _size, Error* _err) override; 73 | 74 | private: 75 | BX_ALIGN_DECL(16, uint8_t) m_internal[64]; 76 | }; 77 | 78 | /// File type. 79 | struct FileType 80 | { 81 | /// File types: 82 | enum Enum 83 | { 84 | File, //!< File. 85 | Dir, //!< Directory. 86 | 87 | Count 88 | }; 89 | }; 90 | 91 | /// File info. 92 | struct FileInfo 93 | { 94 | FilePath filePath; //!< File path. 95 | uint64_t size; //!< File size. 96 | FileType::Enum type; //!< File type. 97 | }; 98 | 99 | /// Directory reader. 100 | class DirectoryReader : public ReaderOpenI, public CloserI, public ReaderI 101 | { 102 | public: 103 | /// 104 | DirectoryReader(); 105 | 106 | /// 107 | virtual ~DirectoryReader(); 108 | 109 | /// 110 | virtual bool open(const FilePath& _filePath, Error* _err) override; 111 | 112 | /// 113 | virtual void close() override; 114 | 115 | /// 116 | virtual int32_t read(void* _data, int32_t _size, Error* _err) override; 117 | 118 | private: 119 | BX_ALIGN_DECL(16, uint8_t) m_internal[sizeof(FilePath)+sizeof(FileInfo)+16]; 120 | }; 121 | 122 | /// FIle stat. 123 | bool stat(FileInfo& _outFileInfo, const FilePath& _filePath); 124 | 125 | /// Creates a directory named `_filePath`. 126 | /// 127 | bool make(const FilePath& _filePath, Error* _err = ErrorIgnore{}); 128 | 129 | /// Creates a directory named `_filePath` along with all necessary parents. 130 | /// 131 | bool makeAll(const FilePath& _filePath, Error* _err = ErrorIgnore{}); 132 | 133 | /// Removes file or directory. 134 | /// 135 | bool remove(const FilePath& _filePath, Error* _err = ErrorIgnore{}); 136 | 137 | /// Removes file or directory recursively. 138 | /// 139 | bool removeAll(const FilePath& _filePath, Error* _err = ErrorIgnore{}); 140 | 141 | } // namespace bx 142 | 143 | #endif // BX_FILE_H_HEADER_GUARD 144 | -------------------------------------------------------------------------------- /include/bx/filepath.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #ifndef BX_FILEPATH_H_HEADER_GUARD 7 | #define BX_FILEPATH_H_HEADER_GUARD 8 | 9 | #include "error.h" 10 | #include "string.h" 11 | 12 | namespace bx 13 | { 14 | BX_ERROR_RESULT(kErrorAccess, BX_MAKEFOURCC('b', 'x', 1, 1) ); 15 | BX_ERROR_RESULT(kErrorNotDirectory, BX_MAKEFOURCC('b', 'x', 1, 2) ); 16 | 17 | constexpr int32_t kMaxFilePath = 1024; 18 | 19 | /// Special predefined OS directories. 20 | /// 21 | struct Dir 22 | { 23 | /// Special OS directories: 24 | enum Enum 25 | { 26 | Current, //!< Current directory. 27 | Executable, //!< Executable file path. 28 | Home, //!< User's home directory. 29 | Temp, //!< Temporary directory. 30 | 31 | Count 32 | }; 33 | }; 34 | 35 | /// FilePath parser and helper. 36 | /// 37 | /// /abv/gd/555/333/pod.mac 38 | /// ppppppppppppppppbbbeeee 39 | /// ^ ^ ^ 40 | /// +-path base-+ +-ext 41 | /// ^^^^^^^ 42 | /// +-filename 43 | /// 44 | class FilePath 45 | { 46 | public: 47 | /// Default constructor, creates empty file path. 48 | /// 49 | FilePath(); 50 | 51 | /// Construct file path from special OS directory. 52 | /// 53 | FilePath(Dir::Enum _dir); 54 | 55 | /// Construct file path from C string. 56 | /// 57 | FilePath(const char* _str); 58 | 59 | /// Construct file path from string. 60 | /// 61 | FilePath(const StringView& _str); 62 | 63 | /// Assign file path from string. 64 | /// 65 | FilePath& operator=(const StringView& _rhs); 66 | 67 | /// Clear file path. 68 | /// 69 | void clear(); 70 | 71 | /// Set file path from special OS directory. 72 | /// 73 | void set(Dir::Enum _dir); 74 | 75 | /// Set file path. 76 | /// 77 | void set(const StringView& _str); 78 | 79 | /// Join directory to file path. 80 | /// 81 | void join(const StringView& _str); 82 | 83 | /// Implicitly converts FilePath to StringView. 84 | /// 85 | operator StringView() const; 86 | 87 | /// Returns zero-terminated C string pointer to file path. 88 | /// 89 | const char* getCPtr() const; 90 | 91 | /// If path is `/abv/gd/555/333/pod.mac` returns `/abv/gd/555/333/`. 92 | /// 93 | StringView getPath() const; 94 | 95 | /// If path is `/abv/gd/555/333/pod.mac` returns `pod.mac`. 96 | /// 97 | StringView getFileName() const; 98 | 99 | /// If path is `/abv/gd/555/333/pod.mac` returns `pod`. 100 | /// 101 | StringView getBaseName() const; 102 | 103 | /// If path is `/abv/gd/555/333/pod.mac` returns `.mac`. 104 | /// 105 | StringView getExt() const; 106 | 107 | /// Returns true if file path is absolute. 108 | /// 109 | bool isAbsolute() const; 110 | 111 | /// Returns true if file path is empty. 112 | /// 113 | bool isEmpty() const; 114 | 115 | private: 116 | char m_filePath[kMaxFilePath]; 117 | }; 118 | 119 | } // namespace bx 120 | 121 | #endif // BX_FILEPATH_H_HEADER_GUARD 122 | -------------------------------------------------------------------------------- /include/bx/float4x4_t.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #ifndef BX_FLOAT4X4_H_HEADER_GUARD 7 | #define BX_FLOAT4X4_H_HEADER_GUARD 8 | 9 | #include "simd_t.h" 10 | 11 | namespace bx 12 | { 13 | /// 4x4 matrix. 14 | BX_ALIGN_DECL_16(struct) float4x4_t 15 | { 16 | simd128_t col[4]; 17 | }; 18 | 19 | /// Multiplies vector `_a` with matrix `_b` ignoring W component of vector `_a`. 20 | simd128_t simd_mul_xyz1(simd128_t _a, const float4x4_t* _b); 21 | 22 | /// Multiplies vector `_a` with matrix `_b`. 23 | simd128_t simd_mul(simd128_t _a, const float4x4_t* _b); 24 | 25 | /// Multiplies two matrices. 26 | void float4x4_mul(float4x4_t* _result, const float4x4_t* _a, const float4x4_t* _b); 27 | 28 | /// Multiplies two 3x4 affine matrices (i.e. "model" or "world" matrices). 29 | /// This function is a micro-optimized version of float4x4_mul() in the case 30 | /// when the last row of the both input matrices are (0, 0, 0, 1). 31 | void model4x4_mul(float4x4_t* _result, const float4x4_t* _a, const float4x4_t* _b); 32 | 33 | /// Multiplies a 3x4 affine matrix with a general 4x4 matrix. 34 | /// This function is a micro-optimized version of float4x4_mul() in the case 35 | /// when the last row of the _model input matrix is (0, 0, 0, 1). 36 | void model4x4_mul_viewproj4x4(float4x4_t* _result, const float4x4_t* _model, const float4x4_t* _viewProj); 37 | 38 | /// Transpose of matrix. 39 | void float4x4_transpose(float4x4_t* _result, const float4x4_t* _mtx); 40 | 41 | /// Inverse of matrix. 42 | void float4x4_inverse(float4x4_t* _result, const float4x4_t* _a); 43 | 44 | } // namespace bx 45 | 46 | #include "inline/float4x4_t.inl" 47 | 48 | #endif // BX_FLOAT4X4_H_HEADER_GUARD 49 | -------------------------------------------------------------------------------- /include/bx/hash.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #ifndef BX_HASH_H_HEADER_GUARD 7 | #define BX_HASH_H_HEADER_GUARD 8 | 9 | #include "allocator.h" // isAligned 10 | #include "string.h" // StringView 11 | 12 | namespace bx 13 | { 14 | /// 32-bit Adler checksum hash. 15 | class HashAdler32 16 | { 17 | public: 18 | /// 19 | void begin(); 20 | 21 | /// 22 | void add(const void* _data, int32_t _len); 23 | 24 | /// 25 | void add(const char* _data); 26 | 27 | /// 28 | void add(const StringView& _data); 29 | 30 | /// 31 | template 32 | void add(const Ty& _data); 33 | 34 | /// 35 | uint32_t end(); 36 | 37 | private: 38 | uint32_t m_a; 39 | uint32_t m_b; 40 | }; 41 | 42 | /// 32-bit cyclic redundancy checksum hash. 43 | class HashCrc32 44 | { 45 | public: 46 | enum Enum 47 | { 48 | Ieee, //!< 0xedb88320 49 | Castagnoli, //!< 0x82f63b78 50 | Koopman, //!< 0xeb31d82e 51 | 52 | Count 53 | }; 54 | 55 | /// 56 | void begin(Enum _type = Ieee); 57 | 58 | /// 59 | void add(const void* _data, int32_t _len); 60 | 61 | /// 62 | void add(const char* _data); 63 | 64 | /// 65 | void add(const StringView& _data); 66 | 67 | /// 68 | template 69 | void add(const Ty& _data); 70 | 71 | /// 72 | uint32_t end(); 73 | 74 | private: 75 | const uint32_t* m_table; 76 | uint32_t m_hash; 77 | }; 78 | 79 | /// 32-bit non-cryptographic multiply and rotate hash. 80 | class HashMurmur2A 81 | { 82 | public: 83 | /// 84 | void begin(uint32_t _seed = 0); 85 | 86 | /// 87 | void add(const void* _data, int32_t _len); 88 | 89 | /// 90 | void add(const char* _data); 91 | 92 | /// 93 | void add(const StringView& _data); 94 | 95 | /// 96 | template 97 | void add(const Ty& _data); 98 | 99 | /// 100 | uint32_t end(); 101 | 102 | private: 103 | uint32_t m_hash; 104 | uint32_t m_size; 105 | uint8_t m_tail[4]; 106 | uint8_t m_count; 107 | }; 108 | 109 | /// 32-bit non-cryptographic multiply and rotate hash. 110 | class HashMurmur3 111 | { 112 | public: 113 | /// 114 | void begin(uint32_t _seed = 0); 115 | 116 | /// 117 | void add(const void* _data, int32_t _len); 118 | 119 | /// 120 | void add(const char* _data); 121 | 122 | /// 123 | void add(const StringView& _data); 124 | 125 | /// 126 | template 127 | void add(const Ty& _data); 128 | 129 | /// 130 | uint32_t end(); 131 | 132 | private: 133 | uint32_t m_hash; 134 | uint32_t m_size; 135 | uint8_t m_tail[4]; 136 | uint8_t m_count; 137 | }; 138 | 139 | /// 140 | template 141 | uint32_t hash(const void* _data, uint32_t _size); 142 | 143 | /// 144 | template 145 | uint32_t hash(const char* _data); 146 | 147 | /// 148 | template 149 | uint32_t hash(const StringView& _data); 150 | 151 | /// 152 | template 153 | uint32_t hash(const Ty& _data); 154 | 155 | } // namespace bx 156 | 157 | #include "inline/hash.inl" 158 | 159 | #endif // BX_HASH_H_HEADER_GUARD 160 | -------------------------------------------------------------------------------- /include/bx/inline/allocator.inl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #ifndef BX_ALLOCATOR_H_HEADER_GUARD 7 | # error "Must be included from bx/allocator.h" 8 | #endif // BX_ALLOCATOR_H_HEADER_GUARD 9 | 10 | inline void* operator new(size_t, bx::PlacementNewTag, void* _ptr) 11 | { 12 | return _ptr; 13 | } 14 | 15 | inline void operator delete(void*, bx::PlacementNewTag, void*) throw() 16 | { 17 | } 18 | 19 | namespace bx 20 | { 21 | inline AllocatorI::~AllocatorI() 22 | { 23 | } 24 | 25 | inline void* alignPtr(void* _ptr, size_t _extra, size_t _align) 26 | { 27 | const uintptr_t addr = bitCast(_ptr); 28 | const uintptr_t unaligned = addr + _extra; // space for header 29 | const uintptr_t aligned = alignUp(unaligned, _align); 30 | 31 | return bitCast(aligned); 32 | } 33 | 34 | inline void* alloc(AllocatorI* _allocator, size_t _size, size_t _align, const Location& _location) 35 | { 36 | return _allocator->realloc(NULL, _size, _align, _location.filePath, _location.line); 37 | } 38 | 39 | inline void free(AllocatorI* _allocator, void* _ptr, size_t _align, const Location& _location) 40 | { 41 | _allocator->realloc(_ptr, 0, _align, _location.filePath, _location.line); 42 | } 43 | 44 | inline void* realloc(AllocatorI* _allocator, void* _ptr, size_t _size, size_t _align, const Location& _location) 45 | { 46 | return _allocator->realloc(_ptr, _size, _align, _location.filePath, _location.line); 47 | } 48 | 49 | inline void* alignedAlloc(AllocatorI* _allocator, size_t _size, size_t _align, const Location& _location) 50 | { 51 | const size_t align = max(_align, sizeof(uint32_t) ); 52 | const size_t total = _size + align; 53 | uint8_t* ptr = (uint8_t*)alloc(_allocator, total, 0, _location); 54 | uint8_t* aligned = (uint8_t*)alignPtr(ptr, sizeof(uint32_t), align); 55 | uint32_t* header = (uint32_t*)aligned - 1; 56 | *header = uint32_t(aligned - ptr); 57 | return aligned; 58 | } 59 | 60 | inline void alignedFree(AllocatorI* _allocator, void* _ptr, size_t _align, const Location& _location) 61 | { 62 | BX_UNUSED(_align); 63 | uint8_t* aligned = (uint8_t*)_ptr; 64 | uint32_t* header = (uint32_t*)aligned - 1; 65 | uint8_t* ptr = aligned - *header; 66 | free(_allocator, ptr, 0, _location); 67 | } 68 | 69 | inline void* alignedRealloc(AllocatorI* _allocator, void* _ptr, size_t _size, size_t _align, const Location& _location) 70 | { 71 | if (NULL == _ptr) 72 | { 73 | return alignedAlloc(_allocator, _size, _align, _location); 74 | } 75 | 76 | uint8_t* aligned = (uint8_t*)_ptr; 77 | uint32_t offset = *( (uint32_t*)aligned - 1); 78 | uint8_t* ptr = aligned - offset; 79 | 80 | const size_t align = max(_align, sizeof(uint32_t) );; 81 | const size_t total = _size + align; 82 | ptr = (uint8_t*)realloc(_allocator, ptr, total, 0, _location); 83 | uint8_t* newAligned = (uint8_t*)alignPtr(ptr, sizeof(uint32_t), align); 84 | 85 | if (newAligned == aligned) 86 | { 87 | return aligned; 88 | } 89 | 90 | aligned = ptr + offset; 91 | memMove(newAligned, aligned, _size); 92 | uint32_t* header = (uint32_t*)newAligned - 1; 93 | *header = uint32_t(newAligned - ptr); 94 | return newAligned; 95 | } 96 | 97 | template 98 | inline void deleteObject(AllocatorI* _allocator, ObjectT* _object, size_t _align, const Location& _location) 99 | { 100 | if (NULL != _object) 101 | { 102 | _object->~ObjectT(); 103 | free(_allocator, _object, _align, _location); 104 | } 105 | } 106 | 107 | } // namespace bx 108 | -------------------------------------------------------------------------------- /include/bx/inline/bx.inl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #ifndef BX_H_HEADER_GUARD 7 | # error "Must be included from bx/bx.h!" 8 | #endif // BX_H_HEADER_GUARD 9 | 10 | namespace bx 11 | { 12 | // Reference(S): 13 | // - https://web.archive.org/web/20181115035420/http://cnicholson.net/2011/01/stupid-c-tricks-a-better-sizeof_array/ 14 | // 15 | template 16 | char (&CountOfRequireArrayArgumentT(const Ty (&)[NumT]) )[NumT]; 17 | 18 | template 19 | struct isEnabled 20 | { 21 | // Template for avoiding MSVC: C4127: conditional expression is constant 22 | static constexpr bool value = B; 23 | }; 24 | 25 | inline constexpr bool ignoreC4127(bool _x) 26 | { 27 | return _x; 28 | } 29 | 30 | template 31 | inline Ty* addressOf(Ty& _a) 32 | { 33 | return reinterpret_cast( 34 | &const_cast( 35 | reinterpret_cast(_a) 36 | ) 37 | ); 38 | } 39 | 40 | template 41 | inline const Ty* addressOf(const Ty& _a) 42 | { 43 | return reinterpret_cast( 44 | &const_cast( 45 | reinterpret_cast(_a) 46 | ) 47 | ); 48 | } 49 | 50 | template 51 | inline Ty* addressOf(void* _ptr, ptrdiff_t _offsetInBytes) 52 | { 53 | return (Ty*)( (uint8_t*)_ptr + _offsetInBytes); 54 | } 55 | 56 | template 57 | inline const Ty* addressOf(const void* _ptr, ptrdiff_t _offsetInBytes) 58 | { 59 | return (const Ty*)( (const uint8_t*)_ptr + _offsetInBytes); 60 | } 61 | 62 | template 63 | inline void swap(Ty& _a, Ty& _b) 64 | { 65 | Ty tmp = move(_a); _a = move(_b); _b = move(tmp); 66 | } 67 | 68 | template 69 | struct LimitsT 70 | { 71 | static constexpr Ty max = ( ( (Ty(1) << ( (sizeof(Ty) * 8) - 2) ) - Ty(1) ) << 1) | Ty(1); 72 | static constexpr Ty min = -max - Ty(1); 73 | }; 74 | 75 | template 76 | struct LimitsT 77 | { 78 | static constexpr Ty min = 0; 79 | static constexpr Ty max = Ty(-1); 80 | }; 81 | 82 | template<> 83 | struct LimitsT 84 | { 85 | static constexpr float min = -kFloatLargest; 86 | static constexpr float max = kFloatLargest; 87 | }; 88 | 89 | template<> 90 | struct LimitsT 91 | { 92 | static constexpr double min = -kDoubleLargest; 93 | static constexpr double max = kDoubleLargest; 94 | }; 95 | 96 | template 97 | inline constexpr Ty max() 98 | { 99 | return LimitsT::max; 100 | } 101 | 102 | template 103 | inline constexpr Ty min() 104 | { 105 | return LimitsT::min; 106 | } 107 | 108 | template 109 | inline constexpr Ty min(const Ty& _a, const TypeIdentityType& _b) 110 | { 111 | return _a < _b ? _a : _b; 112 | } 113 | 114 | template 115 | inline constexpr Ty max(const Ty& _a, const TypeIdentityType& _b) 116 | { 117 | return _a > _b ? _a : _b; 118 | } 119 | 120 | template 121 | inline constexpr Ty min(const Ty& _a, const TypeIdentityType& _b, const Args&... _args) 122 | { 123 | return min(min(_a, _b), _args...); 124 | } 125 | 126 | template 127 | inline constexpr Ty max(const Ty& _a, const TypeIdentityType& _b, const Args&... _args) 128 | { 129 | return max(max(_a, _b), _args...); 130 | } 131 | 132 | template 133 | inline constexpr Ty mid(const Ty& _a, const TypeIdentityType& _b, const Args&... _args) 134 | { 135 | return max(min(_a, _b), min(max(_a, _b), _args...) ); 136 | } 137 | 138 | template 139 | inline constexpr Ty clamp(const Ty& _a, const TypeIdentityType& _min, const TypeIdentityType& _max) 140 | { 141 | return max(min(_a, _max), _min); 142 | } 143 | 144 | template 145 | inline constexpr bool isPowerOf2(Ty _a) 146 | { 147 | return _a && !(_a & (_a - 1) ); 148 | } 149 | 150 | constexpr bool isConstantEvaluated() 151 | { 152 | return __builtin_is_constant_evaluated(); 153 | } 154 | 155 | template 156 | inline constexpr Ty bitCast(const FromT& _from) 157 | { 158 | static_assert(sizeof(Ty) == sizeof(FromT) 159 | , "bx::bitCast failed! Ty and FromT must be the same size." 160 | ); 161 | static_assert(isTriviallyCopyable() 162 | , "bx::bitCast failed! FromT must be trivially copyable." 163 | ); 164 | static_assert(isTriviallyCopyable() 165 | , "bx::bitCast failed! Ty must be trivially copyable." 166 | ); 167 | static_assert(isTriviallyConstructible() 168 | , "bx::bitCast failed! Ty must be trivially constructible." 169 | ); 170 | 171 | return __builtin_bit_cast(Ty, _from); 172 | } 173 | 174 | template 175 | inline Ty narrowCast(const FromT& _from, Location _location) 176 | { 177 | Ty to = static_cast(_from); 178 | BX_ASSERT_LOC(_location, static_cast(to) == _from 179 | , "bx::narrowCast failed! Value is truncated!" 180 | ); 181 | return to; 182 | } 183 | 184 | constexpr float kFloatInfinity = bitCast(kFloatExponentMask); 185 | constexpr double kDoubleInfinity = bitCast(kDoubleExponentMask); 186 | 187 | } // namespace bx 188 | -------------------------------------------------------------------------------- /include/bx/inline/endian.inl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #ifndef BX_ENDIAN_H_HEADER_GUARD 7 | # error "Must be included from bx/endian.h!" 8 | #endif // BX_ENDIAN_H_HEADER_GUARD 9 | 10 | namespace bx 11 | { 12 | inline int16_t endianSwap(int16_t _in) 13 | { 14 | return (int16_t)endianSwap( (uint16_t)_in); 15 | } 16 | 17 | inline uint16_t endianSwap(uint16_t _in) 18 | { 19 | return (_in>>8) | (_in<<8); 20 | } 21 | 22 | inline int32_t endianSwap(int32_t _in) 23 | { 24 | return (int32_t)endianSwap( (uint32_t)_in); 25 | } 26 | 27 | inline uint32_t endianSwap(uint32_t _in) 28 | { 29 | return ( _in >>24) | ( _in <<24) 30 | | ( (_in&0x00ff0000)>> 8) | ( (_in&0x0000ff00)<< 8) 31 | ; 32 | } 33 | 34 | inline int64_t endianSwap(int64_t _in) 35 | { 36 | return (int64_t)endianSwap( (uint64_t)_in); 37 | } 38 | 39 | inline uint64_t endianSwap(uint64_t _in) 40 | { 41 | return (_in >>56) | ( _in <<56) 42 | | ( (_in&UINT64_C(0x00ff000000000000) )>>40) | ( (_in&UINT64_C(0x000000000000ff00) )<<40) 43 | | ( (_in&UINT64_C(0x0000ff0000000000) )>>24) | ( (_in&UINT64_C(0x0000000000ff0000) )<<24) 44 | | ( (_in&UINT64_C(0x000000ff00000000) )>> 8) | ( (_in&UINT64_C(0x00000000ff000000) )<< 8) 45 | ; 46 | } 47 | 48 | template 49 | inline Ty toLittleEndian(Ty _in) 50 | { 51 | #if BX_CPU_ENDIAN_BIG 52 | return endianSwap(_in); 53 | #else 54 | return _in; 55 | #endif // BX_CPU_ENDIAN_BIG 56 | } 57 | 58 | template 59 | inline Ty toBigEndian(Ty _in) 60 | { 61 | #if BX_CPU_ENDIAN_LITTLE 62 | return endianSwap(_in); 63 | #else 64 | return _in; 65 | #endif // BX_CPU_ENDIAN_LITTLE 66 | } 67 | 68 | template 69 | inline Ty toHostEndian(Ty _in, bool _fromLittleEndian) 70 | { 71 | #if BX_CPU_ENDIAN_LITTLE 72 | return _fromLittleEndian ? _in : endianSwap(_in); 73 | #else 74 | return _fromLittleEndian ? endianSwap(_in) : _in; 75 | #endif // BX_CPU_ENDIAN_LITTLE 76 | } 77 | 78 | } // namespace bx 79 | -------------------------------------------------------------------------------- /include/bx/inline/error.inl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #ifndef BX_ERROR_H_HEADER_GUARD 7 | # error "Must be included from bx/error!" 8 | #endif // BX_ERROR_H_HEADER_GUARD 9 | 10 | #include 11 | 12 | namespace bx 13 | { 14 | inline Error::Error() 15 | : m_code(0) 16 | { 17 | } 18 | 19 | inline void Error::reset() 20 | { 21 | m_code = 0; 22 | m_msg.clear(); 23 | } 24 | 25 | inline void Error::setError(ErrorResult _errorResult, const StringLiteral& _msg, const Location& _location) 26 | { 27 | BX_ASSERT(0 != _errorResult.code, "Invalid ErrorResult passed to setError!"); 28 | 29 | if (!isOk() ) 30 | { 31 | return; 32 | } 33 | 34 | m_location = _location; 35 | m_code = _errorResult.code; 36 | m_msg = _msg; 37 | } 38 | 39 | inline bool Error::isOk() const 40 | { 41 | return 0 == m_code; 42 | } 43 | 44 | inline ErrorResult Error::get() const 45 | { 46 | ErrorResult result = { m_code }; 47 | return result; 48 | } 49 | 50 | inline const StringLiteral& Error::getMessage() const 51 | { 52 | return m_msg; 53 | } 54 | 55 | inline const Location& Error::getLocation() const 56 | { 57 | return m_location; 58 | } 59 | 60 | inline bool Error::operator==(const ErrorResult& _rhs) const 61 | { 62 | return _rhs.code == m_code; 63 | } 64 | 65 | inline bool Error::operator!=(const ErrorResult& _rhs) const 66 | { 67 | return _rhs.code != m_code; 68 | } 69 | 70 | inline ErrorIgnore::operator Error*() 71 | { 72 | return this; 73 | } 74 | 75 | inline ErrorAssert::~ErrorAssert() 76 | { 77 | BX_ASSERT_LOC(getLocation(), isOk(), "ErrorAssert: 0x%08x `%S`" 78 | , get().code 79 | , &getMessage() 80 | ); 81 | } 82 | 83 | inline ErrorFatal::operator Error*() 84 | { 85 | return this; 86 | } 87 | 88 | inline ErrorFatal::~ErrorFatal() 89 | { 90 | _BX_ASSERT_LOC(getLocation(), isOk(), "ErrorFatal: 0x%08x `%S`" 91 | , get().code 92 | , &getMessage() 93 | ); 94 | } 95 | 96 | inline ErrorAssert::operator Error*() 97 | { 98 | return this; 99 | } 100 | 101 | inline ErrorScope::ErrorScope(Error* _err, const StringLiteral& _name) 102 | : m_err(_err) 103 | , m_name(_name) 104 | { 105 | BX_UNUSED(m_err); 106 | BX_ASSERT(NULL != _err, "_err can't be NULL"); 107 | } 108 | 109 | inline ErrorScope::~ErrorScope() 110 | { 111 | if (m_name.isEmpty() ) 112 | { 113 | BX_ASSERT_LOC( 114 | m_err->getLocation() 115 | , m_err->isOk() 116 | , "ErrorScope: 0x%08x `%S`" 117 | , m_err->get().code 118 | , &m_err->getMessage() 119 | ); 120 | } 121 | else 122 | { 123 | BX_ASSERT_LOC( 124 | m_err->getLocation() 125 | , m_err->isOk() 126 | , "ErrorScope: %S - 0x%08x `%S`" 127 | , &m_name 128 | , m_err->get().code 129 | , &m_err->getMessage() 130 | ); 131 | } 132 | } 133 | 134 | inline const StringLiteral& ErrorScope::getName() const 135 | { 136 | return m_name; 137 | } 138 | 139 | } // namespace bx 140 | -------------------------------------------------------------------------------- /include/bx/inline/hash.inl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #ifndef BX_HASH_H_HEADER_GUARD 7 | # error "Must be included from bx/hash.h!" 8 | #endif // BX_HASH_H_HEADER_GUARD 9 | 10 | namespace bx 11 | { 12 | inline void HashAdler32::begin() 13 | { 14 | m_a = 1; 15 | m_b = 0; 16 | } 17 | 18 | inline void HashAdler32::add(const void* _data, int32_t _len) 19 | { 20 | constexpr uint32_t kModAdler = 65521; 21 | 22 | const uint8_t* data = (const uint8_t*)_data; 23 | for (; _len != 0; --_len) 24 | { 25 | m_a = (m_a + *data++) % kModAdler; 26 | m_b = (m_b + m_a ) % kModAdler; 27 | } 28 | } 29 | 30 | inline void HashAdler32::add(const char* _data) 31 | { 32 | return add(StringView(_data) ); 33 | } 34 | 35 | inline void HashAdler32::add(const StringView& _data) 36 | { 37 | return add(_data.getPtr(), _data.getLength() ); 38 | } 39 | 40 | template 41 | inline void HashAdler32::add(const Ty& _data) 42 | { 43 | add(&_data, sizeof(Ty) ); 44 | } 45 | 46 | inline uint32_t HashAdler32::end() 47 | { 48 | return m_a | (m_b<<16); 49 | } 50 | 51 | inline void HashCrc32::add(const char* _data) 52 | { 53 | return add(StringView(_data) ); 54 | } 55 | 56 | inline void HashCrc32::add(const StringView& _data) 57 | { 58 | return add(_data.getPtr(), _data.getLength() ); 59 | } 60 | 61 | template 62 | inline void HashCrc32::add(const Ty& _data) 63 | { 64 | add(&_data, sizeof(Ty) ); 65 | } 66 | 67 | inline uint32_t HashCrc32::end() 68 | { 69 | m_hash ^= UINT32_MAX; 70 | return m_hash; 71 | } 72 | 73 | inline void HashMurmur2A::begin(uint32_t _seed) 74 | { 75 | BX_UNUSED(m_tail); 76 | m_hash = _seed; 77 | m_size = 0; 78 | m_count = 0; 79 | } 80 | 81 | inline void HashMurmur2A::add(const char* _data) 82 | { 83 | return add(StringView(_data) ); 84 | } 85 | 86 | inline void HashMurmur2A::add(const StringView& _data) 87 | { 88 | return add(_data.getPtr(), _data.getLength() ); 89 | } 90 | 91 | template 92 | inline void HashMurmur2A::add(const Ty& _data) 93 | { 94 | add(&_data, sizeof(Ty) ); 95 | } 96 | 97 | inline void HashMurmur3::begin(uint32_t _seed) 98 | { 99 | BX_UNUSED(m_tail); 100 | m_hash = _seed; 101 | m_size = 0; 102 | m_count = 0; 103 | } 104 | 105 | inline void HashMurmur3::add(const char* _data) 106 | { 107 | return add(StringView(_data) ); 108 | } 109 | 110 | inline void HashMurmur3::add(const StringView& _data) 111 | { 112 | return add(_data.getPtr(), _data.getLength() ); 113 | } 114 | 115 | template 116 | inline void HashMurmur3::add(const Ty& _data) 117 | { 118 | add(&_data, sizeof(Ty) ); 119 | } 120 | 121 | template 122 | inline uint32_t hash(const void* _data, uint32_t _size) 123 | { 124 | HashT hh; 125 | hh.begin(); 126 | hh.add(_data, (int32_t)_size); 127 | return hh.end(); 128 | } 129 | 130 | template 131 | inline uint32_t hash(const char* _data) 132 | { 133 | return hash(StringView(_data) ); 134 | } 135 | 136 | template 137 | inline uint32_t hash(const StringView& _data) 138 | { 139 | return hash(_data.getPtr(), _data.getLength() ); 140 | } 141 | 142 | template 143 | inline uint32_t hash(const Ty& _data) 144 | { 145 | static_assert(isTriviallyCopyable() ); 146 | return hash(&_data, sizeof(Ty) ); 147 | } 148 | 149 | } // namespace bx 150 | -------------------------------------------------------------------------------- /include/bx/inline/mpscqueue.inl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #ifndef BX_MPSCQUEUE_H_HEADER_GUARD 7 | # error "Must be included from bx/mpscqueue.h!" 8 | #endif // BX_MPSCQUEUE_H_HEADER_GUARD 9 | 10 | namespace bx 11 | { 12 | template 13 | inline MpScUnboundedQueueT::MpScUnboundedQueueT(AllocatorI* _allocator) 14 | : m_queue(_allocator) 15 | { 16 | } 17 | 18 | template 19 | inline MpScUnboundedQueueT::~MpScUnboundedQueueT() 20 | { 21 | } 22 | 23 | template 24 | inline void MpScUnboundedQueueT::push(Ty* _ptr) 25 | { 26 | MutexScope lock(m_write); 27 | m_queue.push(_ptr); 28 | } 29 | 30 | template 31 | inline Ty* MpScUnboundedQueueT::peek() 32 | { 33 | return m_queue.peek(); 34 | } 35 | 36 | template 37 | inline Ty* MpScUnboundedQueueT::pop() 38 | { 39 | return m_queue.pop(); 40 | } 41 | 42 | template 43 | inline MpScUnboundedBlockingQueue::MpScUnboundedBlockingQueue(AllocatorI* _allocator) 44 | : m_queue(_allocator) 45 | { 46 | } 47 | 48 | template 49 | inline MpScUnboundedBlockingQueue::~MpScUnboundedBlockingQueue() 50 | { 51 | } 52 | 53 | template 54 | inline void MpScUnboundedBlockingQueue::push(Ty* _ptr) 55 | { 56 | m_queue.push(_ptr); 57 | m_sem.post(); 58 | } 59 | 60 | template 61 | inline Ty* MpScUnboundedBlockingQueue::pop() 62 | { 63 | m_sem.wait(); 64 | return m_queue.pop(); 65 | } 66 | 67 | } // namespace bx 68 | -------------------------------------------------------------------------------- /include/bx/inline/mutex.inl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #ifndef BX_MUTEX_H_HEADER_GUARD 7 | # error "Must be included from bx/mutex.h!" 8 | #endif // BX_MUTEX_H_HEADER_GUARD 9 | 10 | namespace bx 11 | { 12 | inline MutexScope::MutexScope(Mutex& _mutex) 13 | : m_mutex(_mutex) 14 | { 15 | m_mutex.lock(); 16 | } 17 | 18 | inline MutexScope::~MutexScope() 19 | { 20 | m_mutex.unlock(); 21 | } 22 | 23 | } // namespace bx 24 | -------------------------------------------------------------------------------- /include/bx/inline/os.inl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #ifndef BX_H_HEADER_GUARD 7 | # error "Must be included from bx/os.h!" 8 | #endif // BX_H_HEADER_GUARD 9 | 10 | namespace bx 11 | { 12 | template 13 | inline ProtoT dlsym(void* _handle, const StringView& _symbol) 14 | { 15 | return reinterpret_cast(dlsym(_handle, _symbol) ); 16 | } 17 | 18 | } // namespace bx 19 | -------------------------------------------------------------------------------- /include/bx/inline/rng.inl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #ifndef BX_RNG_H_HEADER_GUARD 7 | # error "Must be included from bx/rng.h!" 8 | #endif // BX_RNG_H_HEADER_GUARD 9 | 10 | namespace bx 11 | { 12 | inline RngMwc::RngMwc(uint32_t _z, uint32_t _w) 13 | : m_z(_z) 14 | , m_w(_w) 15 | { 16 | } 17 | 18 | inline void RngMwc::reset(uint32_t _z, uint32_t _w) 19 | { 20 | m_z = _z; 21 | m_w = _w; 22 | } 23 | 24 | inline uint32_t RngMwc::gen() 25 | { 26 | m_z = 36969*(m_z&65535)+(m_z>>16); 27 | m_w = 18000*(m_w&65535)+(m_w>>16); 28 | return (m_z<<16)+m_w; 29 | } 30 | 31 | inline RngShr3::RngShr3(uint32_t _jsr) 32 | : m_jsr(_jsr) 33 | { 34 | } 35 | 36 | inline void RngShr3::reset(uint32_t _jsr) 37 | { 38 | m_jsr = _jsr; 39 | } 40 | 41 | inline uint32_t RngShr3::gen() 42 | { 43 | m_jsr ^= m_jsr<<17; 44 | m_jsr ^= m_jsr>>13; 45 | m_jsr ^= m_jsr<<5; 46 | return m_jsr; 47 | } 48 | 49 | template 50 | inline float frnd(Rng* _rng) 51 | { 52 | uint32_t rnd = _rng->gen() & UINT16_MAX; 53 | return float(rnd) * 1.0f/float(UINT16_MAX); 54 | } 55 | 56 | template 57 | inline float frndh(Rng* _rng) 58 | { 59 | return 2.0f * frnd(_rng) - 1.0f; 60 | } 61 | 62 | template 63 | inline Vec3 randUnitCircle(Rng* _rng) 64 | { 65 | const float angle = frnd(_rng) * kPi2; 66 | 67 | return 68 | { 69 | cos(angle), 70 | 0.0f, 71 | sin(angle), 72 | }; 73 | } 74 | 75 | template 76 | inline Vec3 randUnitSphere(Rng* _rng) 77 | { 78 | const float rand0 = frnd(_rng) * 2.0f - 1.0f; 79 | const float rand1 = frnd(_rng) * kPi2; 80 | const float sqrtf1 = sqrt(1.0f - rand0*rand0); 81 | 82 | return 83 | { 84 | sqrtf1 * cos(rand1), 85 | sqrtf1 * sin(rand1), 86 | rand0, 87 | }; 88 | } 89 | 90 | template 91 | inline Vec3 randUnitHemisphere(Ty* _rng, const Vec3& _normal) 92 | { 93 | const Vec3 dir = randUnitSphere(_rng); 94 | const float ddotn = dot(dir, _normal); 95 | 96 | if (0.0f > ddotn) 97 | { 98 | return neg(dir); 99 | } 100 | 101 | return dir; 102 | } 103 | 104 | inline void generateSphereHammersley(void* _data, uint32_t _stride, uint32_t _num, float _scale) 105 | { 106 | // Reference(s): 107 | // - Sampling with Hammersley and Halton Points 108 | // https://web.archive.org/web/20190207230709/http://www.cse.cuhk.edu.hk/~ttwong/papers/udpoint/udpoints.html 109 | 110 | uint8_t* data = (uint8_t*)_data; 111 | 112 | for (uint32_t ii = 0; ii < _num; ii++) 113 | { 114 | float tt = 0.0f; 115 | float pp = 0.5; 116 | for (uint32_t jj = ii; jj; jj >>= 1) 117 | { 118 | tt += (jj & 1) ? pp : 0.0f; 119 | pp *= 0.5f; 120 | } 121 | 122 | tt = 2.0f * tt - 1.0f; 123 | 124 | const float phi = (ii + 0.5f) / _num; 125 | const float phirad = phi * kPi2; 126 | const float st = sqrt(1.0f-tt*tt) * _scale; 127 | 128 | float* xyz = (float*)data; 129 | data += _stride; 130 | 131 | xyz[0] = st * cos(phirad); 132 | xyz[1] = st * sin(phirad); 133 | xyz[2] = tt * _scale; 134 | } 135 | } 136 | 137 | template 138 | inline void shuffle(Rng* _rng, Ty* _array, uint32_t _num) 139 | { 140 | BX_ASSERT(_num != 0, "Number of elements can't be 0!"); 141 | 142 | for (uint32_t ii = 0, num = _num-1; ii < num; ++ii) 143 | { 144 | uint32_t jj = ii + 1 + _rng->gen() % (num - ii); 145 | swap(_array[ii], _array[jj]); 146 | } 147 | } 148 | 149 | } // namespace bx 150 | -------------------------------------------------------------------------------- /include/bx/inline/simd256_avx.inl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #ifndef BX_SIMD_T_H_HEADER_GUARD 7 | # error "Must be included from bx/simd_t.h!" 8 | #endif // BX_SIMD_T_H_HEADER_GUARD 9 | 10 | namespace bx 11 | { 12 | template<> 13 | BX_SIMD_FORCE_INLINE simd256_avx_t simd_ld(const void* _ptr) 14 | { 15 | return _mm256_load_ps(reinterpret_cast(_ptr) ); 16 | } 17 | 18 | template<> 19 | BX_SIMD_FORCE_INLINE void simd_st(void* _ptr, simd256_avx_t _a) 20 | { 21 | _mm256_store_ps(reinterpret_cast(_ptr), _a); 22 | } 23 | 24 | template<> 25 | BX_SIMD_FORCE_INLINE simd256_avx_t simd_ld(float _x, float _y, float _z, float _w, float _A, float _B, float _C, float _D) 26 | { 27 | return _mm256_set_ps(_D, _C, _B, _A, _w, _z, _y, _x); 28 | } 29 | 30 | template<> 31 | BX_SIMD_FORCE_INLINE simd256_avx_t simd_ild(uint32_t _x, uint32_t _y, uint32_t _z, uint32_t _w, uint32_t _A, uint32_t _B, uint32_t _C, uint32_t _D) 32 | { 33 | const __m256i set = _mm256_set_epi32(_D, _C, _B, _A, _w, _z, _y, _x); 34 | const simd256_avx_t result = _mm256_castsi256_ps(set); 35 | 36 | return result; 37 | } 38 | 39 | template<> 40 | BX_SIMD_FORCE_INLINE simd256_avx_t simd_splat(float _a) 41 | { 42 | return _mm256_set1_ps(_a); 43 | } 44 | 45 | template<> 46 | BX_SIMD_FORCE_INLINE simd256_avx_t simd_isplat(uint32_t _a) 47 | { 48 | const __m256i splat = _mm256_set1_epi32(_a); 49 | const simd256_avx_t result = _mm256_castsi256_ps(splat); 50 | 51 | return result; 52 | } 53 | 54 | template<> 55 | BX_SIMD_FORCE_INLINE simd256_avx_t simd_itof(simd256_avx_t _a) 56 | { 57 | const __m256i itof = _mm256_castps_si256(_a); 58 | const simd256_avx_t result = _mm256_cvtepi32_ps(itof); 59 | 60 | return result; 61 | } 62 | 63 | template<> 64 | BX_SIMD_FORCE_INLINE simd256_avx_t simd_ftoi(simd256_avx_t _a) 65 | { 66 | const __m256i ftoi = _mm256_cvtps_epi32(_a); 67 | const simd256_avx_t result = _mm256_castsi256_ps(ftoi); 68 | 69 | return result; 70 | } 71 | 72 | typedef simd256_avx_t simd256_t; 73 | 74 | } // namespace bx 75 | -------------------------------------------------------------------------------- /include/bx/inline/simd256_ref.inl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #ifndef BX_SIMD_T_H_HEADER_GUARD 7 | # error "Must be included from bx/simd_t.h!" 8 | #endif // BX_SIMD_T_H_HEADER_GUARD 9 | 10 | namespace bx 11 | { 12 | template<> 13 | BX_SIMD_FORCE_INLINE simd256_ref_t simd_ld(const void* _ptr) 14 | { 15 | const simd256_ref_t::type* ptr = reinterpret_cast(_ptr); 16 | simd256_ref_t result; 17 | result.simd128_0 = simd_ld(&ptr[0]); 18 | result.simd128_1 = simd_ld(&ptr[1]); 19 | return result; 20 | } 21 | 22 | template<> 23 | BX_SIMD_FORCE_INLINE void simd_st(void* _ptr, simd256_ref_t& _a) 24 | { 25 | simd256_ref_t* result = reinterpret_cast(_ptr); 26 | simd_st(&result[0], _a.simd128_0); 27 | simd_st(&result[1], _a.simd128_1); 28 | } 29 | 30 | template<> 31 | BX_SIMD_FORCE_INLINE simd256_ref_t simd_ld(float _x, float _y, float _z, float _w, float _a, float _b, float _c, float _d) 32 | { 33 | simd256_ref_t result; 34 | result.simd128_0 = simd_ld(_x, _y, _z, _w); 35 | result.simd128_1 = simd_ld(_a, _b, _c, _d); 36 | return result; 37 | } 38 | 39 | template<> 40 | BX_SIMD_FORCE_INLINE simd256_ref_t simd_ild(uint32_t _x, uint32_t _y, uint32_t _z, uint32_t _w, uint32_t _a, uint32_t _b, uint32_t _c, uint32_t _d) 41 | { 42 | simd256_ref_t result; 43 | result.simd128_0 = simd_ild(_x, _y, _z, _w); 44 | result.simd128_1 = simd_ild(_a, _b, _c, _d); 45 | return result; 46 | } 47 | 48 | template<> 49 | BX_SIMD_FORCE_INLINE simd256_ref_t simd_splat(float _a) 50 | { 51 | simd256_ref_t result; 52 | result.simd128_0 = simd_splat(_a); 53 | result.simd128_1 = simd_splat(_a); 54 | return result; 55 | } 56 | 57 | template<> 58 | BX_SIMD_FORCE_INLINE simd256_ref_t simd_isplat(uint32_t _a) 59 | { 60 | simd256_ref_t result; 61 | result.simd128_0 = simd_isplat(_a); 62 | result.simd128_1 = simd_isplat(_a); 63 | return result; 64 | } 65 | 66 | template<> 67 | BX_SIMD_FORCE_INLINE simd256_ref_t simd_itof(simd256_ref_t _a) 68 | { 69 | simd256_ref_t result; 70 | result.simd128_0 = simd_itof(_a.simd128_0); 71 | result.simd128_1 = simd_itof(_a.simd128_1); 72 | return result; 73 | } 74 | 75 | template<> 76 | BX_SIMD_FORCE_INLINE simd256_ref_t simd_ftoi(simd256_ref_t _a) 77 | { 78 | simd256_ref_t result; 79 | result.simd128_0 = simd_ftoi(_a.simd128_0); 80 | result.simd128_1 = simd_ftoi(_a.simd128_1); 81 | return result; 82 | } 83 | 84 | } // namespace bx 85 | -------------------------------------------------------------------------------- /include/bx/inline/spscqueue.inl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #ifndef BX_SPSCQUEUE_H_HEADER_GUARD 7 | # error "Must be included from bx/spscqueue.h!" 8 | #endif // BX_SPSCQUEUE_H_HEADER_GUARD 9 | 10 | namespace bx 11 | { 12 | // Reference(s): 13 | // - Writing Lock-Free Code: A Corrected Queue 14 | // https://web.archive.org/web/20190207230604/http://www.drdobbs.com/parallel/writing-lock-free-code-a-corrected-queue/210604448 15 | // 16 | inline SpScUnboundedQueue::SpScUnboundedQueue(AllocatorI* _allocator) 17 | : m_allocator(_allocator) 18 | , m_first(BX_NEW(m_allocator, Node)(NULL) ) 19 | , m_divider(m_first) 20 | , m_last(m_first) 21 | { 22 | } 23 | 24 | inline SpScUnboundedQueue::~SpScUnboundedQueue() 25 | { 26 | while (NULL != m_first) 27 | { 28 | Node* node = m_first; 29 | m_first = node->m_next; 30 | deleteObject(m_allocator, node); 31 | } 32 | } 33 | 34 | inline void SpScUnboundedQueue::push(void* _ptr) 35 | { 36 | m_last->m_next = BX_NEW(m_allocator, Node)(_ptr); 37 | atomicExchangePtr( (void**)&m_last, m_last->m_next); 38 | while (m_first != m_divider) 39 | { 40 | Node* node = m_first; 41 | m_first = m_first->m_next; 42 | deleteObject(m_allocator, node); 43 | } 44 | } 45 | 46 | inline void* SpScUnboundedQueue::peek() 47 | { 48 | if (m_divider != m_last) 49 | { 50 | return m_divider->m_next->m_ptr; 51 | } 52 | 53 | return NULL; 54 | } 55 | 56 | inline void* SpScUnboundedQueue::pop() 57 | { 58 | if (m_divider != m_last) 59 | { 60 | void* ptr = m_divider->m_next->m_ptr; 61 | atomicExchangePtr( (void**)&m_divider, m_divider->m_next); 62 | return ptr; 63 | } 64 | 65 | return NULL; 66 | } 67 | 68 | inline SpScUnboundedQueue::Node::Node(void* _ptr) 69 | : m_ptr(_ptr) 70 | , m_next(NULL) 71 | { 72 | } 73 | 74 | template 75 | inline SpScUnboundedQueueT::SpScUnboundedQueueT(AllocatorI* _allocator) 76 | : m_queue(_allocator) 77 | { 78 | } 79 | 80 | template 81 | inline SpScUnboundedQueueT::~SpScUnboundedQueueT() 82 | { 83 | } 84 | 85 | template 86 | inline void SpScUnboundedQueueT::push(Ty* _ptr) 87 | { 88 | m_queue.push(_ptr); 89 | } 90 | 91 | template 92 | inline Ty* SpScUnboundedQueueT::peek() 93 | { 94 | return (Ty*)m_queue.peek(); 95 | } 96 | 97 | template 98 | inline Ty* SpScUnboundedQueueT::pop() 99 | { 100 | return (Ty*)m_queue.pop(); 101 | } 102 | 103 | #if BX_CONFIG_SUPPORTS_THREADING 104 | inline SpScBlockingUnboundedQueue::SpScBlockingUnboundedQueue(AllocatorI* _allocator) 105 | : m_queue(_allocator) 106 | { 107 | } 108 | 109 | inline SpScBlockingUnboundedQueue::~SpScBlockingUnboundedQueue() 110 | { 111 | } 112 | 113 | inline void SpScBlockingUnboundedQueue::push(void* _ptr) 114 | { 115 | m_queue.push(_ptr); 116 | m_count.post(); 117 | } 118 | 119 | inline void* SpScBlockingUnboundedQueue::peek() 120 | { 121 | return m_queue.peek(); 122 | } 123 | 124 | inline void* SpScBlockingUnboundedQueue::pop(int32_t _msecs) 125 | { 126 | if (m_count.wait(_msecs) ) 127 | { 128 | return m_queue.pop(); 129 | } 130 | 131 | return NULL; 132 | } 133 | 134 | template 135 | inline SpScBlockingUnboundedQueueT::SpScBlockingUnboundedQueueT(AllocatorI* _allocator) 136 | : m_queue(_allocator) 137 | { 138 | } 139 | 140 | template 141 | inline SpScBlockingUnboundedQueueT::~SpScBlockingUnboundedQueueT() 142 | { 143 | } 144 | 145 | template 146 | inline void SpScBlockingUnboundedQueueT::push(Ty* _ptr) 147 | { 148 | m_queue.push(_ptr); 149 | } 150 | 151 | template 152 | inline Ty* SpScBlockingUnboundedQueueT::peek() 153 | { 154 | return (Ty*)m_queue.peek(); 155 | } 156 | 157 | template 158 | inline Ty* SpScBlockingUnboundedQueueT::pop(int32_t _msecs) 159 | { 160 | return (Ty*)m_queue.pop(_msecs); 161 | } 162 | 163 | #endif // BX_CONFIG_SUPPORTS_THREADING 164 | 165 | } // namespace bx 166 | -------------------------------------------------------------------------------- /include/bx/mpscqueue.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #ifndef BX_MPSCQUEUE_H_HEADER_GUARD 7 | #define BX_MPSCQUEUE_H_HEADER_GUARD 8 | 9 | #include "allocator.h" 10 | #include "mutex.h" 11 | #include "spscqueue.h" 12 | 13 | namespace bx 14 | { 15 | /// 16 | template 17 | class MpScUnboundedQueueT 18 | { 19 | BX_CLASS(MpScUnboundedQueueT 20 | , NO_DEFAULT_CTOR 21 | , NO_COPY 22 | ); 23 | 24 | public: 25 | /// 26 | MpScUnboundedQueueT(AllocatorI* _allocator); 27 | 28 | /// 29 | ~MpScUnboundedQueueT(); 30 | 31 | /// 32 | void push(Ty* _ptr); // producer only 33 | 34 | /// 35 | Ty* peek(); // consumer only 36 | 37 | /// 38 | Ty* pop(); // consumer only 39 | 40 | private: 41 | Mutex m_write; 42 | SpScUnboundedQueueT m_queue; 43 | }; 44 | 45 | /// 46 | template 47 | class MpScUnboundedBlockingQueue 48 | { 49 | BX_CLASS(MpScUnboundedBlockingQueue 50 | , NO_DEFAULT_CTOR 51 | , NO_COPY 52 | ); 53 | 54 | public: 55 | /// 56 | MpScUnboundedBlockingQueue(AllocatorI* _allocator); 57 | 58 | /// 59 | ~MpScUnboundedBlockingQueue(); 60 | 61 | /// 62 | void push(Ty* _ptr); // producer only 63 | 64 | /// 65 | Ty* pop(); // consumer only 66 | 67 | private: 68 | MpScUnboundedQueueT m_queue; 69 | Semaphore m_sem; 70 | }; 71 | 72 | } // namespace bx 73 | 74 | #include "inline/mpscqueue.inl" 75 | 76 | #endif // BX_MPSCQUEUE_H_HEADER_GUARD 77 | -------------------------------------------------------------------------------- /include/bx/mutex.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #ifndef BX_MUTEX_H_HEADER_GUARD 7 | #define BX_MUTEX_H_HEADER_GUARD 8 | 9 | #include "bx.h" 10 | 11 | namespace bx 12 | { 13 | /// 14 | class Mutex 15 | { 16 | BX_CLASS(Mutex 17 | , NO_COPY 18 | ); 19 | 20 | public: 21 | /// 22 | Mutex(); 23 | 24 | /// 25 | ~Mutex(); 26 | 27 | /// 28 | void lock(); 29 | 30 | /// 31 | void unlock(); 32 | 33 | private: 34 | BX_ALIGN_DECL(16, uint8_t) m_internal[64]; 35 | }; 36 | 37 | /// 38 | class MutexScope 39 | { 40 | BX_CLASS(MutexScope 41 | , NO_DEFAULT_CTOR 42 | , NO_COPY 43 | ); 44 | 45 | public: 46 | /// 47 | MutexScope(Mutex& _mutex); 48 | 49 | /// 50 | ~MutexScope(); 51 | 52 | private: 53 | Mutex& m_mutex; 54 | }; 55 | 56 | } // namespace bx 57 | 58 | #include "inline/mutex.inl" 59 | 60 | #endif // BX_MUTEX_H_HEADER_GUARD 61 | -------------------------------------------------------------------------------- /include/bx/os.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #ifndef BX_OS_H_HEADER_GUARD 7 | #define BX_OS_H_HEADER_GUARD 8 | 9 | #include "filepath.h" 10 | 11 | #if BX_PLATFORM_OSX 12 | # define BX_DL_EXT "dylib" 13 | #elif BX_PLATFORM_WINDOWS 14 | # define BX_DL_EXT "dll" 15 | #else 16 | # define BX_DL_EXT "so" 17 | #endif // 18 | 19 | BX_ERROR_RESULT(kErrorMemoryMapFailed, BX_MAKEFOURCC('b', 'x', '8', '0') ); 20 | BX_ERROR_RESULT(kErrorMemoryUnmapFailed, BX_MAKEFOURCC('b', 'x', '8', '1') ); 21 | 22 | namespace bx 23 | { 24 | /// 25 | void sleep(uint32_t _ms); 26 | 27 | /// 28 | void yield(); 29 | 30 | /// 31 | uint32_t getTid(); 32 | 33 | /// 34 | size_t getProcessMemoryUsed(); 35 | 36 | /// 37 | void* dlopen(const FilePath& _filePath); 38 | 39 | /// 40 | void dlclose(void* _handle); 41 | 42 | /// 43 | void* dlsym(void* _handle, const StringView& _symbol); 44 | 45 | /// 46 | template 47 | ProtoT dlsym(void* _handle, const StringView& _symbol); 48 | 49 | /// 50 | bool getEnv(char* _out, uint32_t* _inOutSize, const StringView& _name); 51 | 52 | /// 53 | void setEnv(const StringView& _name, const StringView& _value); 54 | 55 | /// 56 | int chdir(const char* _path); 57 | 58 | /// 59 | void* exec(const char* const* _argv); 60 | 61 | /// 62 | [[noreturn]] void exit(int32_t _exitCode); 63 | 64 | /// 65 | void* memoryMap(void* _address, size_t _size, Error* _err); 66 | 67 | /// 68 | void memoryUnmap(void* _address, size_t _size, Error* _err); 69 | 70 | /// 71 | size_t memoryPageSize(); 72 | 73 | } // namespace bx 74 | 75 | #include "inline/os.inl" 76 | 77 | #endif // BX_OS_H_HEADER_GUARD 78 | -------------------------------------------------------------------------------- /include/bx/process.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #ifndef BX_PROCESS_H_HEADER_GUARD 7 | #define BX_PROCESS_H_HEADER_GUARD 8 | 9 | #include "readerwriter.h" 10 | 11 | namespace bx 12 | { 13 | /// 14 | class ProcessReader 15 | : public ProcessOpenI 16 | , public CloserI 17 | , public ReaderI 18 | { 19 | public: 20 | /// 21 | ProcessReader(); 22 | 23 | /// 24 | ~ProcessReader(); 25 | 26 | /// 27 | virtual bool open(const FilePath& _filePath, const StringView& _args, Error* _err) override; 28 | 29 | /// 30 | virtual void close() override; 31 | 32 | /// 33 | virtual int32_t read(void* _data, int32_t _size, Error* _err) override; 34 | 35 | /// 36 | int32_t getExitCode() const; 37 | 38 | private: 39 | void* m_file; 40 | int32_t m_exitCode; 41 | }; 42 | 43 | /// 44 | class ProcessWriter 45 | : public ProcessOpenI 46 | , public CloserI 47 | , public WriterI 48 | { 49 | public: 50 | /// 51 | ProcessWriter(); 52 | 53 | /// 54 | ~ProcessWriter(); 55 | 56 | /// 57 | virtual bool open(const FilePath& _filePath, const StringView& _args, Error* _err) override; 58 | 59 | /// 60 | virtual void close() override; 61 | 62 | /// 63 | virtual int32_t write(const void* _data, int32_t _size, Error* _err) override; 64 | 65 | /// 66 | int32_t getExitCode() const; 67 | 68 | private: 69 | void* m_file; 70 | int32_t m_exitCode; 71 | }; 72 | 73 | } // namespace bx 74 | 75 | #endif // BX_PROCESS_H_HEADER_GUARD 76 | -------------------------------------------------------------------------------- /include/bx/ringbuffer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #ifndef BX_RINGBUFFER_H_HEADER_GUARD 7 | #define BX_RINGBUFFER_H_HEADER_GUARD 8 | 9 | #include "bx.h" 10 | #include "cpu.h" 11 | #include "uint32_t.h" 12 | 13 | namespace bx 14 | { 15 | /// 16 | class RingBufferControl 17 | { 18 | BX_CLASS(RingBufferControl 19 | , NO_DEFAULT_CTOR 20 | , NO_COPY 21 | ); 22 | 23 | public: 24 | /// 25 | RingBufferControl(uint32_t _size); 26 | 27 | /// 28 | ~RingBufferControl(); 29 | 30 | /// 31 | uint32_t available() const; 32 | 33 | /// 34 | uint32_t consume(uint32_t _size); // consumer only 35 | 36 | /// 37 | uint32_t reserve(uint32_t _size, bool _mustSucceed = false); // producer only 38 | 39 | /// 40 | uint32_t commit(uint32_t _size); // producer only 41 | 42 | /// 43 | uint32_t distance(uint32_t _from, uint32_t _to) const; // both 44 | 45 | /// 46 | void reset(); 47 | 48 | const uint32_t m_size; 49 | uint32_t m_current; 50 | uint32_t m_write; 51 | uint32_t m_read; 52 | }; 53 | 54 | /// 55 | class SpScRingBufferControl 56 | { 57 | BX_CLASS(SpScRingBufferControl 58 | , NO_DEFAULT_CTOR 59 | , NO_COPY 60 | ); 61 | 62 | public: 63 | /// 64 | SpScRingBufferControl(uint32_t _size); 65 | 66 | /// 67 | ~SpScRingBufferControl(); 68 | 69 | /// 70 | uint32_t available() const; 71 | 72 | /// 73 | uint32_t consume(uint32_t _size); // consumer only 74 | 75 | /// 76 | uint32_t reserve(uint32_t _size); // producer only 77 | 78 | /// 79 | uint32_t commit(uint32_t _size); // producer only 80 | 81 | /// 82 | uint32_t distance(uint32_t _from, uint32_t _to) const; // both 83 | 84 | /// 85 | void reset(); 86 | 87 | const uint32_t m_size; 88 | uint32_t m_current; 89 | uint32_t m_write; 90 | uint32_t m_read; 91 | }; 92 | 93 | /// 94 | template 95 | class ReadRingBufferT 96 | { 97 | BX_CLASS(ReadRingBufferT 98 | , NO_DEFAULT_CTOR 99 | , NO_COPY 100 | ); 101 | 102 | public: 103 | /// 104 | ReadRingBufferT(ControlT& _control, const char* _buffer, uint32_t _size); 105 | 106 | /// 107 | ~ReadRingBufferT(); 108 | 109 | /// 110 | void end(); 111 | 112 | /// 113 | void read(char* _data, uint32_t _len); 114 | 115 | /// 116 | void skip(uint32_t _len); 117 | 118 | private: 119 | template 120 | friend class WriteRingBufferT; 121 | 122 | ControlT& m_control; 123 | uint32_t m_read; 124 | uint32_t m_end; 125 | const uint32_t m_size; 126 | const char* m_buffer; 127 | }; 128 | 129 | /// 130 | typedef ReadRingBufferT ReadRingBuffer; 131 | 132 | /// 133 | typedef ReadRingBufferT SpScReadRingBuffer; 134 | 135 | /// 136 | template 137 | class WriteRingBufferT 138 | { 139 | BX_CLASS(WriteRingBufferT 140 | , NO_DEFAULT_CTOR 141 | , NO_COPY 142 | ); 143 | 144 | public: 145 | /// 146 | WriteRingBufferT(ControlT& _control, char* _buffer, uint32_t _size); 147 | 148 | /// 149 | ~WriteRingBufferT(); 150 | 151 | /// 152 | void end(); 153 | 154 | /// 155 | void write(const char* _data, uint32_t _len); 156 | 157 | /// 158 | void write(ReadRingBufferT& _read, uint32_t _len); 159 | 160 | /// 161 | void skip(uint32_t _len); 162 | 163 | private: 164 | ControlT& m_control; 165 | uint32_t m_write; 166 | uint32_t m_end; 167 | const uint32_t m_size; 168 | char* m_buffer; 169 | }; 170 | 171 | /// 172 | typedef WriteRingBufferT WriteRingBuffer; 173 | 174 | /// 175 | typedef WriteRingBufferT SpScWriteRingBuffer; 176 | 177 | } // namespace bx 178 | 179 | #include "inline/ringbuffer.inl" 180 | 181 | #endif // BX_RINGBUFFER_H_HEADER_GUARD 182 | -------------------------------------------------------------------------------- /include/bx/rng.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #ifndef BX_RNG_H_HEADER_GUARD 7 | #define BX_RNG_H_HEADER_GUARD 8 | 9 | #include "bx.h" 10 | #include "math.h" 11 | #include "uint32_t.h" 12 | 13 | namespace bx 14 | { 15 | /// George Marsaglia's MWC 16 | class RngMwc 17 | { 18 | public: 19 | /// 20 | RngMwc(uint32_t _z = 12345, uint32_t _w = 65435); 21 | 22 | /// 23 | void reset(uint32_t _z = 12345, uint32_t _w = 65435); 24 | 25 | /// 26 | uint32_t gen(); 27 | 28 | private: 29 | uint32_t m_z; 30 | uint32_t m_w; 31 | }; 32 | 33 | /// George Marsaglia's SHR3 34 | class RngShr3 35 | { 36 | public: 37 | /// 38 | RngShr3(uint32_t _jsr = 34221); 39 | 40 | /// 41 | void reset(uint32_t _jsr = 34221); 42 | 43 | /// 44 | uint32_t gen(); 45 | 46 | private: 47 | uint32_t m_jsr; 48 | }; 49 | 50 | /// Returns random number between 0.0f and 1.0f. 51 | template 52 | float frnd(Rng* _rng); 53 | 54 | /// Returns random number between -1.0f and 1.0f. 55 | template 56 | float frndh(Rng* _rng); 57 | 58 | /// Generate random point on unit circle. 59 | template 60 | Vec3 randUnitCircle(Rng* _rng); 61 | 62 | /// Generate random point on unit sphere. 63 | template 64 | Vec3 randUnitSphere(Rng* _rng); 65 | 66 | /// Generate random point on unit hemisphere. 67 | template 68 | Vec3 randUnitHemisphere(Ty* _rng, const Vec3& _normal); 69 | 70 | /// Sampling with Hammersley and Halton Points. 71 | void generateSphereHammersley(void* _data, uint32_t _stride, uint32_t _num, float _scale = 1.0f); 72 | 73 | /// Fisher-Yates shuffle. 74 | template 75 | void shuffle(Rng* _rng, Ty* _array, uint32_t _num); 76 | 77 | } // namespace bx 78 | 79 | #include "inline/rng.inl" 80 | 81 | #endif // BX_RNG_H_HEADER_GUARD 82 | -------------------------------------------------------------------------------- /include/bx/semaphore.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #ifndef BX_SEM_H_HEADER_GUARD 7 | #define BX_SEM_H_HEADER_GUARD 8 | 9 | #include "bx.h" 10 | 11 | namespace bx 12 | { 13 | /// 14 | class Semaphore 15 | { 16 | BX_CLASS(Semaphore 17 | , NO_COPY 18 | ); 19 | 20 | public: 21 | /// 22 | Semaphore(); 23 | 24 | /// 25 | ~Semaphore(); 26 | 27 | /// 28 | void post(uint32_t _count = 1); 29 | 30 | /// 31 | bool wait(int32_t _msecs = -1); 32 | 33 | private: 34 | BX_ALIGN_DECL(16, uint8_t) m_internal[128]; 35 | }; 36 | 37 | } // namespace bx 38 | 39 | #endif // BX_SEM_H_HEADER_GUARD 40 | -------------------------------------------------------------------------------- /include/bx/settings.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #ifndef BX_SETTINGS_H_HEADER_GUARD 7 | #define BX_SETTINGS_H_HEADER_GUARD 8 | 9 | #include "allocator.h" 10 | #include "readerwriter.h" 11 | #include "string.h" 12 | 13 | namespace bx 14 | { 15 | /// 16 | class Settings 17 | { 18 | public: 19 | /// 20 | Settings(AllocatorI* _allocator, const void* _data = NULL, uint32_t _len = 0); 21 | 22 | /// 23 | ~Settings(); 24 | 25 | /// 26 | void clear(); 27 | 28 | /// 29 | void load(const void* _data, uint32_t _len); 30 | 31 | /// 32 | StringView get(const StringView& _name) const; 33 | 34 | /// 35 | void set(const StringView& _name, const StringView& _value = ""); 36 | 37 | /// 38 | void remove(const StringView& _name) const; 39 | 40 | /// 41 | int32_t read(ReaderSeekerI* _reader, Error* _err); 42 | 43 | /// 44 | int32_t write(WriterI* _writer, Error* _err) const; 45 | 46 | private: 47 | Settings(); 48 | 49 | AllocatorI* m_allocator; 50 | void* m_ini; 51 | }; 52 | 53 | /// 54 | int32_t read(ReaderSeekerI* _reader, Settings& _settings, Error* _err); 55 | 56 | /// 57 | int32_t write(WriterI* _writer, const Settings& _settings, Error* _err); 58 | 59 | } // namespace bx 60 | 61 | #endif // BX_SETTINGS_H_HEADER_GUARD 62 | -------------------------------------------------------------------------------- /include/bx/spscqueue.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #ifndef BX_SPSCQUEUE_H_HEADER_GUARD 7 | #define BX_SPSCQUEUE_H_HEADER_GUARD 8 | 9 | #include "allocator.h" 10 | #include "cpu.h" 11 | #include "semaphore.h" 12 | 13 | namespace bx 14 | { 15 | /// 16 | class SpScUnboundedQueue 17 | { 18 | BX_CLASS(SpScUnboundedQueue 19 | , NO_DEFAULT_CTOR 20 | , NO_COPY 21 | ); 22 | 23 | public: 24 | /// 25 | SpScUnboundedQueue(AllocatorI* _allocator); 26 | 27 | /// 28 | ~SpScUnboundedQueue(); 29 | 30 | /// 31 | void push(void* _ptr); 32 | 33 | /// 34 | void* peek(); 35 | 36 | /// 37 | void* pop(); 38 | 39 | private: 40 | struct Node 41 | { 42 | /// 43 | Node(void* _ptr); 44 | 45 | void* m_ptr; 46 | Node* m_next; 47 | }; 48 | 49 | AllocatorI* m_allocator; 50 | Node* m_first; 51 | Node* m_divider; 52 | Node* m_last; 53 | }; 54 | 55 | /// 56 | template 57 | class SpScUnboundedQueueT 58 | { 59 | BX_CLASS(SpScUnboundedQueueT 60 | , NO_DEFAULT_CTOR 61 | , NO_COPY 62 | ); 63 | 64 | public: 65 | /// 66 | SpScUnboundedQueueT(AllocatorI* _allocator); 67 | 68 | /// 69 | ~SpScUnboundedQueueT(); 70 | 71 | /// 72 | void push(Ty* _ptr); 73 | 74 | /// 75 | Ty* peek(); 76 | 77 | /// 78 | Ty* pop(); 79 | 80 | private: 81 | SpScUnboundedQueue m_queue; 82 | }; 83 | 84 | #if BX_CONFIG_SUPPORTS_THREADING 85 | /// 86 | class SpScBlockingUnboundedQueue 87 | { 88 | BX_CLASS(SpScBlockingUnboundedQueue 89 | , NO_DEFAULT_CTOR 90 | , NO_COPY 91 | ); 92 | 93 | public: 94 | /// 95 | SpScBlockingUnboundedQueue(AllocatorI* _allocator); 96 | 97 | /// 98 | ~SpScBlockingUnboundedQueue(); 99 | 100 | /// 101 | void push(void* _ptr); // producer only 102 | 103 | /// 104 | void* peek(); // consumer only 105 | 106 | /// 107 | void* pop(int32_t _msecs = -1); // consumer only 108 | 109 | private: 110 | Semaphore m_count; 111 | SpScUnboundedQueue m_queue; 112 | }; 113 | 114 | /// 115 | template 116 | class SpScBlockingUnboundedQueueT 117 | { 118 | BX_CLASS(SpScBlockingUnboundedQueueT 119 | , NO_DEFAULT_CTOR 120 | , NO_COPY 121 | ); 122 | 123 | public: 124 | /// 125 | SpScBlockingUnboundedQueueT(AllocatorI* _allocator); 126 | 127 | /// 128 | ~SpScBlockingUnboundedQueueT(); 129 | 130 | /// 131 | void push(Ty* _ptr); // producer only 132 | 133 | /// 134 | Ty* peek(); // consumer only 135 | 136 | /// 137 | Ty* pop(int32_t _msecs = -1); // consumer only 138 | 139 | private: 140 | SpScBlockingUnboundedQueue m_queue; 141 | }; 142 | #endif // BX_CONFIG_SUPPORTS_THREADING 143 | 144 | } // namespace bx 145 | 146 | #include "inline/spscqueue.inl" 147 | 148 | #endif // BX_SPSCQUEUE_H_HEADER_GUARD 149 | -------------------------------------------------------------------------------- /include/bx/thread.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #ifndef BX_THREAD_H_HEADER_GUARD 7 | #define BX_THREAD_H_HEADER_GUARD 8 | 9 | #include "allocator.h" 10 | #include "mpscqueue.h" 11 | 12 | #if BX_CONFIG_SUPPORTS_THREADING 13 | 14 | namespace bx 15 | { 16 | /// 17 | typedef int32_t (*ThreadFn)(class Thread* _self, void* _userData); 18 | 19 | /// 20 | class Thread 21 | { 22 | BX_CLASS(Thread 23 | , NO_COPY 24 | ); 25 | 26 | public: 27 | /// 28 | Thread(); 29 | 30 | /// 31 | virtual ~Thread(); 32 | 33 | /// Create and initialize thread. 34 | /// 35 | /// @param[in] _fn Thread function. 36 | /// @param[in] _userData User data passed to thread function. 37 | /// @param[in] _stackSize Stack size, if zero is passed it will use OS default thread stack 38 | /// size. 39 | /// @param[in] _name Thread name used by debugger. 40 | /// @returns True if thread is created, otherwise returns false. 41 | /// 42 | bool init(ThreadFn _fn, void* _userData = NULL, uint32_t _stackSize = 0, const char* _name = NULL); 43 | 44 | /// 45 | void shutdown(); 46 | 47 | /// 48 | bool isRunning() const; 49 | 50 | /// 51 | int32_t getExitCode() const; 52 | 53 | /// 54 | void setThreadName(const char* _name); 55 | 56 | /// 57 | void push(void* _ptr); 58 | 59 | /// 60 | void* pop(); 61 | 62 | private: 63 | friend struct ThreadInternal; 64 | int32_t entry(); 65 | 66 | BX_ALIGN_DECL(16, uint8_t) m_internal[64]; 67 | 68 | ThreadFn m_fn; 69 | void* m_userData; 70 | MpScUnboundedBlockingQueue m_queue; 71 | Semaphore m_sem; 72 | uint32_t m_stackSize; 73 | int32_t m_exitCode; 74 | bool m_running; 75 | char m_name[64]; 76 | }; 77 | 78 | /// 79 | class TlsData 80 | { 81 | public: 82 | /// 83 | TlsData(); 84 | 85 | /// 86 | ~TlsData(); 87 | 88 | /// 89 | void* get() const; 90 | 91 | /// 92 | void set(void* _ptr); 93 | 94 | private: 95 | BX_ALIGN_DECL(16, uint8_t) m_internal[64]; 96 | }; 97 | 98 | } // namespace bx 99 | 100 | #endif 101 | 102 | #endif // BX_THREAD_H_HEADER_GUARD 103 | -------------------------------------------------------------------------------- /include/bx/timer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #ifndef BX_TIMER_H_HEADER_GUARD 7 | #define BX_TIMER_H_HEADER_GUARD 8 | 9 | #include "bx.h" 10 | 11 | namespace bx 12 | { 13 | /// 14 | int64_t getHPCounter(); 15 | 16 | /// 17 | int64_t getHPFrequency(); 18 | 19 | } // namespace bx 20 | 21 | #endif // BX_TIMER_H_HEADER_GUARD 22 | -------------------------------------------------------------------------------- /include/bx/url.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #ifndef BX_URL_H_HEADER_GUARD 7 | #define BX_URL_H_HEADER_GUARD 8 | 9 | #include "string.h" 10 | 11 | namespace bx 12 | { 13 | /// 14 | class UrlView 15 | { 16 | public: 17 | enum Enum 18 | { 19 | Scheme, 20 | UserName, 21 | Password, 22 | Host, 23 | Port, 24 | Path, 25 | Query, 26 | Fragment, 27 | 28 | Count 29 | }; 30 | 31 | /// 32 | UrlView(); 33 | 34 | /// 35 | void clear(); 36 | 37 | /// 38 | bool parse(const StringView& _url); 39 | 40 | /// 41 | const StringView& get(Enum _token) const; 42 | 43 | private: 44 | StringView m_tokens[Count]; 45 | }; 46 | 47 | /// 48 | void urlEncode(char* _out, uint32_t _max, const StringView& _str); 49 | 50 | } // namespace bx 51 | 52 | #endif // BX_URL_H_HEADER_GUARD 53 | -------------------------------------------------------------------------------- /include/compat/freebsd/dirent.h: -------------------------------------------------------------------------------- 1 | #include 2 | -------------------------------------------------------------------------------- /include/compat/freebsd/malloc.h: -------------------------------------------------------------------------------- 1 | #include 2 | -------------------------------------------------------------------------------- /include/compat/freebsd/signal.h: -------------------------------------------------------------------------------- 1 | #if defined(__GLIBC__) 2 | # include_next 3 | #else 4 | # include 5 | #endif 6 | -------------------------------------------------------------------------------- /include/compat/ios/malloc.h: -------------------------------------------------------------------------------- 1 | #include 2 | -------------------------------------------------------------------------------- /include/compat/linux/sal.h: -------------------------------------------------------------------------------- 1 | #include "../mingw/salieri.h" 2 | -------------------------------------------------------------------------------- /include/compat/mingw/dirent.h: -------------------------------------------------------------------------------- 1 | // BK - MinGW dirent is super broken, using MSVC compatibility one... 2 | #ifndef _DIRENT_H_ 3 | # define _DIRENT_H_ 4 | # include "../msvc/dirent.h" 5 | #endif // _DIRENT_H_ 6 | -------------------------------------------------------------------------------- /include/compat/mingw/sal.h: -------------------------------------------------------------------------------- 1 | #include "salieri.h" 2 | -------------------------------------------------------------------------------- /include/compat/mingw/specstrings_strict.h: -------------------------------------------------------------------------------- 1 | #define __reserved 2 | -------------------------------------------------------------------------------- /include/compat/mingw/specstrings_undef.h: -------------------------------------------------------------------------------- 1 | #undef __reserved 2 | 3 | -------------------------------------------------------------------------------- /include/compat/osx/malloc.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | -------------------------------------------------------------------------------- /include/tinystl/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2012-2018 Matthew Endsley 2 | All rights reserved 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted providing that the following conditions 6 | are met: 7 | 1. Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 | ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 17 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 21 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 22 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 23 | POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /include/tinystl/allocator.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2012-2018 Matthew Endsley 3 | * All rights reserved 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted providing that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 18 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 23 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef TINYSTL_ALLOCATOR_H 28 | #define TINYSTL_ALLOCATOR_H 29 | 30 | #include 31 | 32 | namespace tinystl { 33 | 34 | struct allocator { 35 | static void* static_allocate(size_t bytes) { 36 | return operator new(bytes); 37 | } 38 | 39 | static void static_deallocate(void* ptr, size_t /*bytes*/) { 40 | operator delete(ptr); 41 | } 42 | }; 43 | } 44 | 45 | #ifndef TINYSTL_ALLOCATOR 46 | # define TINYSTL_ALLOCATOR ::tinystl::allocator 47 | #endif 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /include/tinystl/hash.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2012-2018 Matthew Endsley 3 | * All rights reserved 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted providing that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 18 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 23 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef TINYSTL_STRINGHASH_H 28 | #define TINYSTL_STRINGHASH_H 29 | 30 | #include 31 | 32 | namespace tinystl { 33 | 34 | static inline size_t hash_string(const char* str, size_t len) { 35 | // Implementation of sdbm a public domain string hash from Ozan Yigit 36 | // see: http://www.eecs.harvard.edu/margo/papers/usenix91/paper.ps 37 | 38 | size_t hash = 0; 39 | typedef const char* pointer; 40 | for (pointer it = str, end = str + len; it != end; ++it) 41 | hash = *it + (hash << 6) + (hash << 16) - hash; 42 | 43 | return hash; 44 | } 45 | 46 | template 47 | inline size_t hash(const T& value) { 48 | const size_t asint = (size_t)value; 49 | return hash_string((const char*)&asint, sizeof(asint)); 50 | } 51 | } 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /include/tinystl/new.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2012-2018 Matthew Endsley 3 | * All rights reserved 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted providing that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 18 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 23 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef TINYSTL_NEW_H 28 | #define TINYSTL_NEW_H 29 | 30 | #include 31 | 32 | namespace tinystl { 33 | 34 | struct placeholder {}; 35 | } 36 | 37 | inline void* operator new(size_t, tinystl::placeholder, void* ptr) { 38 | return ptr; 39 | } 40 | 41 | inline void operator delete(void*, tinystl::placeholder, void*) throw() {} 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /include/tinystl/stddef.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2012-2018 Matthew Endsley 3 | * All rights reserved 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted providing that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 18 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 23 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef TINYSTL_STDDEF_H 28 | #define TINYSTL_STDDEF_H 29 | 30 | #if defined(_WIN64) 31 | typedef long long unsigned int size_t; 32 | typedef long long int ptrdiff_t; 33 | #elif defined(_WIN32) 34 | typedef unsigned int size_t; 35 | typedef int ptrdiff_t; 36 | #elif defined (__linux__) && defined(__SIZE_TYPE__) && defined(__PTRDIFF_TYPE__) 37 | typedef __SIZE_TYPE__ size_t; 38 | typedef __PTRDIFF_TYPE__ ptrdiff_t; 39 | #else 40 | # include 41 | #endif 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /include/tinystl/string_view.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2012-1017 Matthew Endsley 3 | * All rights reserved 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted providing that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 18 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 23 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef TINYSTL_STRING_VIEW_H 28 | #define TINYSTL_STRING_VIEW_H 29 | 30 | #include 31 | 32 | namespace tinystl { 33 | 34 | class string_view 35 | { 36 | public: 37 | typedef char value_type; 38 | typedef char* pointer; 39 | typedef const char* const_pointer; 40 | typedef char& reference; 41 | typedef const char& const_reference; 42 | typedef const_pointer iterator; 43 | typedef const_pointer const_iterator; 44 | typedef size_t size_type; 45 | typedef ptrdiff_t difference_type; 46 | 47 | static constexpr size_type npos = size_type(-1); 48 | 49 | constexpr string_view(); 50 | constexpr string_view(const char* s, size_type count); 51 | constexpr string_view(const char* s); 52 | constexpr string_view(const string_view&) = default; 53 | string_view& operator=(const string_view&) = default; 54 | 55 | constexpr const char* data() const; 56 | constexpr char operator[](size_type pos) const; 57 | constexpr size_type size() const; 58 | constexpr bool empty() const; 59 | constexpr iterator begin() const; 60 | constexpr const_iterator cbegin() const; 61 | constexpr iterator end() const; 62 | constexpr const_iterator cend() const; 63 | constexpr string_view substr(size_type pos = 0, size_type count = npos) const; 64 | constexpr void swap(string_view& v); 65 | 66 | private: 67 | string_view(decltype(nullptr)) = delete; 68 | 69 | static constexpr size_type strlen(const char*); 70 | 71 | const char* m_str; 72 | size_type m_size; 73 | }; 74 | 75 | constexpr string_view::string_view() 76 | : m_str(nullptr) 77 | , m_size(0) 78 | { 79 | } 80 | 81 | constexpr string_view::string_view(const char* s, size_type count) 82 | : m_str(s) 83 | , m_size(count) 84 | { 85 | } 86 | 87 | constexpr string_view::string_view(const char* s) 88 | : m_str(s) 89 | , m_size(strlen(s)) 90 | { 91 | } 92 | 93 | constexpr const char* string_view::data() const { 94 | return m_str; 95 | } 96 | 97 | constexpr char string_view::operator[](size_type pos) const { 98 | return m_str[pos]; 99 | } 100 | 101 | constexpr string_view::size_type string_view::size() const { 102 | return m_size; 103 | } 104 | 105 | constexpr bool string_view::empty() const { 106 | return 0 == m_size; 107 | } 108 | 109 | constexpr string_view::iterator string_view::begin() const { 110 | return m_str; 111 | } 112 | 113 | constexpr string_view::const_iterator string_view::cbegin() const { 114 | return m_str; 115 | } 116 | 117 | constexpr string_view::iterator string_view::end() const { 118 | return m_str + m_size; 119 | } 120 | 121 | constexpr string_view::const_iterator string_view::cend() const { 122 | return m_str + m_size; 123 | } 124 | 125 | constexpr string_view string_view::substr(size_type pos, size_type count) const { 126 | return string_view(m_str + pos, npos == count ? m_size - pos : count); 127 | } 128 | 129 | constexpr void string_view::swap(string_view& v) { 130 | const char* strtmp = m_str; 131 | size_type sizetmp = m_size; 132 | m_str = v.m_str; 133 | m_size = v.m_size; 134 | v.m_str = strtmp; 135 | v.m_size = sizetmp; 136 | } 137 | 138 | constexpr string_view::size_type string_view::strlen(const char* s) { 139 | for (size_t len = 0; ; ++len) { 140 | if (0 == s[len]) { 141 | return len; 142 | } 143 | } 144 | } 145 | } 146 | 147 | #endif // TINYSTL_STRING_VIEW_H 148 | -------------------------------------------------------------------------------- /include/tinystl/traits.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2012-2018 Matthew Endsley 3 | * All rights reserved 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted providing that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 18 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 23 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef TINYSTL_TRAITS_H 28 | #define TINYSTL_TRAITS_H 29 | 30 | #include 31 | 32 | #if defined(__GNUC__) 33 | # define TINYSTL_TRY_POD_OPTIMIZATION(t) __is_pod(t) 34 | #elif defined(_MSC_VER) 35 | # define TINYSTL_TRY_POD_OPTIMIZATION(t) (!__is_class(t) || __is_pod(t)) 36 | #else 37 | # define TINYSTL_TRY_POD_OPTIMIZATION(t) false 38 | #endif 39 | 40 | namespace tinystl { 41 | template struct pod_traits {}; 42 | 43 | template struct swap_holder; 44 | 45 | template 46 | static inline void move_impl(T& a, T& b, ...) { 47 | a = b; 48 | } 49 | 50 | template 51 | static inline void move_impl(T& a, T& b, T*, swap_holder* = 0) { 52 | a.swap(b); 53 | } 54 | 55 | template 56 | static inline void move(T& a, T&b) { 57 | move_impl(a, b, (T*)0); 58 | } 59 | 60 | template 61 | static inline void move_construct_impl(T* a, T& b, ...) { 62 | new(placeholder(), a) T(b); 63 | } 64 | 65 | template 66 | static inline void move_construct_impl(T* a, T& b, void*, swap_holder* = 0) { 67 | // If your type T does not have a default constructor, simply insert: 68 | // struct tinystl_nomove_construct; 69 | // in the class definition 70 | new(placeholder(), a) T; 71 | a->swap(b); 72 | } 73 | 74 | template 75 | static inline void move_construct_impl(T* a, T& b, T*, typename T::tinystl_nomove_construct* = 0) { 76 | new(placeholder(), a) T(b); 77 | } 78 | 79 | template 80 | static inline void move_construct(T* a, T& b) { 81 | move_construct_impl(a, b, (T*)0); 82 | } 83 | 84 | template 85 | struct remove_reference { 86 | typedef T type; 87 | }; 88 | 89 | template 90 | struct remove_reference { 91 | typedef T type; 92 | }; 93 | 94 | template 95 | struct remove_reference { 96 | typedef T type; 97 | }; 98 | 99 | template 100 | struct remove_const { 101 | typedef T type; 102 | }; 103 | 104 | template 105 | struct remove_const { 106 | typedef T type; 107 | }; 108 | 109 | template 110 | struct remove_const { 111 | typedef T& type; 112 | }; 113 | 114 | template 115 | struct remove_const { 116 | typedef T&& type; 117 | }; 118 | 119 | template 120 | struct remove_const_reference { 121 | typedef typename remove_reference::type>::type type; 122 | }; 123 | } 124 | 125 | #endif 126 | -------------------------------------------------------------------------------- /scripts/bin2c.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | -- License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | -- 5 | 6 | project "bin2c" 7 | kind "ConsoleApp" 8 | 9 | files { 10 | "../tools/bin2c/**.cpp", 11 | "../tools/bin2c/**.h", 12 | } 13 | 14 | using_bx() 15 | 16 | configuration { "mingw-*" } 17 | targetextension ".exe" 18 | 19 | configuration { "linux-*" } 20 | links { 21 | "pthread", 22 | } 23 | configuration { "osx-*" } 24 | linkoptions { 25 | "-framework Foundation" 26 | } 27 | 28 | configuration { "vs20* or mingw*" } 29 | links { 30 | "psapi", 31 | } 32 | 33 | configuration {} 34 | 35 | strip() 36 | -------------------------------------------------------------------------------- /scripts/bx.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | -- License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | -- 5 | 6 | local function userdefines() 7 | local defines = {} 8 | local BX_CONFIG = os.getenv("BX_CONFIG") 9 | if BX_CONFIG then 10 | for def in BX_CONFIG:gmatch "[^%s:]+" do 11 | table.insert(defines, "BX_CONFIG_" .. def) 12 | end 13 | end 14 | 15 | return defines 16 | end 17 | 18 | function using_bx() 19 | includedirs { 20 | path.join(BX_DIR, "include"), 21 | } 22 | 23 | links { 24 | "bx", 25 | } 26 | 27 | configuration { "Debug" } 28 | defines { 29 | "BX_CONFIG_DEBUG=1", 30 | } 31 | 32 | configuration { "Release" } 33 | defines { 34 | "BX_CONFIG_DEBUG=0", 35 | } 36 | 37 | configuration {} 38 | end 39 | 40 | project "bx" 41 | kind "StaticLib" 42 | 43 | includedirs { 44 | path.join(BX_DIR, "include"), 45 | path.join(BX_DIR, "3rdparty"), 46 | } 47 | 48 | files { 49 | path.join(BX_DIR, "include/**.h"), 50 | path.join(BX_DIR, "include/**.inl"), 51 | path.join(BX_DIR, "src/**.cpp"), 52 | path.join(BX_DIR, "scripts/**.natvis"), 53 | } 54 | 55 | defines (userdefines()) 56 | 57 | configuration { "linux-*" } 58 | buildoptions { 59 | "-fPIC", 60 | } 61 | 62 | configuration {} 63 | 64 | if _OPTIONS["with-amalgamated"] then 65 | excludes { 66 | path.join(BX_DIR, "src/allocator.cpp"), 67 | path.join(BX_DIR, "src/bounds.cpp"), 68 | path.join(BX_DIR, "src/bx.cpp"), 69 | path.join(BX_DIR, "src/commandline.cpp"), 70 | path.join(BX_DIR, "src/crtnone.cpp"), 71 | path.join(BX_DIR, "src/debug.cpp"), 72 | path.join(BX_DIR, "src/dtoa.cpp"), 73 | path.join(BX_DIR, "src/easing.cpp"), 74 | path.join(BX_DIR, "src/file.cpp"), 75 | path.join(BX_DIR, "src/filepath.cpp"), 76 | path.join(BX_DIR, "src/hash.cpp"), 77 | path.join(BX_DIR, "src/math.cpp"), 78 | path.join(BX_DIR, "src/mutex.cpp"), 79 | path.join(BX_DIR, "src/os.cpp"), 80 | path.join(BX_DIR, "src/process.cpp"), 81 | path.join(BX_DIR, "src/semaphore.cpp"), 82 | path.join(BX_DIR, "src/settings.cpp"), 83 | path.join(BX_DIR, "src/sort.cpp"), 84 | path.join(BX_DIR, "src/string.cpp"), 85 | path.join(BX_DIR, "src/thread.cpp"), 86 | path.join(BX_DIR, "src/timer.cpp"), 87 | path.join(BX_DIR, "src/url.cpp"), 88 | } 89 | else 90 | excludes { 91 | path.join(BX_DIR, "src/amalgamated.**"), 92 | } 93 | end 94 | 95 | configuration { "Debug" } 96 | defines { 97 | "BX_CONFIG_DEBUG=1", 98 | } 99 | 100 | configuration { "Release" } 101 | defines { 102 | "BX_CONFIG_DEBUG=0", 103 | } 104 | 105 | configuration {} 106 | -------------------------------------------------------------------------------- /scripts/bx.natvis: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {m_ptr,[m_len]s8} 5 | m_ptr,[m_len]s8 6 | 7 | m_ptr,[m_len] 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /scripts/genie.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | -- License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | -- 5 | 6 | newoption { 7 | trigger = "with-amalgamated", 8 | description = "Enable amalgamated build.", 9 | } 10 | 11 | newoption { 12 | trigger = "with-crtnone", 13 | description = "Enable build without CRT.", 14 | } 15 | 16 | solution "bx" 17 | configurations { 18 | "Debug", 19 | "Release", 20 | } 21 | 22 | platforms { 23 | "x32", 24 | "x64", 25 | "Native", -- for targets where bitness is not specified 26 | } 27 | 28 | language "C++" 29 | 30 | BX_DIR = path.getabsolute("..") 31 | BX_BUILD_DIR = path.join(BX_DIR, ".build") 32 | BX_THIRD_PARTY_DIR = path.join(BX_DIR, "3rdparty") 33 | 34 | dofile "toolchain.lua" 35 | toolchain(BX_BUILD_DIR, BX_THIRD_PARTY_DIR) 36 | 37 | function copyLib() 38 | end 39 | 40 | dofile "bx.lua" 41 | dofile "bin2c.lua" 42 | 43 | project "bx.test" 44 | kind "ConsoleApp" 45 | 46 | debugdir (path.join(BX_DIR, "tests")) 47 | 48 | flags { 49 | -- "FatalWarnings", 50 | } 51 | 52 | removeflags { 53 | "NoExceptions", 54 | } 55 | 56 | includedirs { 57 | BX_THIRD_PARTY_DIR, 58 | } 59 | 60 | files { 61 | path.join(BX_DIR, "3rdparty/catch/catch_amalgamated.cpp"), 62 | path.join(BX_DIR, "tests/*_test.cpp"), 63 | path.join(BX_DIR, "tests/*.h"), 64 | path.join(BX_DIR, "tests/dbg.*"), 65 | } 66 | 67 | using_bx() 68 | 69 | defines { 70 | "CATCH_AMALGAMATED_CUSTOM_MAIN", 71 | } 72 | 73 | configuration { "vs* or mingw*" } 74 | links { 75 | "psapi", 76 | } 77 | 78 | configuration { "android*" } 79 | targetextension ".so" 80 | linkoptions { 81 | "-shared", 82 | } 83 | 84 | configuration { "linux-*" } 85 | links { 86 | "pthread", 87 | } 88 | 89 | configuration { "ios*" } 90 | linkoptions { 91 | "-framework CoreFoundation", 92 | "-framework Foundation", 93 | } 94 | 95 | configuration { "osx*" } 96 | links { 97 | "Cocoa.framework", 98 | } 99 | 100 | configuration { "wasm" } 101 | buildoptions { 102 | "-fwasm-exceptions", 103 | } 104 | linkoptions { 105 | "-fwasm-exceptions", 106 | "-s STACK_SIZE=262144", 107 | } 108 | 109 | configuration {} 110 | 111 | strip() 112 | 113 | project "bx.bench" 114 | kind "ConsoleApp" 115 | 116 | debugdir (path.join(BX_DIR, "tests")) 117 | 118 | includedirs { 119 | path.join(BX_DIR, "include"), 120 | BX_THIRD_PARTY_DIR, 121 | } 122 | 123 | files { 124 | path.join(BX_DIR, "tests/*_bench.cpp"), 125 | path.join(BX_DIR, "tests/*_bench.h"), 126 | path.join(BX_DIR, "tests/dbg.*"), 127 | } 128 | 129 | using_bx() 130 | 131 | configuration { "vs* or mingw*" } 132 | links { 133 | "psapi", 134 | } 135 | 136 | configuration { "android*" } 137 | targetextension ".so" 138 | linkoptions { 139 | "-shared", 140 | } 141 | 142 | configuration { "linux-*" } 143 | links { 144 | "pthread", 145 | } 146 | 147 | configuration { "osx*" } 148 | links { 149 | "Cocoa.framework", 150 | } 151 | 152 | configuration {} 153 | 154 | strip() 155 | -------------------------------------------------------------------------------- /scripts/tinystl.natvis: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{ size={last - first} }} 5 | 6 | last - first 7 | capacity - first 8 | 9 | last - first 10 | first 11 | 12 | 13 | 14 | 15 | 16 | {{ size={m_buffer.last - m_buffer.first} }} 17 | 18 | m_buffer 19 | 20 | 21 | 22 | 23 | {{ size={m_size} }} 24 | 25 | m_size 26 | m_buckets.last - m_buckets.first 27 | 28 | *m_buckets.first 29 | next 30 | first 31 | 32 | 33 | 34 | 35 | 36 | {{ size={m_size} }} 37 | 38 | m_size 39 | m_buckets.last - m_buckets.first 40 | 41 | *m_buckets.first 42 | next 43 | second 44 | 45 | 46 | 47 | 48 | 49 | {m_first,[m_last - m_first]na} 50 | m_first,[m_last - m_first]na 51 | 52 | m_last - m_first 53 | m_capacity - m_first 54 | 55 | m_last - m_first 56 | m_first 57 | 58 | 59 | 60 | 61 | 62 | {m_str,[m_size]na} 63 | m_str,[m_size]na 64 | 65 | m_size 66 | 67 | m_size 68 | m_str 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /scripts/update_tinystl.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -eux 2 | 3 | if [ $# != 1 ]; then 4 | echo "Usage: $0 " 5 | exit 1 6 | fi 7 | 8 | SRC_DIR=$1 9 | DST_DIR="include/tinystl" 10 | 11 | pushd $(dirname $0)/.. 12 | 13 | cp $SRC_DIR/include/TINYSTL/*.h $DST_DIR/ 14 | find $DST_DIR -iname "*.h" -exec sed --in-place 's/ 7 | 8 | #include 9 | 10 | #ifndef BX_CONFIG_ALLOCATOR_NATURAL_ALIGNMENT 11 | # define BX_CONFIG_ALLOCATOR_NATURAL_ALIGNMENT 8 12 | #endif // BX_CONFIG_ALLOCATOR_NATURAL_ALIGNMENT 13 | 14 | namespace bx 15 | { 16 | DefaultAllocator::DefaultAllocator() 17 | { 18 | } 19 | 20 | DefaultAllocator::~DefaultAllocator() 21 | { 22 | } 23 | 24 | void* DefaultAllocator::realloc(void* _ptr, size_t _size, size_t _align, const char* _filePath, uint32_t _line) 25 | { 26 | if (0 == _size) 27 | { 28 | if (NULL != _ptr) 29 | { 30 | if (BX_CONFIG_ALLOCATOR_NATURAL_ALIGNMENT >= _align) 31 | { 32 | ::free(_ptr); 33 | return NULL; 34 | } 35 | 36 | # if BX_COMPILER_MSVC 37 | BX_UNUSED(_filePath, _line); 38 | _aligned_free(_ptr); 39 | # else 40 | alignedFree(this, _ptr, _align, Location(_filePath, _line) ); 41 | # endif // BX_ 42 | } 43 | 44 | return NULL; 45 | } 46 | else if (NULL == _ptr) 47 | { 48 | if (BX_CONFIG_ALLOCATOR_NATURAL_ALIGNMENT >= _align) 49 | { 50 | return ::malloc(_size); 51 | } 52 | 53 | # if BX_COMPILER_MSVC 54 | BX_UNUSED(_filePath, _line); 55 | return _aligned_malloc(_size, _align); 56 | # else 57 | return alignedAlloc(this, _size, _align, Location(_filePath, _line) ); 58 | # endif // BX_ 59 | } 60 | 61 | if (BX_CONFIG_ALLOCATOR_NATURAL_ALIGNMENT >= _align) 62 | { 63 | return ::realloc(_ptr, _size); 64 | } 65 | 66 | # if BX_COMPILER_MSVC 67 | BX_UNUSED(_filePath, _line); 68 | return _aligned_realloc(_ptr, _size, _align); 69 | # else 70 | return alignedRealloc(this, _ptr, _size, _align, Location(_filePath, _line) ); 71 | # endif // BX_ 72 | } 73 | 74 | } // namespace bx 75 | -------------------------------------------------------------------------------- /src/amalgamated.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #include "allocator.cpp" 7 | #include "bounds.cpp" 8 | #include "bx.cpp" 9 | #include "commandline.cpp" 10 | #include "crtnone.cpp" 11 | #include "debug.cpp" 12 | #include "dtoa.cpp" 13 | #include "easing.cpp" 14 | #include "file.cpp" 15 | #include "filepath.cpp" 16 | #include "hash.cpp" 17 | #include "math.cpp" 18 | #include "mutex.cpp" 19 | #include "os.cpp" 20 | #include "process.cpp" 21 | #include "semaphore.cpp" 22 | #include "settings.cpp" 23 | #include "sort.cpp" 24 | #include "string.cpp" 25 | #include "thread.cpp" 26 | #include "timer.cpp" 27 | #include "url.cpp" 28 | -------------------------------------------------------------------------------- /src/easing.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #include 7 | 8 | namespace bx 9 | { 10 | static const EaseFn s_easeFunc[] = 11 | { 12 | easeLinear, 13 | easeStep, 14 | easeSmoothStep, 15 | easeInQuad, 16 | easeOutQuad, 17 | easeInOutQuad, 18 | easeOutInQuad, 19 | easeInCubic, 20 | easeOutCubic, 21 | easeInOutCubic, 22 | easeOutInCubic, 23 | easeInQuart, 24 | easeOutQuart, 25 | easeInOutQuart, 26 | easeOutInQuart, 27 | easeInQuint, 28 | easeOutQuint, 29 | easeInOutQuint, 30 | easeOutInQuint, 31 | easeInSine, 32 | easeOutSine, 33 | easeInOutSine, 34 | easeOutInSine, 35 | easeInExpo, 36 | easeOutExpo, 37 | easeInOutExpo, 38 | easeOutInExpo, 39 | easeInCirc, 40 | easeOutCirc, 41 | easeInOutCirc, 42 | easeOutInCirc, 43 | easeInElastic, 44 | easeOutElastic, 45 | easeInOutElastic, 46 | easeOutInElastic, 47 | easeInBack, 48 | easeOutBack, 49 | easeInOutBack, 50 | easeOutInBack, 51 | easeInBounce, 52 | easeOutBounce, 53 | easeInOutBounce, 54 | easeOutInBounce, 55 | }; 56 | static_assert(BX_COUNTOF(s_easeFunc) == Easing::Count); 57 | 58 | EaseFn getEaseFunc(Easing::Enum _enum) 59 | { 60 | return s_easeFunc[_enum]; 61 | } 62 | 63 | } // namespace bx 64 | -------------------------------------------------------------------------------- /src/mutex.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #include 7 | 8 | #if BX_CONFIG_SUPPORTS_THREADING 9 | 10 | #if BX_CRT_NONE 11 | # include 12 | # include 13 | #elif BX_PLATFORM_ANDROID \ 14 | || BX_PLATFORM_LINUX \ 15 | || BX_PLATFORM_IOS \ 16 | || BX_PLATFORM_OSX \ 17 | || BX_PLATFORM_PS4 \ 18 | || BX_PLATFORM_RPI \ 19 | || BX_PLATFORM_NX \ 20 | || BX_PLATFORM_VISIONOS 21 | # include 22 | #elif BX_PLATFORM_WINDOWS \ 23 | || BX_PLATFORM_WINRT \ 24 | || BX_PLATFORM_XBOXONE 25 | # ifndef WIN32_LEAN_AND_MEAN 26 | # define WIN32_LEAN_AND_MEAN 27 | # endif // WIN32_LEAN_AND_MEAN 28 | # include 29 | # include 30 | #endif // BX_PLATFORM_ 31 | 32 | namespace bx 33 | { 34 | #if BX_CRT_NONE 35 | struct State 36 | { 37 | enum Enum 38 | { 39 | Unlocked, 40 | Locked, 41 | Contested, 42 | }; 43 | }; 44 | 45 | Mutex::Mutex() 46 | { 47 | static_assert(sizeof(int32_t) <= sizeof(m_internal) ); 48 | 49 | uint32_t* futex = (uint32_t*)m_internal; 50 | *futex = State::Unlocked; 51 | } 52 | 53 | Mutex::~Mutex() 54 | { 55 | } 56 | 57 | void Mutex::lock() 58 | { 59 | uint32_t* futex = (uint32_t*)m_internal; 60 | 61 | if (State::Unlocked == atomicCompareAndSwap(futex, State::Unlocked, State::Locked) ) 62 | { 63 | return; 64 | } 65 | 66 | while (State::Unlocked != atomicCompareAndSwap(futex, State::Locked, State::Contested) ) 67 | { 68 | crt0::futexWait(futex, State::Contested); 69 | } 70 | } 71 | 72 | void Mutex::unlock() 73 | { 74 | uint32_t* futex = (uint32_t*)m_internal; 75 | 76 | if (State::Contested == atomicCompareAndSwap(futex, State::Locked, State::Unlocked) ) 77 | { 78 | crt0::futexWake(futex, State::Locked); 79 | } 80 | } 81 | 82 | #else 83 | 84 | # if BX_PLATFORM_WINDOWS \ 85 | || BX_PLATFORM_XBOXONE \ 86 | || BX_PLATFORM_WINRT 87 | typedef CRITICAL_SECTION pthread_mutex_t; 88 | typedef unsigned pthread_mutexattr_t; 89 | 90 | inline int pthread_mutex_lock(pthread_mutex_t* _mutex) 91 | { 92 | EnterCriticalSection(_mutex); 93 | return 0; 94 | } 95 | 96 | inline int pthread_mutex_unlock(pthread_mutex_t* _mutex) 97 | { 98 | LeaveCriticalSection(_mutex); 99 | return 0; 100 | } 101 | 102 | inline int pthread_mutex_trylock(pthread_mutex_t* _mutex) 103 | { 104 | return TryEnterCriticalSection(_mutex) ? 0 : EBUSY; 105 | } 106 | 107 | inline int pthread_mutex_init(pthread_mutex_t* _mutex, pthread_mutexattr_t* /*_attr*/) 108 | { 109 | # if BX_PLATFORM_WINRT 110 | InitializeCriticalSectionEx(_mutex, 4000, 0); // docs recommend 4000 spincount as sane default 111 | # else 112 | InitializeCriticalSection(_mutex); 113 | # endif // BX_PLATFORM_ 114 | return 0; 115 | } 116 | 117 | inline int pthread_mutex_destroy(pthread_mutex_t* _mutex) 118 | { 119 | DeleteCriticalSection(_mutex); 120 | return 0; 121 | } 122 | # endif // BX_PLATFORM_ 123 | 124 | Mutex::Mutex() 125 | { 126 | static_assert(sizeof(pthread_mutex_t) <= sizeof(m_internal) ); 127 | 128 | pthread_mutexattr_t attr; 129 | 130 | # if BX_PLATFORM_WINDOWS \ 131 | || BX_PLATFORM_XBOXONE \ 132 | || BX_PLATFORM_WINRT 133 | # else 134 | pthread_mutexattr_init(&attr); 135 | pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); 136 | # endif // BX_PLATFORM_ 137 | 138 | pthread_mutex_t* handle = (pthread_mutex_t*)m_internal; 139 | pthread_mutex_init(handle, &attr); 140 | } 141 | 142 | Mutex::~Mutex() 143 | { 144 | pthread_mutex_t* handle = (pthread_mutex_t*)m_internal; 145 | pthread_mutex_destroy(handle); 146 | } 147 | 148 | void Mutex::lock() 149 | { 150 | pthread_mutex_t* handle = (pthread_mutex_t*)m_internal; 151 | pthread_mutex_lock(handle); 152 | } 153 | 154 | void Mutex::unlock() 155 | { 156 | pthread_mutex_t* handle = (pthread_mutex_t*)m_internal; 157 | pthread_mutex_unlock(handle); 158 | } 159 | #endif // BX_CRT_NONE 160 | 161 | } // namespace bx 162 | 163 | #else 164 | 165 | namespace bx 166 | { 167 | Mutex::Mutex() 168 | { 169 | } 170 | 171 | Mutex::~Mutex() 172 | { 173 | } 174 | 175 | void Mutex::lock() 176 | { 177 | } 178 | 179 | void Mutex::unlock() 180 | { 181 | } 182 | 183 | } // namespace bx 184 | 185 | #endif // BX_CONFIG_SUPPORTS_THREADING 186 | -------------------------------------------------------------------------------- /src/process.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #include 7 | 8 | #include 9 | 10 | #ifndef BX_CONFIG_CRT_PROCESS 11 | # define BX_CONFIG_CRT_PROCESS !(0 \ 12 | || BX_CRT_NONE \ 13 | || BX_PLATFORM_EMSCRIPTEN \ 14 | || BX_PLATFORM_PS4 \ 15 | || BX_PLATFORM_WINRT \ 16 | || BX_PLATFORM_XBOXONE \ 17 | ) 18 | #endif // BX_CONFIG_CRT_PROCESS 19 | 20 | namespace bx 21 | { 22 | #if BX_CONFIG_CRT_PROCESS 23 | 24 | #if BX_CRT_MSVC 25 | # define popen _popen 26 | # define pclose _pclose 27 | #endif // BX_CRT_MSVC 28 | 29 | ProcessReader::ProcessReader() 30 | : m_file(NULL) 31 | { 32 | } 33 | 34 | ProcessReader::~ProcessReader() 35 | { 36 | BX_ASSERT(NULL == m_file, "Process not closed!"); 37 | } 38 | 39 | bool ProcessReader::open(const FilePath& _filePath, const StringView& _args, Error* _err) 40 | { 41 | BX_ASSERT(NULL != _err, "Reader/Writer interface calling functions must handle errors."); 42 | 43 | if (NULL != m_file) 44 | { 45 | BX_ERROR_SET(_err, kErrorReaderWriterAlreadyOpen, "ProcessReader: File is already open."); 46 | return false; 47 | } 48 | 49 | char tmp[kMaxFilePath*2] = "\""; 50 | strCat(tmp, BX_COUNTOF(tmp), _filePath); 51 | strCat(tmp, BX_COUNTOF(tmp), "\" "); 52 | strCat(tmp, BX_COUNTOF(tmp), _args); 53 | 54 | m_file = popen(tmp, "r"); 55 | if (NULL == m_file) 56 | { 57 | BX_ERROR_SET(_err, kErrorReaderWriterOpen, "ProcessReader: Failed to open process."); 58 | return false; 59 | } 60 | 61 | return true; 62 | } 63 | 64 | void ProcessReader::close() 65 | { 66 | BX_ASSERT(NULL != m_file, "Process not open!"); 67 | FILE* file = (FILE*)m_file; 68 | m_exitCode = pclose(file); 69 | m_file = NULL; 70 | } 71 | 72 | int32_t ProcessReader::read(void* _data, int32_t _size, Error* _err) 73 | { 74 | BX_ASSERT(NULL != _err, "Reader/Writer interface calling functions must handle errors."); BX_UNUSED(_err); 75 | 76 | FILE* file = (FILE*)m_file; 77 | int32_t size = (int32_t)fread(_data, 1, _size, file); 78 | if (size != _size) 79 | { 80 | if (0 != feof(file) ) 81 | { 82 | BX_ERROR_SET(_err, kErrorReaderWriterEof, "ProcessReader: EOF."); 83 | } 84 | else if (0 != ferror(file) ) 85 | { 86 | BX_ERROR_SET(_err, kErrorReaderWriterRead, "ProcessReader: read error."); 87 | } 88 | 89 | return size >= 0 ? size : 0; 90 | } 91 | 92 | return size; 93 | } 94 | 95 | int32_t ProcessReader::getExitCode() const 96 | { 97 | return m_exitCode; 98 | } 99 | 100 | ProcessWriter::ProcessWriter() 101 | : m_file(NULL) 102 | { 103 | } 104 | 105 | ProcessWriter::~ProcessWriter() 106 | { 107 | BX_ASSERT(NULL == m_file, "Process not closed!"); 108 | } 109 | 110 | bool ProcessWriter::open(const FilePath& _filePath, const StringView& _args, Error* _err) 111 | { 112 | BX_ASSERT(NULL != _err, "Reader/Writer interface calling functions must handle errors."); 113 | 114 | if (NULL != m_file) 115 | { 116 | BX_ERROR_SET(_err, kErrorReaderWriterAlreadyOpen, "ProcessWriter: File is already open."); 117 | return false; 118 | } 119 | 120 | char tmp[kMaxFilePath*2] = "\""; 121 | strCat(tmp, BX_COUNTOF(tmp), _filePath); 122 | strCat(tmp, BX_COUNTOF(tmp), "\" "); 123 | strCat(tmp, BX_COUNTOF(tmp), _args); 124 | 125 | m_file = popen(tmp, "w"); 126 | if (NULL == m_file) 127 | { 128 | BX_ERROR_SET(_err, kErrorReaderWriterOpen, "ProcessWriter: Failed to open process."); 129 | return false; 130 | } 131 | 132 | return true; 133 | } 134 | 135 | void ProcessWriter::close() 136 | { 137 | BX_ASSERT(NULL != m_file, "Process not open!"); 138 | FILE* file = (FILE*)m_file; 139 | m_exitCode = pclose(file); 140 | m_file = NULL; 141 | } 142 | 143 | int32_t ProcessWriter::write(const void* _data, int32_t _size, Error* _err) 144 | { 145 | BX_ASSERT(NULL != _err, "Reader/Writer interface calling functions must handle errors."); BX_UNUSED(_err); 146 | 147 | FILE* file = (FILE*)m_file; 148 | int32_t size = (int32_t)fwrite(_data, 1, _size, file); 149 | if (size != _size) 150 | { 151 | if (0 != ferror(file) ) 152 | { 153 | BX_ERROR_SET(_err, kErrorReaderWriterWrite, "ProcessWriter: write error."); 154 | } 155 | 156 | return size >= 0 ? size : 0; 157 | } 158 | 159 | return size; 160 | } 161 | 162 | int32_t ProcessWriter::getExitCode() const 163 | { 164 | return m_exitCode; 165 | } 166 | #endif // BX_CONFIG_CRT_PROCESS 167 | 168 | } // namespace bx 169 | -------------------------------------------------------------------------------- /src/sort.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #include 7 | 8 | namespace bx 9 | { 10 | static void quickSortR(void* _pivot, void* _data, uint32_t _num, uint32_t _stride, const ComparisonFn _fn) 11 | { 12 | if (2 > _num) 13 | { 14 | return; 15 | } 16 | 17 | memCopy(_pivot, _data, _stride); 18 | 19 | uint8_t* data = (uint8_t*)_data; 20 | 21 | uint32_t ll = 0; 22 | uint32_t gg = 1; 23 | 24 | for (uint32_t ii = 1; ii < _num;) 25 | { 26 | int32_t result = _fn(&data[ii*_stride], _pivot); 27 | if (0 > result) 28 | { 29 | swap(&data[ll*_stride], &data[ii*_stride], _stride); 30 | ++ll; 31 | } 32 | else if (0 == result) 33 | { 34 | swap(&data[gg*_stride], &data[ii*_stride], _stride); 35 | ++gg; 36 | ++ii; 37 | } 38 | else 39 | { 40 | ++ii; 41 | } 42 | } 43 | 44 | quickSortR(_pivot, &data[0 ], ll, _stride, _fn); 45 | quickSortR(_pivot, &data[gg*_stride], _num-gg, _stride, _fn); 46 | } 47 | 48 | void quickSort(void* _data, uint32_t _num, uint32_t _stride, const ComparisonFn _fn) 49 | { 50 | uint8_t* pivot = (uint8_t*)BX_STACK_ALLOC(_stride); 51 | quickSortR(pivot, _data, _num, _stride, _fn); 52 | } 53 | 54 | bool isSorted(const void* _data, uint32_t _num, uint32_t _stride, const ComparisonFn _fn) 55 | { 56 | const uint8_t* data = (uint8_t*)_data; 57 | 58 | for (uint32_t ii = 1; ii < _num; ++ii) 59 | { 60 | int32_t result = _fn(&data[(ii-1)*_stride], &data[ii*_stride]); 61 | 62 | if (0 < result) 63 | { 64 | return false; 65 | } 66 | } 67 | 68 | return true; 69 | } 70 | 71 | uint32_t unique(void* _data, uint32_t _num, uint32_t _stride, const ComparisonFn _fn) 72 | { 73 | if (0 == _num) 74 | { 75 | return 0; 76 | } 77 | 78 | uint8_t* data = (uint8_t*)_data; 79 | 80 | uint32_t last = 0; 81 | 82 | for (uint32_t ii = 1; ii < _num; ++ii) 83 | { 84 | int32_t result = _fn(&data[last*_stride], &data[ii*_stride]); 85 | BX_ASSERT(0 >= result, "Performing unique on non-sorted array (ii %d, last %d)!", ii, last); 86 | 87 | if (0 > result) 88 | { 89 | last++; 90 | swap(&data[last*_stride], &data[ii*_stride], _stride); 91 | } 92 | } 93 | 94 | return last+1; 95 | } 96 | 97 | uint32_t lowerBound(const void* _key, const void* _data, uint32_t _num, uint32_t _stride, const ComparisonFn _fn) 98 | { 99 | uint32_t offset = 0; 100 | const uint8_t* data = (uint8_t*)_data; 101 | 102 | for (uint32_t ll = _num; offset < ll;) 103 | { 104 | const uint32_t idx = (offset + ll) / 2; 105 | 106 | int32_t result = _fn(_key, &data[idx * _stride]); 107 | 108 | if (result <= 0) 109 | { 110 | ll = idx; 111 | } 112 | else 113 | { 114 | offset = idx + 1; 115 | } 116 | } 117 | 118 | return offset; 119 | } 120 | 121 | uint32_t upperBound(const void* _key, const void* _data, uint32_t _num, uint32_t _stride, const ComparisonFn _fn) 122 | { 123 | uint32_t offset = 0; 124 | const uint8_t* data = (uint8_t*)_data; 125 | 126 | for (uint32_t ll = _num; offset < ll;) 127 | { 128 | const uint32_t idx = (offset + ll) / 2; 129 | 130 | int32_t result = _fn(_key, &data[idx * _stride]); 131 | 132 | if (result < 0) 133 | { 134 | ll = idx; 135 | } 136 | else 137 | { 138 | offset = idx + 1; 139 | } 140 | } 141 | 142 | return offset; 143 | } 144 | 145 | int32_t binarySearch(const void* _key, const void* _data, uint32_t _num, uint32_t _stride, const ComparisonFn _fn) 146 | { 147 | uint32_t offset = 0; 148 | const uint8_t* data = (uint8_t*)_data; 149 | 150 | for (uint32_t ll = _num; offset < ll;) 151 | { 152 | const uint32_t idx = (offset + ll) / 2; 153 | 154 | int32_t result = _fn(_key, &data[idx * _stride]); 155 | 156 | if (result < 0) 157 | { 158 | ll = idx; 159 | } 160 | else if (result > 0) 161 | { 162 | offset = idx + 1; 163 | } 164 | else 165 | { 166 | return idx; 167 | } 168 | } 169 | 170 | return ~offset; 171 | } 172 | 173 | } // namespace bx 174 | 175 | -------------------------------------------------------------------------------- /src/timer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #include 7 | 8 | #if BX_CRT_NONE 9 | # include 10 | #elif BX_PLATFORM_ANDROID 11 | # include // clock, clock_gettime 12 | #elif BX_PLATFORM_EMSCRIPTEN 13 | # include 14 | #elif BX_PLATFORM_WINDOWS || BX_PLATFORM_XBOXONE || BX_PLATFORM_WINRT 15 | # ifndef WIN32_LEAN_AND_MEAN 16 | # define WIN32_LEAN_AND_MEAN 17 | # endif // WIN32_LEAN_AND_MEAN 18 | # include 19 | #else 20 | # include // gettimeofday 21 | #endif // BX_PLATFORM_ 22 | 23 | namespace bx 24 | { 25 | int64_t getHPCounter() 26 | { 27 | #if BX_CRT_NONE 28 | int64_t i64 = crt0::getHPCounter(); 29 | #elif BX_PLATFORM_WINDOWS \ 30 | || BX_PLATFORM_XBOXONE \ 31 | || BX_PLATFORM_WINRT 32 | LARGE_INTEGER li; 33 | QueryPerformanceCounter(&li); 34 | int64_t i64 = li.QuadPart; 35 | #elif BX_PLATFORM_ANDROID 36 | struct timespec now; 37 | clock_gettime(CLOCK_MONOTONIC, &now); 38 | int64_t i64 = now.tv_sec*INT64_C(1000000000) + now.tv_nsec; 39 | #elif BX_PLATFORM_EMSCRIPTEN 40 | int64_t i64 = int64_t(1000.0f * emscripten_get_now() ); 41 | #elif !BX_PLATFORM_NONE 42 | struct timeval now; 43 | gettimeofday(&now, NULL); 44 | int64_t i64 = now.tv_sec*INT64_C(1000000) + now.tv_usec; 45 | #else 46 | BX_ASSERT(false, "Not implemented!"); 47 | int64_t i64 = UINT64_MAX; 48 | #endif // BX_PLATFORM_ 49 | return i64; 50 | } 51 | 52 | int64_t getHPFrequency() 53 | { 54 | #if BX_CRT_NONE 55 | return INT64_C(1000000000); 56 | #elif BX_PLATFORM_WINDOWS \ 57 | || BX_PLATFORM_XBOXONE \ 58 | || BX_PLATFORM_WINRT 59 | LARGE_INTEGER li; 60 | QueryPerformanceFrequency(&li); 61 | return li.QuadPart; 62 | #elif BX_PLATFORM_ANDROID 63 | return INT64_C(1000000000); 64 | #elif BX_PLATFORM_EMSCRIPTEN 65 | return INT64_C(1000000); 66 | #else 67 | return INT64_C(1000000); 68 | #endif // BX_PLATFORM_ 69 | } 70 | 71 | } // namespace bx 72 | -------------------------------------------------------------------------------- /src/url.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bnet#license-bsd-2-clause 4 | */ 5 | 6 | #include 7 | 8 | namespace bx 9 | { 10 | UrlView::UrlView() 11 | { 12 | } 13 | 14 | void UrlView::clear() 15 | { 16 | for (uint32_t ii = 0; ii < Count; ++ii) 17 | { 18 | m_tokens[ii].clear(); 19 | } 20 | } 21 | 22 | bool UrlView::parse(const StringView& _url) 23 | { 24 | clear(); 25 | 26 | const char* term = _url.getTerm(); 27 | StringView schemeEnd = strFind(_url, "://"); 28 | const char* hostStart = !schemeEnd.isEmpty() ? schemeEnd.getTerm() : _url.getPtr(); 29 | StringView path = strFind(StringView(hostStart, term), '/'); 30 | 31 | if (schemeEnd.isEmpty() 32 | && path.isEmpty() ) 33 | { 34 | return false; 35 | } 36 | 37 | if (!schemeEnd.isEmpty() 38 | && (path.isEmpty() || path.getPtr() > schemeEnd.getPtr() ) ) 39 | { 40 | const StringView scheme(_url.getPtr(), schemeEnd.getPtr() ); 41 | 42 | if (!isAlpha(scheme) ) 43 | { 44 | return false; 45 | } 46 | 47 | m_tokens[Scheme].set(scheme); 48 | } 49 | 50 | if (!path.isEmpty() ) 51 | { 52 | path.set(path.getPtr(), term); 53 | const StringView query = strFind(path, '?'); 54 | const StringView fragment = strFind(path, '#'); 55 | 56 | if (!fragment.isEmpty() 57 | && fragment.getPtr() < query.getPtr() ) 58 | { 59 | return false; 60 | } 61 | 62 | m_tokens[Path].set(path.getPtr() 63 | , !query.isEmpty() ? query.getPtr() 64 | : !fragment.isEmpty() ? fragment.getPtr() 65 | : term 66 | ); 67 | 68 | if (!query.isEmpty() ) 69 | { 70 | m_tokens[Query].set(query.getPtr()+1 71 | , !fragment.isEmpty() ? fragment.getPtr() 72 | : term 73 | ); 74 | } 75 | 76 | if (!fragment.isEmpty() ) 77 | { 78 | m_tokens[Fragment].set(fragment.getPtr()+1, term); 79 | } 80 | 81 | term = path.getPtr(); 82 | } 83 | 84 | const StringView userPassEnd = strFind(StringView(hostStart, term), '@'); 85 | const char* userPassStart = !userPassEnd.isEmpty() ? hostStart : NULL; 86 | hostStart = !userPassEnd.isEmpty() ? userPassEnd.getPtr()+1 : hostStart; 87 | const StringView portStart = strFind(StringView(hostStart, term), ':'); 88 | 89 | m_tokens[Host].set(hostStart, !portStart.isEmpty() ? portStart.getPtr() : term); 90 | 91 | if (!portStart.isEmpty()) 92 | { 93 | m_tokens[Port].set(portStart.getPtr()+1, term); 94 | } 95 | 96 | if (NULL != userPassStart) 97 | { 98 | StringView passStart = strFind(StringView(userPassStart, userPassEnd.getPtr() ), ':'); 99 | 100 | m_tokens[UserName].set(userPassStart 101 | , !passStart.isEmpty() ? passStart.getPtr() 102 | : userPassEnd.getPtr() 103 | ); 104 | 105 | if (!passStart.isEmpty() ) 106 | { 107 | m_tokens[Password].set(passStart.getPtr()+1, userPassEnd.getPtr() ); 108 | } 109 | } 110 | 111 | return true; 112 | } 113 | 114 | const StringView& UrlView::get(Enum _token) const 115 | { 116 | return m_tokens[_token]; 117 | } 118 | 119 | static char toHex(char _nible) 120 | { 121 | return "0123456789ABCDEF"[_nible&0xf]; 122 | } 123 | 124 | // https://secure.wikimedia.org/wikipedia/en/wiki/URL_encoding 125 | void urlEncode(char* _out, uint32_t _max, const StringView& _str) 126 | { 127 | _max--; // need space for zero terminator 128 | 129 | const char* str = _str.getPtr(); 130 | const char* term = _str.getTerm(); 131 | 132 | uint32_t ii = 0; 133 | for (char ch = *str++ 134 | ; str <= term && ii < _max 135 | ; ch = *str++ 136 | ) 137 | { 138 | if (isAlphaNum(ch) 139 | || ch == '-' 140 | || ch == '_' 141 | || ch == '.' 142 | || ch == '~') 143 | { 144 | _out[ii++] = ch; 145 | } 146 | else if (ii+3 < _max) 147 | { 148 | _out[ii++] = '%'; 149 | _out[ii++] = toHex(ch>>4); 150 | _out[ii++] = toHex(ch); 151 | } 152 | } 153 | 154 | _out[ii] = '\0'; 155 | } 156 | 157 | } // namespace bx 158 | -------------------------------------------------------------------------------- /tests/allocator_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #include "test.h" 7 | 8 | #include 9 | 10 | struct MockNonFreeingAllocator : public bx::AllocatorI 11 | { 12 | MockNonFreeingAllocator() 13 | : m_sbrk(1) 14 | { 15 | } 16 | 17 | ~MockNonFreeingAllocator() override 18 | { 19 | } 20 | 21 | void* realloc(void* _ptr, size_t _size, size_t _align, const char* _file, uint32_t _line) override 22 | { 23 | BX_ASSERT(_ptr == NULL, "MockNonFreeingAllocator can't realloc or free."); 24 | BX_ASSERT(m_sbrk + _size < BX_COUNTOF(m_storage), ""); 25 | BX_UNUSED(_ptr, _file, _line); 26 | 27 | const uintptr_t sbrk = bx::alignUp(m_sbrk, bx::max(int32_t(_align), 1) ); 28 | m_sbrk = sbrk + _size; 29 | 30 | return &m_storage[sbrk]; 31 | } 32 | 33 | uintptr_t m_sbrk; 34 | BX_ALIGN_DECL(256, uint8_t) m_storage[0x10000]; 35 | }; 36 | 37 | bool testAlignment(size_t _expected, void* _ptr) 38 | { 39 | bool aligned = bx::isAligned(_ptr, int32_t(_expected) ); 40 | // BX_TRACE("%p, %d", _ptr, _expected); 41 | BX_WARN(aligned, "%p not aligned to %d bytes.", _ptr, _expected); 42 | return aligned; 43 | } 44 | 45 | TEST_CASE("Allocator", "") 46 | { 47 | MockNonFreeingAllocator mnfa; 48 | 49 | REQUIRE(testAlignment(1, bx::alloc (&mnfa, 1, 1 ) ) ); 50 | REQUIRE(testAlignment(2, bx::alloc (&mnfa, 1, 2 ) ) ); 51 | REQUIRE(testAlignment(1, bx::alloc (&mnfa, 1, 1 ) ) ); 52 | REQUIRE(testAlignment(4, bx::alloc (&mnfa, 1, 4 ) ) ); 53 | REQUIRE(testAlignment(1, bx::alloc (&mnfa, 1, 1 ) ) ); 54 | REQUIRE(testAlignment(8, bx::alloc (&mnfa, 1, 8 ) ) ); 55 | REQUIRE(testAlignment(1, bx::alloc (&mnfa, 1, 1 ) ) ); 56 | REQUIRE(testAlignment(16, bx::alloc (&mnfa, 1, 16 ) ) ); 57 | REQUIRE(testAlignment(1, bx::alloc (&mnfa, 1, 1 ) ) ); 58 | REQUIRE(testAlignment(32, bx::alloc (&mnfa, 1, 32 ) ) ); 59 | REQUIRE(testAlignment(1, bx::alloc (&mnfa, 1, 1 ) ) ); 60 | REQUIRE(testAlignment(64, bx::alloc (&mnfa, 1, 64 ) ) ); 61 | REQUIRE(testAlignment(1, bx::alloc (&mnfa, 1, 1 ) ) ); 62 | REQUIRE(testAlignment(128, bx::alloc (&mnfa, 1, 128) ) ); 63 | 64 | REQUIRE(testAlignment(1, bx::alignedAlloc(&mnfa, 1, 1 ) ) ); 65 | REQUIRE(testAlignment(2, bx::alignedAlloc(&mnfa, 1, 2 ) ) ); 66 | REQUIRE(testAlignment(1, bx::alignedAlloc(&mnfa, 1, 1 ) ) ); 67 | REQUIRE(testAlignment(4, bx::alignedAlloc(&mnfa, 1, 4 ) ) ); 68 | REQUIRE(testAlignment(1, bx::alignedAlloc(&mnfa, 1, 1 ) ) ); 69 | REQUIRE(testAlignment(8, bx::alignedAlloc(&mnfa, 1, 8 ) ) ); 70 | REQUIRE(testAlignment(1, bx::alignedAlloc(&mnfa, 1, 1 ) ) ); 71 | REQUIRE(testAlignment(16, bx::alignedAlloc(&mnfa, 1, 16 ) ) ); 72 | REQUIRE(testAlignment(1, bx::alignedAlloc(&mnfa, 1, 1 ) ) ); 73 | REQUIRE(testAlignment(32, bx::alignedAlloc(&mnfa, 1, 32 ) ) ); 74 | REQUIRE(testAlignment(1, bx::alignedAlloc(&mnfa, 1, 1 ) ) ); 75 | REQUIRE(testAlignment(64, bx::alignedAlloc(&mnfa, 1, 64 ) ) ); 76 | REQUIRE(testAlignment(1, bx::alignedAlloc(&mnfa, 1, 1 ) ) ); 77 | REQUIRE(testAlignment(128, bx::alignedAlloc(&mnfa, 1, 128) ) ); 78 | } 79 | -------------------------------------------------------------------------------- /tests/atomic_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #include "test.h" 7 | #include 8 | 9 | TEST_CASE("atomic", "") 10 | { 11 | uint32_t test = 1337; 12 | uint32_t fetched; 13 | 14 | fetched = bx::atomicFetchAndAdd(&test, 52u); 15 | REQUIRE(fetched == 1337); 16 | REQUIRE(test == 1389); 17 | 18 | fetched = bx::atomicAddAndFetch(&test, 64u); 19 | REQUIRE(fetched == 1453); 20 | REQUIRE(test == 1453); 21 | 22 | fetched = bx::atomicFetchAndSub(&test, 64u); 23 | REQUIRE(fetched == 1453); 24 | REQUIRE(test == 1389); 25 | 26 | fetched = bx::atomicSubAndFetch(&test, 52u); 27 | REQUIRE(fetched == 1337); 28 | REQUIRE(test == 1337); 29 | 30 | fetched = bx::atomicFetchAndAddsat(&test, 52u, 1453u); 31 | REQUIRE(fetched == 1337); 32 | REQUIRE(test == 1389); 33 | 34 | fetched = bx::atomicFetchAndAddsat(&test, 1000u, 1453u); 35 | REQUIRE(fetched == 1389); 36 | REQUIRE(test == 1453); 37 | 38 | fetched = bx::atomicFetchAndSubsat(&test, 64u, 1337u); 39 | REQUIRE(fetched == 1453); 40 | REQUIRE(test == 1389); 41 | 42 | fetched = bx::atomicFetchAndSubsat(&test, 1000u, 1337u); 43 | REQUIRE(fetched == 1389); 44 | REQUIRE(test == 1337); 45 | 46 | } 47 | -------------------------------------------------------------------------------- /tests/cast_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #include "test.h" 7 | #include 8 | 9 | TEST_CASE("Bit cast", "[cast]") 10 | { 11 | STATIC_REQUIRE(0x4172f58bc0000000ull == bx::bitCast(19880124.0) ); 12 | STATIC_REQUIRE(0x3fe9000000000000ull == bx::bitCast(0.781250) ); 13 | STATIC_REQUIRE(19880124.0 == bx::bitCast(0x4172f58bc0000000ull) ); 14 | STATIC_REQUIRE(0.781250 == bx::bitCast(0x3fe9000000000000ull) ); 15 | } 16 | 17 | TEST_CASE("Narrow cast", "[cast]") 18 | { 19 | REQUIRE(127 == bx::narrowCast(int32_t(127) ) ); 20 | REQUIRE_ASSERTS(bx::narrowCast(int32_t(128) ) ); 21 | REQUIRE_ASSERTS(bx::narrowCast(uint32_t(128) ) ); 22 | REQUIRE(128 == bx::narrowCast(int32_t(128) ) ); 23 | } 24 | -------------------------------------------------------------------------------- /tests/crt_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #include "test.h" 7 | 8 | TEST_CASE("memSet", "") 9 | { 10 | char temp[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; 11 | 12 | bx::memSet(temp, 0, 0); 13 | REQUIRE(temp[0] == 1); 14 | 15 | bx::memSet(temp, 0, 5); 16 | REQUIRE(temp[0] == 0); 17 | REQUIRE(temp[1] == 0); 18 | REQUIRE(temp[2] == 0); 19 | REQUIRE(temp[3] == 0); 20 | REQUIRE(temp[4] == 0); 21 | REQUIRE(temp[5] == 6); 22 | } 23 | 24 | TEST_CASE("memMove", "") 25 | { 26 | const char* original = "xxxxabvgd"; 27 | char str[] = { 'x', 'x', 'x', 'x', 'a', 'b', 'v', 'g', 'd' }; 28 | 29 | bx::memMove(&str[4], &str[4], 0); 30 | REQUIRE(0 == bx::memCmp(str, original, 9) ); 31 | 32 | bx::memMove(&str[4], &str[4], 5); 33 | REQUIRE(0 == bx::memCmp(str, original, 9) ); 34 | 35 | bx::memMove(str, &str[4], 5); 36 | REQUIRE(0 == bx::memCmp(str, "abvgd", 5) ); 37 | 38 | bx::memMove(&str[4], str, 5); 39 | REQUIRE(str[4] == 'a' ); 40 | 41 | bx::memSet(str, 'x', 4); 42 | REQUIRE(0 == bx::memCmp(str, original, 9) ); 43 | } 44 | 45 | TEST_CASE("scatter/gather", "") 46 | { 47 | const char* str = "a\0b\0v\0g\0d"; 48 | 49 | char tmp0[64]; 50 | bx::gather(tmp0, str, 2, 1, 5); 51 | REQUIRE(0 == bx::memCmp(tmp0, "abvgd", 5) ); 52 | 53 | char tmp1[64]; 54 | bx::scatter(tmp1, 2, tmp0, 1, 5); 55 | bx::memSet(&tmp1[1], 2, 0, 1, 5); 56 | REQUIRE(0 == bx::memCmp(tmp1, str, 5) ); 57 | 58 | } 59 | -------------------------------------------------------------------------------- /tests/dbg.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #ifndef DBG_H_HEADER_GUARD 7 | #define DBG_H_HEADER_GUARD 8 | 9 | #include 10 | 11 | #define DBG_STRINGIZE(_x) DBG_STRINGIZE_(_x) 12 | #define DBG_STRINGIZE_(_x) #_x 13 | #define DBG_FILE_LINE_LITERAL "" __FILE__ "(" DBG_STRINGIZE(__LINE__) "): " 14 | #define DBG(_format, ...) bx::debugPrintf(DBG_FILE_LINE_LITERAL "" _format "\n", ##__VA_ARGS__) 15 | 16 | #endif // DBG_H_HEADER_GUARD 17 | -------------------------------------------------------------------------------- /tests/easing_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #include "test.h" 7 | 8 | #include 9 | #include 10 | 11 | TEST_CASE("easing", "") 12 | { 13 | bx::WriterI* writer = bx::getNullOut(); 14 | bx::Error err; 15 | 16 | for (uint32_t ee = 0; ee < bx::Easing::Count; ++ee) 17 | { 18 | bx::write(writer, &err, "\n\n%d\n", ee); 19 | 20 | const bx::EaseFn easing = bx::getEaseFunc(bx::Easing::Enum(ee) ); 21 | 22 | const int32_t nx = 64; 23 | const int32_t ny = 10; 24 | 25 | bx::write(writer, &err, "\t/// ^\n"); 26 | 27 | for (int32_t yy = ny+4; yy >= -5; --yy) 28 | { 29 | const float ys = float(yy )/float(ny); 30 | const float ye = float(yy+1.0)/float(ny); 31 | 32 | bx::write(writer, &err, "\t/// %c", yy != 0 ? '|' : '+'); 33 | 34 | for (int32_t xx = 0; xx < nx; ++xx) 35 | { 36 | int32_t jj = 0; 37 | for (; jj < 10; ++jj) 38 | { 39 | const float tt = float(xx*10+jj)/10.0f/float(nx); 40 | const float vv = easing(tt); 41 | 42 | if (vv >= ys 43 | && vv < ye) 44 | { 45 | bx::write(writer, &err, "*"); 46 | break; 47 | } 48 | } 49 | 50 | if (jj == 10) 51 | { 52 | bx::write(writer, &err, "%c", yy != 0 ? ' ' : '-'); 53 | } 54 | } 55 | 56 | bx::write(writer, &err, "%s\n", yy != 0 ? "" : ">"); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /tests/filepath_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #include "test.h" 7 | #include 8 | 9 | struct FilePathTest 10 | { 11 | const char* filePath; 12 | const char* expected; 13 | }; 14 | 15 | FilePathTest s_filePathTest[] = 16 | { 17 | // Already clean 18 | {"", "."}, 19 | {"abc", "abc"}, 20 | {"abc/def", "abc/def"}, 21 | {"a/b/c", "a/b/c"}, 22 | {".", "."}, 23 | {"..", ".."}, 24 | {"../..", "../.."}, 25 | {"../../abc", "../../abc"}, 26 | {"/abc", "/abc"}, 27 | {"/", "/"}, 28 | 29 | // Do not remove trailing slash 30 | {"abc/", "abc/"}, 31 | {"abc/def/", "abc/def/"}, 32 | {"a/b/c/", "a/b/c/"}, 33 | {"./", "./"}, 34 | {"../", "../"}, 35 | {"../../", "../../"}, 36 | {"/abc/", "/abc/"}, 37 | 38 | // Remove doubled slash 39 | {"abc//def//ghi", "abc/def/ghi"}, 40 | {"//abc", "/abc"}, 41 | {"///abc", "/abc"}, 42 | {"//abc//", "/abc/"}, 43 | {"abc//", "abc/"}, 44 | 45 | // Remove . elements 46 | {"abc/./def", "abc/def"}, 47 | {"/./abc/def", "/abc/def"}, 48 | {"abc/.", "abc"}, 49 | 50 | // Remove .. elements 51 | {"abc/def/ghi/../jkl", "abc/def/jkl"}, 52 | {"abc/def/../ghi/../jkl", "abc/jkl"}, 53 | {"abc/def/..", "abc"}, 54 | {"abc/def/../..", "."}, 55 | {"/abc/def/../..", "/"}, 56 | {"abc/def/../../..", ".."}, 57 | {"/abc/def/../../..", "/"}, 58 | {"abc/def/../../../ghi/jkl/../../../mno", "../../mno"}, 59 | 60 | // Combinations 61 | {"abc/./../def", "def"}, 62 | {"abc//./../def", "def"}, 63 | {"abc/../../././../def", "../../def"}, 64 | 65 | {"abc\\/../..\\/././../def", "../../def"}, 66 | {"\\abc/def\\../..\\..", "/"}, 67 | }; 68 | 69 | struct FilePathSplit 70 | { 71 | const char* filePath; 72 | bool absolute; 73 | const char* path; 74 | const char* fileName; 75 | const char* baseName; 76 | const char* extension; 77 | }; 78 | 79 | static const FilePathSplit s_filePathSplit[] = 80 | { 81 | { "\\abc/def\\../..\\../test.txt", true, "/", "test.txt", "test", ".txt" }, 82 | { "/abv/gd/555/333/pod.mac", true, "/abv/gd/555/333/", "pod.mac", "pod", ".mac" }, 83 | { "archive.tar.gz", false, "", "archive.tar.gz", "archive", ".tar.gz" }, 84 | { "tmp/archive.tar.gz", false, "tmp/", "archive.tar.gz", "archive", ".tar.gz" }, 85 | { "/tmp/archive.tar.gz", true, "/tmp/", "archive.tar.gz", "archive", ".tar.gz" }, 86 | { "d:/tmp/archive.tar.gz", true, "D:/tmp/", "archive.tar.gz", "archive", ".tar.gz" }, 87 | { "/tmp/abv/gd", true, "/tmp/abv/", "gd", "gd", "" }, 88 | { "/tmp/abv/gd/", true, "/tmp/abv/gd/", "", "", "" }, 89 | }; 90 | 91 | TEST_CASE("FilePath", "[filepath][string]") 92 | { 93 | bx::FilePath fp; 94 | for (uint32_t ii = 0; ii < BX_COUNTOF(s_filePathTest); ++ii) 95 | { 96 | const FilePathTest& test = s_filePathTest[ii]; 97 | 98 | fp.set(test.filePath); 99 | 100 | REQUIRE(0 == bx::strCmp(test.expected, fp) ); 101 | } 102 | 103 | for (uint32_t ii = 0; ii < BX_COUNTOF(s_filePathSplit); ++ii) 104 | { 105 | const FilePathSplit& test = s_filePathSplit[ii]; 106 | 107 | fp.set(test.filePath); 108 | const bx::StringView path = fp.getPath(); 109 | const bx::StringView fileName = fp.getFileName(); 110 | const bx::StringView baseName = fp.getBaseName(); 111 | const bx::StringView ext = fp.getExt(); 112 | 113 | REQUIRE(0 == bx::strCmp(test.path, path) ); 114 | REQUIRE(0 == bx::strCmp(test.fileName, fileName) ); 115 | REQUIRE(0 == bx::strCmp(test.baseName, baseName) ); 116 | REQUIRE(0 == bx::strCmp(test.extension, ext) ); 117 | REQUIRE(test.absolute == fp.isAbsolute() ); 118 | }; 119 | } 120 | 121 | TEST_CASE("FilePath temp", "[filepath]") 122 | { 123 | bx::FilePath tmp(bx::Dir::Temp); 124 | REQUIRE(0 != bx::strCmp(".", tmp.getPath().getPtr() ) ); 125 | 126 | tmp.set(bx::Dir::Temp); 127 | tmp.join("bx.test"); 128 | bx::removeAll(tmp, bx::ErrorIgnore{}); 129 | 130 | tmp.join("bx.test/abvgd/555333/test"); 131 | REQUIRE(bx::makeAll(tmp, bx::ErrorAssert{}) ); 132 | 133 | if (BX_ENABLED(BX_PLATFORM_EMSCRIPTEN) ) 134 | { 135 | SKIP("Not supported by wasm."); 136 | } 137 | 138 | tmp.set(bx::Dir::Temp); 139 | tmp.join("bx.test"); 140 | REQUIRE(bx::removeAll(tmp, bx::ErrorAssert{}) ); 141 | } 142 | 143 | TEST_CASE("FilePath special", "[filepath]") 144 | { 145 | { 146 | bx::FilePath tmp(bx::Dir::Current); 147 | bx::StringView sv(tmp); 148 | DBG("%S", &sv); 149 | } 150 | 151 | { 152 | bx::FilePath tmp(bx::Dir::Executable); 153 | bx::StringView sv(tmp); 154 | DBG("%S", &sv); 155 | } 156 | 157 | { 158 | bx::FilePath tmp(bx::Dir::Home); 159 | bx::StringView sv(tmp); 160 | DBG("%S", &sv); 161 | } 162 | 163 | { 164 | bx::FilePath tmp(bx::Dir::Temp); 165 | bx::StringView sv(tmp); 166 | DBG("%S", &sv); 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /tests/handle_bench.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | template 18 | bool mapRemove(MapType& _map, const typename MapType::value_type::first_type& _first) 19 | { 20 | typename MapType::const_iterator it = _map.find(_first); 21 | if (it != _map.end() ) 22 | { 23 | _map.erase(it); 24 | return true; 25 | } 26 | 27 | return false; 28 | } 29 | 30 | int main() 31 | { 32 | const uint32_t numElements = 4<<10; 33 | const uint32_t numIterations = 16; 34 | 35 | // 36 | { 37 | int64_t elapsed = -bx::getHPCounter(); 38 | 39 | for (uint32_t ii = 0; ii < numIterations; ++ii) 40 | { 41 | typedef tinystl::unordered_map TinyStlUnorderedMap; 42 | TinyStlUnorderedMap map; 43 | // map.reserve(numElements); 44 | for (uint32_t jj = 0; jj < numElements; ++jj) 45 | { 46 | tinystl::pair ok = map.insert(tinystl::make_pair(uint64_t(jj), uint16_t(jj) ) ); 47 | assert(ok.second); BX_UNUSED(ok); 48 | } 49 | 50 | for (uint32_t jj = 0; jj < numElements; ++jj) 51 | { 52 | bool ok = mapRemove(map, uint64_t(jj) ); 53 | assert(ok); BX_UNUSED(ok); 54 | } 55 | 56 | assert(map.size() == 0); 57 | } 58 | 59 | elapsed += bx::getHPCounter(); 60 | printf(" TinyStl: %15f\n", double(elapsed) ); 61 | } 62 | 63 | /// 64 | { 65 | int64_t elapsed = -bx::getHPCounter(); 66 | 67 | for (uint32_t ii = 0; ii < numIterations; ++ii) 68 | { 69 | typedef std::unordered_map StdUnorderedMap; 70 | StdUnorderedMap map; 71 | map.reserve(numElements); 72 | for (uint32_t jj = 0; jj < numElements; ++jj) 73 | { 74 | std::pair ok = map.insert(std::make_pair(uint64_t(jj), uint16_t(jj) ) ); 75 | assert(ok.second); BX_UNUSED(ok); 76 | } 77 | 78 | for (uint32_t jj = 0; jj < numElements; ++jj) 79 | { 80 | bool ok = mapRemove(map, uint64_t(jj) ); 81 | assert(ok); BX_UNUSED(ok); 82 | } 83 | 84 | assert(map.size() == 0); 85 | } 86 | 87 | elapsed += bx::getHPCounter(); 88 | printf(" STL: %15f\n", double(elapsed) ); 89 | } 90 | 91 | /// 92 | { 93 | int64_t elapsed = -bx::getHPCounter(); 94 | 95 | for (uint32_t ii = 0; ii < numIterations; ++ii) 96 | { 97 | typedef bx::HandleHashMapT HandleHashMap; 98 | HandleHashMap map; 99 | for (uint32_t jj = 0; jj < numElements; ++jj) 100 | { 101 | bool ok = map.insert(jj, uint16_t(jj) ); 102 | assert(ok); BX_UNUSED(ok); 103 | } 104 | 105 | for (uint32_t jj = 0; jj < numElements; ++jj) 106 | { 107 | bool ok = map.removeByKey(uint64_t(jj) ); 108 | assert(ok); BX_UNUSED(ok); 109 | } 110 | 111 | assert(map.getNumElements() == 0); 112 | } 113 | 114 | elapsed += bx::getHPCounter(); 115 | printf("HandleHashMap: %15f\n", double(elapsed) ); 116 | } 117 | 118 | extern void simd_bench(); 119 | simd_bench(); 120 | 121 | extern void math_bench(); 122 | math_bench(); 123 | 124 | return bx::kExitSuccess; 125 | } 126 | -------------------------------------------------------------------------------- /tests/handle_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #include "test.h" 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | TEST_CASE("HandleAllocT", "") 14 | { 15 | constexpr int32_t kMax = 64; 16 | bx::HandleAllocT alloc; 17 | 18 | REQUIRE(sizeof(alloc) == sizeof(uint16_t) * kMax * 2 + sizeof(bx::HandleAlloc) ); 19 | 20 | for (uint16_t ii = 0; ii < kMax; ++ii) 21 | { 22 | REQUIRE(!alloc.isValid(ii) ); 23 | } 24 | 25 | bx::RngMwc random; 26 | std::set handleSet; 27 | 28 | int32_t count = 0; 29 | 30 | for (int32_t ii = 0; ii < 200000; ++ii) 31 | { 32 | const bool add = random.gen() % 2; 33 | 34 | if (add && count < kMax) 35 | { 36 | count++; 37 | uint16_t handle = alloc.alloc(); 38 | handleSet.insert(handle); 39 | } 40 | else if (count > 0) 41 | { 42 | count--; 43 | 44 | const int32_t idx = rand() % handleSet.size(); 45 | auto it = handleSet.begin(); 46 | 47 | for (int32_t it_idx = 0; it_idx < idx; ++it_idx) 48 | { 49 | it++; 50 | REQUIRE(alloc.isValid(*it) ); 51 | } 52 | 53 | uint16_t handleToRemove = *it; 54 | alloc.free(handleToRemove); 55 | 56 | REQUIRE(!alloc.isValid(handleToRemove) ); 57 | 58 | handleSet.erase(it); 59 | } 60 | 61 | // Check if it's still correct 62 | for (auto it = handleSet.begin(); it != handleSet.end(); ++it) 63 | { 64 | REQUIRE(alloc.isValid(*it) ); 65 | } 66 | } 67 | 68 | // Finally delete all 69 | for (auto it = handleSet.begin(); it != handleSet.end(); ++it) 70 | { 71 | REQUIRE(alloc.isValid(*it) ); 72 | 73 | alloc.free(*it); 74 | } 75 | 76 | handleSet.clear(); 77 | 78 | for (uint16_t ii = 0; ii < kMax; ++ii) 79 | { 80 | REQUIRE(!alloc.isValid(ii) ); 81 | } 82 | } 83 | 84 | TEST_CASE("HandleListT", "") 85 | { 86 | bx::HandleListT<32> list; 87 | 88 | list.pushBack(16); 89 | REQUIRE(list.getFront() == 16); 90 | REQUIRE(list.getBack() == 16); 91 | 92 | list.pushFront(7); 93 | REQUIRE(list.getFront() == 7); 94 | REQUIRE(list.getBack() == 16); 95 | 96 | uint16_t expected0[] = { 15, 31, 7, 16, 17, 11, 13 }; 97 | list.pushBack(17); 98 | list.pushBack(11); 99 | list.pushBack(13); 100 | list.pushFront(31); 101 | list.pushFront(15); 102 | uint16_t count = 0; 103 | for (uint16_t it = list.getFront(); it != UINT16_MAX; it = list.getNext(it), ++count) 104 | { 105 | REQUIRE(it == expected0[count]); 106 | } 107 | REQUIRE(count == BX_COUNTOF(expected0) ); 108 | 109 | list.remove(17); 110 | list.remove(31); 111 | list.remove(16); 112 | list.pushBack(16); 113 | uint16_t expected1[] = { 15, 7, 11, 13, 16 }; 114 | count = 0; 115 | for (uint16_t it = list.getFront(); it != UINT16_MAX; it = list.getNext(it), ++count) 116 | { 117 | REQUIRE(it == expected1[count]); 118 | } 119 | REQUIRE(count == BX_COUNTOF(expected1) ); 120 | 121 | list.popBack(); 122 | list.popFront(); 123 | list.popBack(); 124 | list.popBack(); 125 | 126 | REQUIRE(list.getFront() == 7); 127 | REQUIRE(list.getBack() == 7); 128 | 129 | list.popBack(); 130 | REQUIRE(list.getFront() == UINT16_MAX); 131 | REQUIRE(list.getBack() == UINT16_MAX); 132 | } 133 | 134 | TEST_CASE("HandleAllocLruT", "") 135 | { 136 | bx::HandleAllocLruT<16> lru; 137 | 138 | uint16_t handle[4] = 139 | { 140 | lru.alloc(), 141 | lru.alloc(), 142 | lru.alloc(), 143 | lru.alloc(), 144 | }; 145 | 146 | lru.touch(handle[1]); 147 | 148 | uint16_t expected0[] = { handle[1], handle[3], handle[2], handle[0] }; 149 | uint16_t count = 0; 150 | for (uint16_t it = lru.getFront(); it != UINT16_MAX; it = lru.getNext(it), ++count) 151 | { 152 | REQUIRE(it == expected0[count]); 153 | } 154 | } 155 | 156 | TEST_CASE("HandleHashTable", "") 157 | { 158 | typedef bx::HandleHashMapT<512> HashMap; 159 | 160 | HashMap hm; 161 | 162 | REQUIRE(512 == hm.getMaxCapacity() ); 163 | 164 | bx::StringView sv0("test0"); 165 | 166 | bool ok = hm.insert(bx::hash(sv0), 0); 167 | REQUIRE(ok); 168 | 169 | ok = hm.insert(bx::hash(sv0), 0); 170 | REQUIRE(!ok); 171 | REQUIRE(1 == hm.getNumElements() ); 172 | 173 | bx::StringView sv1("test1"); 174 | 175 | ok = hm.insert(bx::hash(sv1), 0); 176 | REQUIRE(ok); 177 | REQUIRE(2 == hm.getNumElements() ); 178 | 179 | hm.removeByHandle(0); 180 | REQUIRE(0 == hm.getNumElements() ); 181 | 182 | ok = hm.insert(bx::hash(sv0), 0); 183 | REQUIRE(ok); 184 | 185 | hm.removeByKey(bx::hash(sv0) ); 186 | REQUIRE(0 == hm.getNumElements() ); 187 | 188 | for (uint32_t ii = 0, num = hm.getMaxCapacity(); ii < num; ++ii) 189 | { 190 | ok = hm.insert(ii, uint16_t(ii) ); 191 | REQUIRE(ok); 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /tests/macros_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #include "test.h" 7 | #include 8 | #include 9 | 10 | static_assert(false 11 | || BX_CRT_BIONIC 12 | || BX_CRT_GLIBC 13 | || BX_CRT_LIBCXX 14 | || BX_CRT_MINGW 15 | || BX_CRT_MSVC 16 | || BX_CRT_NEWLIB 17 | || BX_CRT_NONE 18 | ); 19 | 20 | static_assert(1 == BX_VA_ARGS_COUNT(1) ); 21 | static_assert(2 == BX_VA_ARGS_COUNT(1, 2) ); 22 | static_assert(3 == BX_VA_ARGS_COUNT(1, 2, 3) ); 23 | static_assert(4 == BX_VA_ARGS_COUNT(1, 2, 3, 4) ); 24 | static_assert(5 == BX_VA_ARGS_COUNT(1, 2, 3, 4, 5) ); 25 | static_assert(6 == BX_VA_ARGS_COUNT(1, 2, 3, 4, 5, 6) ); 26 | 27 | BX_NO_INLINE void unusedFunction() 28 | { 29 | CHECK(false); 30 | } 31 | 32 | void testAssert() 33 | { 34 | BX_ASSERT(false % 1, "Assert works!"); 35 | } 36 | 37 | TEST_CASE("Macros", "") 38 | { 39 | uint32_t unused0; 40 | BX_UNUSED(unused0); 41 | 42 | uint32_t unused1; 43 | BX_UNUSED(unused0, unused1); 44 | 45 | uint32_t unused2; 46 | BX_UNUSED(unused0, unused1, unused2, unusedFunction() ); 47 | 48 | REQUIRE(1 == BX_VA_ARGS_COUNT(1) ); 49 | REQUIRE(2 == BX_VA_ARGS_COUNT(1, 2) ); 50 | REQUIRE(3 == BX_VA_ARGS_COUNT(1, 2, 3) ); 51 | REQUIRE(4 == BX_VA_ARGS_COUNT(1, 2, 3, 4) ); 52 | REQUIRE(5 == BX_VA_ARGS_COUNT(1, 2, 3, 4, 5) ); 53 | REQUIRE(6 == BX_VA_ARGS_COUNT(1, 2, 3, 4, 5, 6) ); 54 | 55 | REQUIRE(0 == bx::strCmp(BX_STRINGIZE(TEST 1234 % 1 ^&*), "TEST 1234 % 1 ^&*") ); 56 | 57 | { 58 | struct PodStruct { int32_t x, y, z; }; 59 | REQUIRE(0 == BX_OFFSETOF(PodStruct, x) ); 60 | REQUIRE(4 == BX_OFFSETOF(PodStruct, y) ); 61 | REQUIRE(8 == BX_OFFSETOF(PodStruct, z) ); 62 | } 63 | 64 | { 65 | union PodUnion { int32_t x, y, z; }; 66 | REQUIRE(BX_OFFSETOF(PodUnion, x) == BX_OFFSETOF(PodUnion, y) ); 67 | REQUIRE(BX_OFFSETOF(PodUnion, y) == BX_OFFSETOF(PodUnion, z) ); 68 | } 69 | 70 | { 71 | struct NonPodStruct { NonPodStruct() { } int32_t x, y, z; }; 72 | REQUIRE(0 == BX_OFFSETOF(NonPodStruct, x) ); 73 | REQUIRE(4 == BX_OFFSETOF(NonPodStruct, y) ); 74 | REQUIRE(8 == BX_OFFSETOF(NonPodStruct, z) ); 75 | } 76 | 77 | { 78 | union NonPodUnion { NonPodUnion() { } int32_t x, y, z; }; 79 | REQUIRE(BX_OFFSETOF(NonPodUnion, x) == BX_OFFSETOF(NonPodUnion, y) ); 80 | REQUIRE(BX_OFFSETOF(NonPodUnion, y) == BX_OFFSETOF(NonPodUnion, z) ); 81 | } 82 | 83 | REQUIRE_ASSERTS(testAssert() ); 84 | } 85 | -------------------------------------------------------------------------------- /tests/main_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #include "test.h" 7 | 8 | int runAllTests(int _argc, const char* _argv[]); 9 | 10 | #if BX_PLATFORM_ANDROID 11 | # include 12 | 13 | static const char* s_argv[] = { "bx.test" }; 14 | 15 | void ANativeActivity_onCreate(ANativeActivity*, void*, size_t) 16 | { 17 | exit(runAllTests(BX_COUNTOF(s_argv), s_argv) ); 18 | } 19 | #else 20 | int main(int _argc, const char* _argv[]) 21 | { 22 | return runAllTests(_argc, _argv); 23 | } 24 | #endif // BX_PLATFORM 25 | -------------------------------------------------------------------------------- /tests/math_bench.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | typedef float (*MathFn)(float); 13 | 14 | template 15 | float mathTest(const char* _name) 16 | { 17 | bx::WriterI* writer = bx::getStdOut(); 18 | int64_t elapsed = -bx::getHPCounter(); 19 | 20 | float result = 0.0f; 21 | const float max = 1389.0f; 22 | 23 | for (float xx = 0.0f; xx < max; xx += 0.1f) 24 | { 25 | result += mfn(xx); 26 | } 27 | 28 | bx::Error err; 29 | 30 | elapsed += bx::getHPCounter(); 31 | bx::write(writer, &err, "%-20s: %15f\n", _name, double(elapsed) ); 32 | 33 | return result; 34 | } 35 | 36 | float rsqrt(float _a) 37 | { 38 | return 1.0f/::sqrtf(_a); 39 | } 40 | 41 | float sinCosNonApproxBench() 42 | { 43 | bx::WriterI* writer = bx::getStdOut(); 44 | int64_t elapsed = -bx::getHPCounter(); 45 | 46 | float result = 0.0f; 47 | const float max = 1389.0f; 48 | 49 | for (float xx = 0.0f; xx < max; xx += 0.1f) 50 | { 51 | float ss, cc; 52 | ss = bx::sin(xx); 53 | cc = bx::cos(xx); 54 | 55 | result += ss + cc; 56 | } 57 | 58 | bx::Error err; 59 | 60 | elapsed += bx::getHPCounter(); 61 | bx::write(writer, &err, "%-20s: %15f\n", "sin + cos", double(elapsed) ); 62 | 63 | return result; 64 | } 65 | 66 | float sinCosApproxBench() 67 | { 68 | bx::WriterI* writer = bx::getStdOut(); 69 | int64_t elapsed = -bx::getHPCounter(); 70 | 71 | float result = 0.0f; 72 | const float max = 1389.0f; 73 | 74 | for (float xx = 0.0f; xx < max; xx += 0.1f) 75 | { 76 | float ss, cc; 77 | bx::sinCosApprox(ss, cc, xx); 78 | 79 | result += ss + cc; 80 | } 81 | 82 | bx::Error err; 83 | 84 | elapsed += bx::getHPCounter(); 85 | bx::write(writer, &err, "%-20s: %15f\n", "sinCosApprox", double(elapsed) ); 86 | 87 | return result; 88 | } 89 | 90 | float g_result; // trick compiler to not discard results 91 | 92 | void math_bench() 93 | { 94 | bx::WriterI* writer = bx::getStdOut(); 95 | bx::Error err; 96 | bx::write(writer, &err, "Math bench\n\n"); 97 | 98 | g_result += mathTest< ::sqrtf >(" ::sqrtf"); 99 | g_result += mathTest("bx::sqrtRef"); 100 | g_result += mathTest("bx::sqrtSimd"); 101 | g_result += mathTest("bx::sqrt"); 102 | 103 | bx::write(writer, &err, "\n"); 104 | g_result += mathTest< ::rsqrt >(" ::rsqrtf"); 105 | g_result += mathTest("bx::rsqrtRef"); 106 | g_result += mathTest("bx::rsqrtSimd"); 107 | g_result += mathTest("bx::rsqrt"); 108 | 109 | bx::write(writer, &err, "\n"); 110 | g_result += sinCosNonApproxBench(); 111 | g_result += sinCosApproxBench(); 112 | 113 | bx::write(writer, &err, "\n"); 114 | g_result += mathTest< ::sinf >(" ::sinf"); 115 | g_result += mathTest("bx::sin"); 116 | 117 | bx::write(writer, &err, "\n"); 118 | g_result += mathTest< ::sinhf>(" ::sinhf"); 119 | g_result += mathTest("bx::sinh"); 120 | 121 | bx::write(writer, &err, "\n"); 122 | g_result += mathTest< ::asinf>(" ::asinf"); 123 | g_result += mathTest("bx::asin"); 124 | 125 | bx::write(writer, &err, "\n"); 126 | g_result += mathTest< ::cosf >(" ::cosf"); 127 | g_result += mathTest("bx::cos"); 128 | 129 | bx::write(writer, &err, "\n"); 130 | g_result += mathTest< ::coshf>(" ::coshf"); 131 | g_result += mathTest("bx::cosh"); 132 | 133 | bx::write(writer, &err, "\n"); 134 | g_result += mathTest< ::acosf>(" ::acosf"); 135 | g_result += mathTest("bx::acos"); 136 | 137 | bx::write(writer, &err, "\n"); 138 | g_result += mathTest< ::tanf >(" ::tanf"); 139 | g_result += mathTest("bx::tan"); 140 | 141 | bx::write(writer, &err, "\n"); 142 | g_result += mathTest< ::tanhf>(" ::tanhf"); 143 | g_result += mathTest("bx::tanh"); 144 | 145 | bx::write(writer, &err, "\n"); 146 | g_result += mathTest< ::atanf>(" ::atanf"); 147 | g_result += mathTest("bx::atan"); 148 | 149 | bx::write(writer, &err, "\n"); 150 | g_result += mathTest< ::expf>(" ::expf"); 151 | g_result += mathTest("bx::exp"); 152 | 153 | bx::write(writer, &err, "\n"); 154 | g_result += mathTest< ::exp2f>(" ::exp2f"); 155 | g_result += mathTest("bx::exp2"); 156 | 157 | bx::write(writer, &err, "\n"); 158 | g_result += mathTest< ::logf >(" ::logf"); 159 | g_result += mathTest("bx::log"); 160 | 161 | bx::write(writer, &err, "\n"); 162 | g_result += mathTest< ::log2f>(" ::log2f"); 163 | g_result += mathTest("bx::log2"); 164 | } 165 | -------------------------------------------------------------------------------- /tests/os_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #include "test.h" 7 | #include 8 | #include 9 | #include 10 | 11 | TEST_CASE("getProcessMemoryUsed", "") 12 | { 13 | if (BX_ENABLED(BX_PLATFORM_EMSCRIPTEN) ) 14 | { 15 | SKIP("Not supported by wasm."); 16 | } 17 | 18 | REQUIRE(0 != bx::getProcessMemoryUsed() ); 19 | } 20 | 21 | #if BX_CONFIG_SUPPORTS_THREADING 22 | 23 | TEST_CASE("semaphore_timeout", "") 24 | { 25 | bx::Semaphore sem; 26 | 27 | int64_t start = bx::getHPCounter(); 28 | bool ok = sem.wait(900); 29 | int64_t elapsed = bx::getHPCounter() - start; 30 | int64_t frequency = bx::getHPFrequency(); 31 | double ms = double(elapsed) / double(frequency) * 1000; 32 | bx::printf("%f\n", ms); 33 | REQUIRE(!ok); 34 | } 35 | 36 | #endif // BX_CONFIG_SUPPORTS_THREADING 37 | -------------------------------------------------------------------------------- /tests/pixelformat_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #include "test.h" 7 | #include 8 | 9 | TEST_CASE("pack/unpack Rgba8", "[pixelformat]") 10 | { 11 | float rgba[4] = { 0.1f, 0.3f, 0.8f, 0.9f }; 12 | uint32_t encoded; 13 | bx::packRgba8(&encoded, rgba); 14 | 15 | float decoded[4]; 16 | bx::unpackRgba8(decoded, &encoded); 17 | 18 | REQUIRE(bx::isEqual(rgba, decoded, 4, 0.01f) ); 19 | } 20 | 21 | TEST_CASE("pack/unpack Rgb9E5F", "[pixelformat]") 22 | { 23 | float rgba[3] = { 0.1f, 0.3f, 0.89f }; 24 | uint32_t encoded; 25 | bx::packRgb9E5F(&encoded, rgba); 26 | 27 | float decoded[3]; 28 | bx::unpackRgb9E5F(decoded, &encoded); 29 | 30 | REQUIRE(bx::isEqual(rgba, decoded, BX_COUNTOF(rgba), 0.001f) ); 31 | } 32 | -------------------------------------------------------------------------------- /tests/queue_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #include "test.h" 7 | #include 8 | #include 9 | 10 | void* bitsToPtr(uintptr_t _ui) 11 | { 12 | union { uintptr_t ui; void* ptr; } cast = { _ui }; 13 | return cast.ptr; 14 | } 15 | 16 | uintptr_t ptrToBits(void* _ptr) 17 | { 18 | union { void* ptr; uintptr_t ui; } cast = { _ptr }; 19 | return cast.ui; 20 | } 21 | 22 | TEST_CASE("SpSc", "") 23 | { 24 | bx::DefaultAllocator allocator; 25 | bx::SpScUnboundedQueue queue(&allocator); 26 | queue.push(bitsToPtr(0xdeadbeef) ); 27 | REQUIRE(0xdeadbeef == ptrToBits(queue.pop() ) ); 28 | } 29 | 30 | TEST_CASE("MpSc", "") 31 | { 32 | bx::DefaultAllocator allocator; 33 | bx::MpScUnboundedQueueT queue(&allocator); 34 | queue.push(bitsToPtr(0xdeadbeef) ); 35 | REQUIRE(0xdeadbeef == ptrToBits(queue.pop() ) ); 36 | } 37 | -------------------------------------------------------------------------------- /tests/readerwriter_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #include "test.h" 7 | #include 8 | 9 | TEST_CASE("writeLE", "") 10 | { 11 | bx::SizerWriter writer; 12 | 13 | bx::Error err; 14 | 15 | int32_t total = bx::writeLE(&writer, 1.0f, &err); 16 | 17 | REQUIRE(err.isOk() ); 18 | REQUIRE(total == 4); 19 | } 20 | 21 | TEST_CASE("writeBE", "") 22 | { 23 | bx::SizerWriter writer; 24 | 25 | bx::Error err; 26 | 27 | int32_t total = bx::writeBE(&writer, 1.0f, &err); 28 | 29 | REQUIRE(err.isOk() ); 30 | REQUIRE(total == 4); 31 | } 32 | 33 | TEST_CASE("writeRep", "") 34 | { 35 | uint8_t tmp[1389]; 36 | bx::StaticMemoryBlock mb(tmp, sizeof(tmp) ); 37 | bx::MemoryWriter writer(&mb); 38 | 39 | bx::Error err; 40 | 41 | int32_t total = 0; 42 | 43 | total += bx::writeRep(&writer, 0xfb, BX_COUNTOF(tmp)-1, &err); 44 | REQUIRE(err.isOk() ); 45 | REQUIRE(BX_COUNTOF(tmp)-1 == total); 46 | 47 | total += bx::writeRep(&writer, 0xfb, 2, &err); 48 | REQUIRE(!err.isOk() ); 49 | REQUIRE(BX_COUNTOF(tmp) == total); 50 | 51 | for (uint32_t ii = 0; ii < BX_COUNTOF(tmp); ++ii) 52 | { 53 | REQUIRE(0xfb == tmp[ii]); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /tests/ringbuffer_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #include "test.h" 7 | #include 8 | 9 | TEST_CASE("RingBufferControl", "") 10 | { 11 | bx::RingBufferControl control(16); 12 | 13 | REQUIRE(1 == control.reserve(1) ); 14 | REQUIRE(0 == control.reserve(16, true) ); 15 | REQUIRE(14 == control.reserve(16) ); 16 | REQUIRE(15 == control.commit(15) ); 17 | REQUIRE(15 == control.available() ); 18 | REQUIRE(15 == control.consume(15) ); 19 | REQUIRE(0 == control.available() ); 20 | } 21 | -------------------------------------------------------------------------------- /tests/rng_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #include "test.h" 7 | 8 | #include 9 | #include 10 | 11 | const uint32_t kMax = 10<<20; 12 | 13 | template 14 | void testRng(const char* _name, Ty* _rng) 15 | { 16 | uint32_t histBits[32]; 17 | uint32_t histUint8[256]; 18 | 19 | bx::memSet(histBits, 0, sizeof(histBits) ); 20 | bx::memSet(histUint8, 0, sizeof(histUint8) ); 21 | 22 | for (uint32_t ii = 0; ii < kMax; ++ii) 23 | { 24 | uint32_t val = _rng->gen(); 25 | 26 | for (uint32_t shift = 0; shift < 32; ++shift) 27 | { 28 | const uint32_t mask = 1<>24; 33 | const uint32_t m0f00 = (val & 0x00ff0000)>>16; 34 | const uint32_t m00f0 = (val & 0x0000ff00)>> 8; 35 | const uint32_t m000f = (val & 0x000000ff)>> 0; 36 | 37 | histUint8[mf000]++; 38 | histUint8[m0f00]++; 39 | histUint8[m00f0]++; 40 | histUint8[m000f]++; 41 | } 42 | 43 | bx::WriterI* writer = bx::getNullOut(); 44 | bx::Error err; 45 | 46 | bx::write(writer, &err, "%s\n", _name); 47 | 48 | { 49 | bx::write(writer, &err, "\tbits histogram:\n"); 50 | uint32_t min = UINT32_MAX; 51 | uint32_t max = 0; 52 | 53 | for (uint32_t ii = 0; ii < BX_COUNTOF(histBits); ++ii) 54 | { 55 | bx::write(writer, &err, "\t\t%3d: %d\n", ii, histBits[ii]); 56 | min = bx::min(min, histBits[ii]); 57 | max = bx::max(max, histBits[ii]); 58 | } 59 | 60 | bx::write(writer, &err, "\tmin: %d, max: %d (diff: %d)\n", min, max, max-min); 61 | 62 | REQUIRE(max-min < 8000); 63 | } 64 | 65 | { 66 | bx::write(writer, &err, "\tuint8_t histogram:\n"); 67 | uint32_t min = UINT32_MAX; 68 | uint32_t max = 0; 69 | 70 | for (uint32_t ii = 0; ii < BX_COUNTOF(histUint8); ++ii) 71 | { 72 | bx::write(writer, &err, "\t\t%3d: %d\n", ii, histUint8[ii]); 73 | min = bx::min(min, histUint8[ii]); 74 | max = bx::max(max, histUint8[ii]); 75 | } 76 | 77 | bx::write(writer, &err, "\tmin: %d, max: %d (diff: %d)\n", min, max, max-min); 78 | 79 | REQUIRE(max-min < 8000); 80 | } 81 | } 82 | 83 | TEST_CASE("Rng", "") 84 | { 85 | bx::RngMwc mwc; 86 | testRng("RngMwc", &mwc); 87 | 88 | bx::RngShr3 shr3; 89 | testRng("RngShr3", &shr3); 90 | } 91 | -------------------------------------------------------------------------------- /tests/run_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #define CATCH_CONFIG_RUNNER 7 | #include "test.h" 8 | #include 9 | #include 10 | #include 11 | 12 | bool testAssertHandler(const bx::Location& _location, const char* _format, va_list _argList) 13 | { 14 | bx::printf("%s(%d): ", _location.filePath, _location.line); 15 | bx::vprintf(_format, _argList); 16 | bx::printf("\n"); 17 | 18 | uintptr_t stack[32]; 19 | const uint32_t num = bx::getCallStack(2 /* skip self */, BX_COUNTOF(stack), stack); 20 | bx::writeCallstack(bx::getStdOut(), stack, num, bx::ErrorIgnore{}); 21 | 22 | // Throwing exceptions is required for testing asserts being trigged. 23 | // Use REQUIRE_ASSERTS to test asserts. 24 | throw std::exception(); 25 | 26 | return true; 27 | } 28 | 29 | int runAllTests(int32_t _argc, const char* _argv[]) 30 | { 31 | bx::setAssertHandler(testAssertHandler); 32 | 33 | bx::printf( 34 | "\nCompiler: " BX_COMPILER_NAME 35 | ", CPU: " BX_CPU_NAME 36 | ", Arch: " BX_ARCH_NAME 37 | ", OS: " BX_PLATFORM_NAME 38 | ", CRT: " BX_CRT_NAME 39 | ", Features: " BX_CPP_NAME 40 | #if BX_SIMD_SUPPORTED 41 | ", SIMD" 42 | # if BX_SIMD_AVX 43 | ", AVX" 44 | # endif // BX_SIMD_AVX 45 | # if BX_SIMD_LANGEXT 46 | ", LangExt" 47 | # endif // BX_SIMD_LANGEXT 48 | # if BX_SIMD_NEON 49 | ", Neon" 50 | # endif // BX_SIMD_NEON 51 | # if BX_SIMD_SSE 52 | ", SSE" 53 | # endif // BX_SIMD_SSE 54 | #endif // BX_SIMD_SUPPORTED 55 | 56 | ", Date: " __DATE__ 57 | ", Time: " __TIME__ 58 | "\n\n" 59 | ); 60 | 61 | bx::printf("Args:\n"); 62 | 63 | for (int32_t ii = 0; ii < _argc; ++ii) 64 | { 65 | bx::printf("\t%2d: \"%s\"\n", ii, _argv[ii]); 66 | } 67 | 68 | bx::printf("\n"); 69 | 70 | using namespace Catch; 71 | 72 | Session session; 73 | 74 | ConfigData config; 75 | config.defaultColourMode = BX_PLATFORM_EMSCRIPTEN 76 | ? ColourMode::None 77 | : ColourMode::PlatformDefault 78 | ; 79 | config.showDurations = ShowDurations::Always; 80 | 81 | session.useConfigData(config); 82 | 83 | return session.run(_argc, _argv); 84 | } 85 | -------------------------------------------------------------------------------- /tests/settings_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #include "test.h" 7 | #include 8 | #include 9 | 10 | TEST_CASE("Settings", "") 11 | { 12 | bx::FilePath filePath; 13 | filePath.set(bx::Dir::Temp); 14 | filePath.join("settings.ini"); 15 | 16 | bx::DefaultAllocator allocator; 17 | 18 | bx::Settings settings(&allocator); 19 | 20 | settings.set("meh/podmac", "true"); 21 | settings.set("test/foo/bar/abvgd", "1389"); 22 | 23 | bx::FileWriter writer; 24 | if (bx::open(&writer, filePath, false, bx::ErrorIgnore{}) ) 25 | { 26 | bx::write(&writer, settings, bx::ErrorIgnore{}); 27 | bx::close(&writer); 28 | } 29 | 30 | REQUIRE(settings.get("meh").isEmpty() ); 31 | REQUIRE(0 == bx::strCmp(settings.get("meh/podmac"), "true") ); 32 | REQUIRE(0 == bx::strCmp(settings.get("test/foo/bar/abvgd"), "1389") ); 33 | 34 | settings.remove("meh/podmac"); 35 | REQUIRE(settings.get("meh/podmac").isEmpty() ); 36 | 37 | settings.clear(); 38 | 39 | bx::FileReader reader; 40 | if (bx::open(&reader, filePath, bx::ErrorIgnore{}) ) 41 | { 42 | bx::read(&reader, settings, bx::ErrorIgnore{}); 43 | bx::close(&reader); 44 | } 45 | 46 | REQUIRE(settings.get("meh").isEmpty() ); 47 | REQUIRE(0 == bx::strCmp(settings.get("meh/podmac"), "true") ); 48 | REQUIRE(0 == bx::strCmp(settings.get("test/foo/bar/abvgd"), "1389") ); 49 | } 50 | -------------------------------------------------------------------------------- /tests/simd_bench.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | static void flushCache() 14 | { 15 | static uint32_t length = 1 << 26; 16 | static uint8_t* input = new uint8_t[length]; 17 | static uint8_t* output = new uint8_t[length]; 18 | bx::memCopy(output, input, length); 19 | } 20 | 21 | typedef bx::simd128_t (*SimdRsqrtFn)(bx::simd128_t _a); 22 | 23 | template 24 | void simd_rsqrt_bench(bx::simd128_t* _dst, bx::simd128_t* _src, uint32_t _numVertices) 25 | { 26 | for (uint32_t ii = 0, num = _numVertices/4; ii < num; ++ii) 27 | { 28 | bx::simd128_t* ptr = &_src[ii*4]; 29 | bx::simd128_t tmp0 = bx::simd_ld(ptr + 0); 30 | bx::simd128_t tmp1 = bx::simd_ld(ptr + 1); 31 | bx::simd128_t tmp2 = bx::simd_ld(ptr + 2); 32 | bx::simd128_t tmp3 = bx::simd_ld(ptr + 3); 33 | bx::simd128_t rsqrt0 = simdRsqrtFn(tmp0); 34 | bx::simd128_t rsqrt1 = simdRsqrtFn(tmp1); 35 | bx::simd128_t rsqrt2 = simdRsqrtFn(tmp2); 36 | bx::simd128_t rsqrt3 = simdRsqrtFn(tmp3); 37 | 38 | ptr = &_dst[ii*4]; 39 | bx::simd_st(ptr + 0, rsqrt0); 40 | bx::simd_st(ptr + 1, rsqrt1); 41 | bx::simd_st(ptr + 2, rsqrt2); 42 | bx::simd_st(ptr + 3, rsqrt3); 43 | } 44 | } 45 | 46 | void simd_bench_pass(bx::simd128_t* _dst, bx::simd128_t* _src, uint32_t _numVertices) 47 | { 48 | const uint32_t numIterations = 10; 49 | 50 | { 51 | int64_t elapsed = 0; 52 | for (uint32_t test = 0; test < numIterations; ++test) 53 | { 54 | flushCache(); 55 | elapsed += -bx::getHPCounter(); 56 | simd_rsqrt_bench(_dst, _src, _numVertices); 57 | elapsed += bx::getHPCounter(); 58 | } 59 | printf(" simd_rsqrt_est: %15f\n", double(elapsed) ); 60 | } 61 | 62 | { 63 | int64_t elapsed = 0; 64 | for (uint32_t test = 0; test < numIterations; ++test) 65 | { 66 | flushCache(); 67 | elapsed += -bx::getHPCounter(); 68 | simd_rsqrt_bench(_dst, _src, _numVertices); 69 | elapsed += bx::getHPCounter(); 70 | } 71 | printf(" simd_rsqrt_nr: %15f\n", double(elapsed) ); 72 | } 73 | 74 | { 75 | int64_t elapsed = 0; 76 | for (uint32_t test = 0; test < numIterations; ++test) 77 | { 78 | flushCache(); 79 | elapsed += -bx::getHPCounter(); 80 | simd_rsqrt_bench(_dst, _src, _numVertices); 81 | elapsed += bx::getHPCounter(); 82 | } 83 | printf("simd_rsqrt_carmack: %15f\n", double(elapsed) ); 84 | } 85 | 86 | { 87 | int64_t elapsed = 0; 88 | for (uint32_t test = 0; test < numIterations; ++test) 89 | { 90 | flushCache(); 91 | elapsed += -bx::getHPCounter(); 92 | simd_rsqrt_bench(_dst, _src, _numVertices); 93 | elapsed += bx::getHPCounter(); 94 | } 95 | printf(" simd_rsqrt: %15f\n", double(elapsed) ); 96 | } 97 | } 98 | 99 | void simd_bench() 100 | { 101 | bx::DefaultAllocator allocator; 102 | bx::RngMwc rng; 103 | 104 | const uint32_t numVertices = 1024*1024; 105 | 106 | uint8_t* data = (uint8_t*)bx::alloc(&allocator, 2*numVertices*sizeof(bx::simd128_t), 16); 107 | bx::simd128_t* src = (bx::simd128_t*)data; 108 | bx::simd128_t* dst = &src[numVertices]; 109 | 110 | printf("\n -- positive & negative --\n"); 111 | for (uint32_t ii = 0; ii < numVertices; ++ii) 112 | { 113 | float* ptr = (float*)&src[ii]; 114 | bx::store(ptr, bx::randUnitSphere(&rng) ); 115 | ptr[3] = 1.0f; 116 | } 117 | 118 | simd_bench_pass(dst, src, numVertices); 119 | 120 | printf("\n -- positive only --\n"); 121 | for (uint32_t ii = 0; ii < numVertices; ++ii) 122 | { 123 | float* ptr = (float*)&src[ii]; 124 | ptr[0] = bx::abs(ptr[0]); 125 | ptr[1] = bx::abs(ptr[1]); 126 | ptr[2] = bx::abs(ptr[2]); 127 | ptr[3] = bx::abs(ptr[3]); 128 | } 129 | 130 | simd_bench_pass(dst, src, numVertices); 131 | 132 | bx::free(&allocator, data, 16); 133 | } 134 | -------------------------------------------------------------------------------- /tests/test.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #ifndef BX_TEST_H_HEADER_GUARD 7 | #define BX_TEST_H_HEADER_GUARD 8 | 9 | #include 10 | 11 | BX_PRAGMA_DIAGNOSTIC_PUSH(); 12 | BX_PRAGMA_DIAGNOSTIC_IGNORED_MSVC(4312); // warning C4312 : 'reinterpret_cast' : conversion from 'int' to 'const char *' of greater size 13 | //BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG("-Wnan-infinity-disabled"); 14 | #include 15 | BX_PRAGMA_DIAGNOSTIC_POP(); 16 | 17 | #define TEST(_x) TEST_CASE(#_x, "") 18 | 19 | #if BX_CONFIG_DEBUG 20 | # define REQUIRE_ASSERTS(_x) REQUIRE_THROWS(_x) 21 | #else 22 | # define REQUIRE_ASSERTS(_x) BX_UNUSED(_x) 23 | #endif // BX_CONFIG_DEBUG 24 | 25 | #include "dbg.h" 26 | 27 | #endif // BX_TEST_H_HEADER_GUARD 28 | -------------------------------------------------------------------------------- /tests/thread_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #include "test.h" 7 | #include 8 | 9 | #if BX_CONFIG_SUPPORTS_THREADING 10 | 11 | bx::DefaultAllocator s_allocator; 12 | bx::MpScUnboundedBlockingQueue s_mpsc(&s_allocator); 13 | 14 | int32_t threadExit0(bx::Thread* _thread, void*) 15 | { 16 | _thread->pop(); 17 | 18 | s_mpsc.push(reinterpret_cast(uintptr_t(0x1300) ) ); 19 | 20 | return bx::kExitSuccess; 21 | } 22 | 23 | int32_t threadExit1(bx::Thread* _thread, void*) 24 | { 25 | BX_UNUSED(_thread); 26 | 27 | s_mpsc.push(reinterpret_cast(uintptr_t(0x89) ) ); 28 | 29 | return bx::kExitFailure; 30 | } 31 | 32 | TEST_CASE("Semaphore", "") 33 | { 34 | bx::Semaphore sem; 35 | REQUIRE(!sem.wait(10) ); 36 | 37 | sem.post(1); 38 | REQUIRE(sem.wait() ); 39 | } 40 | 41 | TEST_CASE("Thread", "") 42 | { 43 | bx::Thread th; 44 | 45 | REQUIRE(!th.isRunning() ); 46 | 47 | bool init = th.init(threadExit0, NULL, 0, NULL); 48 | REQUIRE(init); 49 | 50 | REQUIRE(th.isRunning() ); 51 | th.push(NULL); 52 | th.shutdown(); 53 | 54 | REQUIRE(!th.isRunning() ); 55 | REQUIRE(th.getExitCode() == 0); 56 | 57 | th.init(threadExit1); 58 | REQUIRE(th.isRunning() ); 59 | th.shutdown(); 60 | 61 | REQUIRE(!th.isRunning() ); 62 | REQUIRE(th.getExitCode() == 1); 63 | } 64 | 65 | TEST_CASE("MpScUnboundedBlockingQueue", "") 66 | { 67 | void* p0 = s_mpsc.pop(); 68 | void* p1 = s_mpsc.pop(); 69 | 70 | uintptr_t result = uintptr_t(p0) | uintptr_t(p1); 71 | 72 | REQUIRE(result == 0x1389); 73 | } 74 | 75 | #endif // BX_CONFIG_SUPPORTS_THREADING 76 | -------------------------------------------------------------------------------- /tests/tokenizecmd_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #include "test.h" 7 | #include 8 | #include 9 | 10 | TEST_CASE("commandLine", "") 11 | { 12 | const char* args[] = 13 | { 14 | "-s", 15 | "--long", 16 | "--platform", 17 | "x", 18 | "--num", "1389", 19 | "--foo", 20 | "--", // it should not parse arguments after argument terminator 21 | "--bar", 22 | }; 23 | 24 | bx::CommandLine cmdLine(BX_COUNTOF(args), args); 25 | 26 | REQUIRE( cmdLine.hasArg("long") ); 27 | REQUIRE( cmdLine.hasArg('s') ); 28 | 29 | int32_t num; 30 | REQUIRE(cmdLine.hasArg(num, '\0', "num") ); 31 | REQUIRE(1389 == num); 32 | 33 | // test argument terminator 34 | REQUIRE( cmdLine.hasArg("foo") ); 35 | REQUIRE(!cmdLine.hasArg("bar") ); 36 | 37 | // non-existing argument 38 | REQUIRE(!cmdLine.hasArg('x') ); 39 | REQUIRE(!cmdLine.hasArg("preprocess") ); 40 | } 41 | 42 | static bool test(const char* _input, int32_t _argc, ...) 43 | { 44 | char buffer[1024]; 45 | uint32_t len = sizeof(buffer); 46 | char* argv[32]; 47 | int32_t argc; 48 | bx::tokenizeCommandLine(_input, buffer, len, argc, argv, BX_COUNTOF(argv) ); 49 | 50 | if (_argc != argc) 51 | { 52 | return false; 53 | } 54 | 55 | va_list argList; 56 | va_start(argList, _argc); 57 | 58 | for (int32_t ii = 0; ii < _argc; ++ii) 59 | { 60 | const char* arg = va_arg(argList, const char*); 61 | if (0 != bx::strCmp(argv[ii], arg) ) 62 | { 63 | return false; 64 | } 65 | } 66 | 67 | va_end(argList); 68 | 69 | return true; 70 | } 71 | 72 | TEST_CASE("tokenizeCommandLine", "") 73 | { 74 | REQUIRE(test(" ", 0, NULL) ); 75 | REQUIRE(test("\\", 0, NULL) ); 76 | 77 | REQUIRE(test("a b v g d", 5, "a", "b", "v", "g", "d") ); 78 | 79 | REQUIRE(test("\"ab\\\"v\" \"\\\\\" g", 3, "ab\"v", "\\", "g") ); 80 | REQUIRE(test("a\\\\\\\"b v g", 3, "a\\\"b", "v", "g") ); 81 | REQUIRE(test("a\\\\\\\\\"b v\" g d", 3, "a\\\\b v", "g", "d") ); 82 | } 83 | -------------------------------------------------------------------------------- /tests/uint32_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #include "test.h" 7 | #include 8 | 9 | TEST_CASE("StrideAlign", "[uint32_t]") 10 | { 11 | REQUIRE(0 == bx::strideAlign(0, 12) ); 12 | for (uint32_t ii = 0; ii < 12; ++ii) 13 | { 14 | REQUIRE(12 == bx::strideAlign(ii+1, 12) ); 15 | } 16 | 17 | REQUIRE(0 == bx::strideAlign<16>(0, 12) ); 18 | for (uint32_t ii = 0; ii < 12; ++ii) 19 | { 20 | REQUIRE(48 == bx::strideAlign<16>(ii+1, 12) ); 21 | } 22 | 23 | uint32_t offset = 11; 24 | offset = bx::strideAlign(offset, 32); 25 | REQUIRE(offset == 32); 26 | 27 | offset = bx::strideAlign(offset, 24); 28 | REQUIRE(offset == 48); 29 | } 30 | 31 | TEST_CASE("uint32_part", "[uint32_t]") 32 | { 33 | REQUIRE(UINT32_C(0x55555555) == bx::uint32_part1by1(UINT16_MAX) ); 34 | REQUIRE(UINT32_C(0x09249249) == bx::uint32_part1by2(0x3ff) ); 35 | } 36 | 37 | TEST_CASE("uint32_splat", "[uint32_t]") 38 | { 39 | REQUIRE(UINT32_C(0x01010101) == bx::uint32_splat(0x01) ); 40 | REQUIRE(UINT32_C(0x55555555) == bx::uint32_splat(0x55) ); 41 | REQUIRE(UINT32_C(0x13891389) == bx::uint32_splat(0x1389) ); 42 | } 43 | 44 | TEST_CASE("uint64_splat", "[uint32_t]") 45 | { 46 | REQUIRE(UINT64_C(0x0101010101010101) == bx::uint64_splat(0x01) ); 47 | REQUIRE(UINT64_C(0x5555555555555555) == bx::uint64_splat(0x55) ); 48 | REQUIRE(UINT32_C(0x1389138913891389) == bx::uint64_splat(0x1389) ); 49 | REQUIRE(UINT32_C(0x1506138915061389) == bx::uint64_splat(0x15061389) ); 50 | } 51 | 52 | TEST_CASE("uint32_gcd", "[uint32_t]") 53 | { 54 | REQUIRE(1 == bx::uint32_gcd(13, 89) ); 55 | REQUIRE(3 == bx::uint32_gcd( 3, 9) ); 56 | REQUIRE(8 == bx::uint32_gcd( 8, 64) ); 57 | REQUIRE(9 == bx::uint32_gcd(18, 81) ); 58 | } 59 | 60 | TEST_CASE("uint32_lcm", "[uint32_t]") 61 | { 62 | REQUIRE(1157 == bx::uint32_lcm(13, 89) ); 63 | REQUIRE( 9 == bx::uint32_lcm( 3, 9) ); 64 | REQUIRE( 48 == bx::uint32_lcm( 6, 16) ); 65 | REQUIRE( 80 == bx::uint32_lcm(16, 20) ); 66 | } 67 | 68 | TEST_CASE("halfTo/FromFloat", "[uint32_t]") 69 | { 70 | for (uint32_t ii = 0; ii < 0x7c00; ++ii) 71 | { 72 | const uint16_t orig = uint16_t(ii); 73 | const float htf = bx::halfToFloat(orig); 74 | const uint16_t hff = bx::halfFromFloat(htf); 75 | REQUIRE(orig == hff); 76 | } 77 | 78 | for (uint32_t ii = 0x8000; ii < 0xfc00; ++ii) 79 | { 80 | const uint16_t orig = uint16_t(ii); 81 | const float htf = bx::halfToFloat(orig); 82 | const uint16_t hff = bx::halfFromFloat(htf); 83 | REQUIRE(orig == hff); 84 | } 85 | } 86 | 87 | TEST_CASE("uint32_testpow2", "[uint32_t]") 88 | { 89 | uint32_t shift = 0; 90 | uint32_t nextpow2 = bx::uint32_nextpow2(1); 91 | 92 | for (uint32_t ii = 1; ii < 1<<24; ++ii) 93 | { 94 | REQUIRE(nextpow2 == bx::uint32_nextpow2(ii) ); 95 | 96 | if (bx::uint32_testpow2(ii) ) 97 | { 98 | REQUIRE(ii == 1u << shift); 99 | ++shift; 100 | 101 | REQUIRE(ii == nextpow2); 102 | nextpow2 = bx::uint32_nextpow2(ii+1); 103 | } 104 | } 105 | } 106 | 107 | TEST_CASE("uint32_roX", "[uint32_t]") 108 | { 109 | REQUIRE(bx::uint32_rol(0x80000000, 1) == 1); 110 | REQUIRE(bx::uint32_ror(1, 1) == 0x80000000); 111 | } 112 | 113 | TEST_CASE("uint64_roX", "[uint32_t]") 114 | { 115 | REQUIRE(bx::uint64_rol(0x8000000000000000, 1) == 1); 116 | REQUIRE(bx::uint64_ror(1, 1) == 0x8000000000000000); 117 | } 118 | 119 | TEST_CASE("align", "[uint32_t]") 120 | { 121 | REQUIRE( bx::isAligned(0, 8) ); 122 | REQUIRE(!bx::isAligned(7, 8) ); 123 | REQUIRE( bx::isAligned(64, 8) ); 124 | REQUIRE(!bx::isAligned(63, 8) ); 125 | 126 | for (int32_t ii = 0; ii < 1024; ++ii) 127 | { 128 | REQUIRE(bx::isAligned(ii, 0) ); 129 | REQUIRE(ii == bx::alignUp(ii, 0) ); 130 | REQUIRE(ii == bx::alignDown(ii, 0) ); 131 | } 132 | 133 | REQUIRE( 0 == bx::alignUp( 0, 16) ); 134 | REQUIRE( 16 == bx::alignUp( 1, 16) ); 135 | REQUIRE( 16 == bx::alignUp( 15, 16) ); 136 | REQUIRE( 16 == bx::alignUp( 16, 16) ); 137 | REQUIRE(256 == bx::alignUp(255, 16) ); 138 | REQUIRE( 0 == bx::alignUp(-1, 16) ); 139 | REQUIRE(-16 == bx::alignUp(-31, 16) ); 140 | 141 | REQUIRE( 0 == bx::alignUp( 0, 256) ); 142 | REQUIRE(256 == bx::alignUp( 1, 256) ); 143 | REQUIRE(256 == bx::alignUp( 15, 256) ); 144 | REQUIRE(256 == bx::alignUp(255, 256) ); 145 | REQUIRE(256 == bx::alignUp(256, 256) ); 146 | REQUIRE(256 == bx::alignUp(256, 256) ); 147 | REQUIRE(512 == bx::alignUp(511, 256) ); 148 | 149 | REQUIRE( 0 == bx::alignDown( 0, 16) ); 150 | REQUIRE( 0 == bx::alignDown( 1, 16) ); 151 | REQUIRE( 0 == bx::alignDown( 15, 16) ); 152 | REQUIRE( 16 == bx::alignDown( 16, 16) ); 153 | REQUIRE(240 == bx::alignDown(255, 16) ); 154 | REQUIRE(-16 == bx::alignDown(-1, 16) ); 155 | REQUIRE(-32 == bx::alignDown(-31, 16) ); 156 | } 157 | -------------------------------------------------------------------------------- /tests/unordered_map_nonpod_test.cpp: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2012-2015 Matthew Endsley 3 | * All rights reserved 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted providing that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 18 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 23 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #include "test.h" 28 | 29 | #include 30 | #include 31 | 32 | namespace { 33 | struct Foo { int bar; }; 34 | } 35 | 36 | TEST(uomap_nonpod_compiles) { 37 | 38 | // verify this compiles 39 | typedef tinystl::unordered_map map; 40 | map m; 41 | } 42 | -------------------------------------------------------------------------------- /tests/unordered_set_copyctor_test.cpp: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2012-2015 Matthew Endsley 3 | * All rights reserved 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted providing that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 18 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 23 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #include "test.h" 28 | 29 | #include 30 | #include 31 | 32 | TEST(uoset_copyctor) { 33 | 34 | // verify this compiles 35 | typedef tinystl::unordered_set set; 36 | set s; 37 | s.insert(32); 38 | set other = s; 39 | CHECK(other.find(32) != other.end()); 40 | other.clear(); 41 | CHECK(other.empty()); 42 | } 43 | -------------------------------------------------------------------------------- /tests/unordered_set_pod_test.cpp: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2012-2015 Matthew Endsley 3 | * All rights reserved 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted providing that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 18 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 23 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #include "test.h" 28 | 29 | #include 30 | #include 31 | 32 | TEST(uoset_pod_compiles) { 33 | 34 | // verify this compiles 35 | tinystl::unordered_set s; 36 | s.insert(32); 37 | s.clear(); 38 | } 39 | -------------------------------------------------------------------------------- /tests/unordered_set_test.cpp: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2012-2018 Matthew Endsley 3 | * All rights reserved 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted providing that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 18 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 23 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #include "test.h" 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | template 34 | static void comparesets(const tinystl::unordered_set& s, const tinystl::unordered_set& expected) { 35 | CHECK( s.size() == expected.size() ); 36 | 37 | typedef typename tinystl::unordered_set::const_iterator iterator; 38 | for (iterator it = expected.begin(), end = expected.end(); it != end; ++it) { 39 | CHECK( s.find(*it) != s.end() ); 40 | } 41 | } 42 | 43 | TEST(uoset_constructor) { 44 | typedef tinystl::unordered_set unordered_set; 45 | 46 | unordered_set baseline; 47 | comparesets(baseline, baseline); // test on empty 48 | baseline.insert(5); 49 | baseline.insert(6); 50 | CHECK( 2 == baseline.size() ); 51 | CHECK( baseline.find(5) != baseline.end() ); 52 | CHECK( baseline.find(6) != baseline.end() ); 53 | comparesets(baseline, baseline); 54 | 55 | { 56 | unordered_set s; 57 | 58 | CHECK( s.empty() ); 59 | CHECK( s.size() == 0 ); 60 | } 61 | 62 | { 63 | unordered_set s = baseline; 64 | 65 | comparesets(s, baseline); 66 | } 67 | 68 | { 69 | unordered_set other = baseline; 70 | unordered_set s = std::move(other); 71 | 72 | comparesets(s, baseline); 73 | CHECK( other.empty() ); 74 | } 75 | } 76 | 77 | TEST(uoset_assign) { 78 | typedef tinystl::unordered_set unordered_set; 79 | 80 | unordered_set baseline; 81 | baseline.insert(5); 82 | baseline.insert(6); 83 | CHECK( 2 == baseline.size() ); 84 | CHECK( baseline.find(5) != baseline.end() ); 85 | CHECK( baseline.find(6) != baseline.end() ); 86 | comparesets(baseline, baseline); 87 | 88 | { 89 | unordered_set s; 90 | s = baseline; 91 | 92 | comparesets(s, baseline); 93 | } 94 | 95 | { 96 | unordered_set s; 97 | for (int ii = 0; ii != 10; ++ii) 98 | s.insert(ii); 99 | 100 | s = baseline; 101 | 102 | comparesets(s, baseline); 103 | } 104 | 105 | { 106 | unordered_set other = baseline; 107 | unordered_set s; 108 | s = std::move(other); 109 | 110 | comparesets(s, baseline); 111 | CHECK( other.empty() ); 112 | } 113 | 114 | { 115 | unordered_set other = baseline; 116 | unordered_set s; 117 | for (int ii = 0; ii != 10; ++ii) 118 | s.insert(ii); 119 | 120 | s = std::move(other); 121 | 122 | comparesets(s, baseline); 123 | CHECK( other.empty() ); 124 | } 125 | } 126 | 127 | TEST(uoset_insert) { 128 | typedef tinystl::unordered_set unordered_set; 129 | typedef tinystl::pair pair; 130 | 131 | { 132 | unordered_set s; 133 | s.insert("hello"); 134 | CHECK( s.find("hello") != s.end() ); 135 | } 136 | 137 | { 138 | unordered_set s; 139 | pair p1 = s.insert("hello"); 140 | CHECK( p1.second ); 141 | CHECK( (*p1.first) == tinystl::string("hello") ); 142 | 143 | pair p2 = s.insert("hello"); 144 | CHECK( !p2.second ); 145 | CHECK( p2.first == p1.first ); 146 | } 147 | 148 | { 149 | unordered_set s; 150 | s.emplace("hello"); 151 | 152 | CHECK( s.find("hello") != s.end() ); 153 | } 154 | 155 | { 156 | unordered_set s; 157 | pair p1 = s.emplace("hello"); 158 | CHECK( p1.second ); 159 | CHECK( (*p1.first) == tinystl::string("hello") ); 160 | 161 | pair p2 = s.emplace("hello"); 162 | CHECK( !p2.second ); 163 | CHECK( p2.first == p1.first ); 164 | } 165 | 166 | { 167 | unordered_set s; 168 | tinystl::string key("hello"); 169 | s.emplace(std::move(key)); 170 | 171 | CHECK( s.find("hello") != s.end() ); 172 | CHECK( key.size() == 0 ); 173 | } 174 | } 175 | 176 | TEST(uoset_iterate) { 177 | typedef tinystl::unordered_set unordered_set; 178 | { 179 | unordered_set s; 180 | for (size_t i = 0; i < 1000; ++i) { 181 | CHECK( s.size() == i ); 182 | size_t count = 0; 183 | for (auto it = s.begin(); it != s.end(); ++it) { 184 | count++; 185 | } 186 | CHECK( count == i ); 187 | 188 | s.insert(int(17 * i)); 189 | } 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /tests/url_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2025 Branimir Karadzic. All rights reserved. 3 | * License: https://github.com/bkaradzic/bx/blob/master/LICENSE 4 | */ 5 | 6 | #include "test.h" 7 | #include 8 | #include 9 | 10 | struct UrlTest 11 | { 12 | bool result; 13 | const char* url; 14 | const char* tokens[bx::UrlView::Count]; 15 | }; 16 | 17 | static const UrlTest s_urlTest[] = 18 | { 19 | { true 20 | , "scheme://username:password@host.rs:80/this/is/path/index.php?query=\"value\"#fragment", 21 | { "scheme", "username", "password", "host.rs", "80", "/this/is/path/index.php", "query=\"value\"", "fragment" } 22 | }, 23 | { true 24 | , "scheme://host.rs/", 25 | { "scheme", "", "", "host.rs", "", "/", "", "" }, 26 | }, 27 | { true 28 | , "scheme://host.rs:1389/", 29 | { "scheme", "", "", "host.rs", "1389", "/", "", "" }, 30 | }, 31 | { true 32 | , "host.rs/abvgd.html", 33 | { "", "", "", "host.rs", "", "/abvgd.html", "", "" }, 34 | }, 35 | { true 36 | , "https://192.168.0.1:8080/", 37 | { "https", "", "", "192.168.0.1", "8080", "/", "", "" }, 38 | }, 39 | 40 | { true 41 | , "file:///d:/tmp/archive.tar.gz", 42 | { "file", "", "", "", "", "/d:/tmp/archive.tar.gz", "", "" }, 43 | }, 44 | }; 45 | 46 | TEST_CASE("tokenizeUrl", "[url][string]") 47 | { 48 | bx::UrlView url; 49 | 50 | for (uint32_t ii = 0; ii < BX_COUNTOF(s_urlTest); ++ii) 51 | { 52 | const UrlTest& urlTest = s_urlTest[ii]; 53 | 54 | bool result = url.parse(urlTest.url); 55 | REQUIRE(urlTest.result == result); 56 | 57 | if (result) 58 | { 59 | for (uint32_t token = 0; token < bx::UrlView::Count; ++token) 60 | { 61 | // char tmp[1024]; 62 | // strCopy(tmp, BX_COUNTOF(tmp), url.get(bx::UrlView::Enum(token)) ); 63 | // printf("`%s`, expected: `%s`\n", tmp, urlTest.tokens[token]); 64 | 65 | REQUIRE(0 == bx::strCmp(urlTest.tokens[token], url.get(bx::UrlView::Enum(token)) ) ); 66 | } 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /tests/vector_header_test.cpp: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2012-1015 Matthew Endsley 3 | * All rights reserved 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted providing that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 18 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 23 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | // Test that header is standalone 28 | #include 29 | #include 30 | -------------------------------------------------------------------------------- /tests/vector_shrinktofit_test.cpp: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2012-2014 Matthew Endsley 3 | * All rights reserved 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted providing that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 18 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 23 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #include "test.h" 28 | 29 | #include 30 | #include 31 | 32 | TEST(vector_shrinktofit) { 33 | typedef tinystl::vector vector; 34 | 35 | { 36 | vector v; 37 | CHECK(v.capacity() == 0); 38 | v.clear(); 39 | v.shrink_to_fit(); 40 | CHECK(v.capacity() == 0); 41 | } 42 | 43 | { 44 | vector v(10, 0); 45 | CHECK(v.capacity() >= 10); 46 | v.shrink_to_fit(); 47 | CHECK(v.capacity() == 10); 48 | } 49 | 50 | { 51 | vector v(10, 0); 52 | CHECK(v.capacity() >= 10); 53 | v.erase(v.end() - 1, v.end()); 54 | CHECK(v.size() == 9); 55 | CHECK(v.capacity() >= 10); 56 | v.shrink_to_fit(); 57 | CHECK(v.capacity() == 9); 58 | } 59 | 60 | { 61 | vector v(10, 0); 62 | CHECK(v.capacity() >= 10); 63 | const int* ptr = v.data(); 64 | v.shrink_to_fit(); 65 | CHECK(v.capacity() >= 10); 66 | CHECK(v.data() == ptr); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /tools/bin/darwin/bin2c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bkaradzic/bx/5a20afef842daa0a76b1d3ed11440c96cab94745/tools/bin/darwin/bin2c -------------------------------------------------------------------------------- /tools/bin/darwin/genie: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bkaradzic/bx/5a20afef842daa0a76b1d3ed11440c96cab94745/tools/bin/darwin/genie -------------------------------------------------------------------------------- /tools/bin/darwin/ninja: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bkaradzic/bx/5a20afef842daa0a76b1d3ed11440c96cab94745/tools/bin/darwin/ninja -------------------------------------------------------------------------------- /tools/bin/linux/bin2c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bkaradzic/bx/5a20afef842daa0a76b1d3ed11440c96cab94745/tools/bin/linux/bin2c -------------------------------------------------------------------------------- /tools/bin/linux/genie: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bkaradzic/bx/5a20afef842daa0a76b1d3ed11440c96cab94745/tools/bin/linux/genie -------------------------------------------------------------------------------- /tools/bin/linux/ninja: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bkaradzic/bx/5a20afef842daa0a76b1d3ed11440c96cab94745/tools/bin/linux/ninja -------------------------------------------------------------------------------- /tools/bin/windows/bin2c.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bkaradzic/bx/5a20afef842daa0a76b1d3ed11440c96cab94745/tools/bin/windows/bin2c.exe -------------------------------------------------------------------------------- /tools/bin/windows/genie.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bkaradzic/bx/5a20afef842daa0a76b1d3ed11440c96cab94745/tools/bin/windows/genie.exe -------------------------------------------------------------------------------- /tools/bin/windows/ninja.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bkaradzic/bx/5a20afef842daa0a76b1d3ed11440c96cab94745/tools/bin/windows/ninja.exe --------------------------------------------------------------------------------