├── .gitattributes ├── .github └── workflows │ ├── build-linux-clang.yml │ ├── build-linux-gcc.yml │ ├── build-macos.yml │ ├── build-windows-cygwin.yml │ ├── build-windows-mingw.yml │ ├── build-windows-msys2.yml │ ├── build-windows-vs.yml │ └── doxygen.yml ├── .gitignore ├── .gitlinks ├── CMakeLists.txt ├── LICENSE ├── README.md ├── TODO.md ├── bin └── .gitignore ├── documents └── Doxyfile ├── examples ├── algorithms_token_bucket.cpp ├── cache_filecache.cpp ├── cache_memcache.cpp ├── common_flags.cpp ├── common_function.cpp ├── common_uint128.cpp ├── common_uint256.cpp ├── containers_bintree.cpp ├── containers_flatmap.cpp ├── containers_hashmap.cpp ├── containers_list.cpp ├── containers_queue.cpp ├── containers_stack.cpp ├── errors_exceptions_handler.cpp ├── errors_fatal.cpp ├── errors_system_error.cpp ├── filesystem_directory.cpp ├── filesystem_file.cpp ├── filesystem_path.cpp ├── filesystem_symlink.cpp ├── filesystem_touch.cpp ├── math_math.cpp ├── memory_arena.cpp ├── memory_leaks.cpp ├── memory_memory.cpp ├── memory_pool.cpp ├── string_encoding.cpp ├── string_format.cpp ├── string_utils.cpp ├── system_console.cpp ├── system_cpu.cpp ├── system_dll.cpp ├── system_environment.cpp ├── system_pipe.cpp ├── system_process.cpp ├── system_process_pipes.cpp ├── system_shared_memory.cpp ├── system_shared_type.cpp ├── system_source_location.cpp ├── system_stack_trace.cpp ├── system_uuid.cpp ├── threads_barrier.cpp ├── threads_condition_variable.cpp ├── threads_critical_section.cpp ├── threads_event_auto_reset.cpp ├── threads_event_manual_reset.cpp ├── threads_file_lock.cpp ├── threads_latch_multi.cpp ├── threads_latch_single.cpp ├── threads_mpmc_ring_queue.cpp ├── threads_mpsc_linked_queue.cpp ├── threads_mpsc_ring_buffer.cpp ├── threads_mpsc_ring_queue.cpp ├── threads_mutex.cpp ├── threads_named_condition_variable.cpp ├── threads_named_critical_section.cpp ├── threads_named_event_auto_reset.cpp ├── threads_named_event_manual_reset.cpp ├── threads_named_mutex.cpp ├── threads_named_rw_lock.cpp ├── threads_named_semaphore.cpp ├── threads_rw_lock.cpp ├── threads_semaphore.cpp ├── threads_seq_lock.cpp ├── threads_spin_barrier.cpp ├── threads_spin_lock.cpp ├── threads_spsc_ring_buffer.cpp ├── threads_spsc_ring_queue.cpp ├── threads_thread.cpp ├── threads_wait_batcher.cpp ├── threads_wait_queue.cpp ├── threads_wait_ring.cpp ├── time_time.cpp ├── time_timespan.cpp ├── time_timestamp.cpp ├── time_timezone.cpp ├── utility_singleton.cpp └── utility_static_constructor.cpp ├── images ├── BinTree.png ├── BinTreeRB.png ├── BinTreeSplay-Zig.png ├── BinTreeSplay-Zigzag.png ├── BinTreeSplay-Zigzig.png ├── List.png ├── Queue.png ├── Stack.png └── TokenBucket.png ├── include ├── algorithms │ ├── token_bucket.h │ └── token_bucket.inl ├── cache │ ├── filecache.h │ ├── filecache.inl │ ├── memcache.h │ └── memcache.inl ├── common │ ├── flags.h │ ├── flags.inl │ ├── function.h │ ├── function.inl │ ├── reader.h │ ├── uint128.h │ ├── uint128.inl │ ├── uint256.h │ ├── uint256.inl │ ├── version.h │ └── writer.h ├── containers │ ├── bintree.h │ ├── bintree.inl │ ├── bintree_aa.h │ ├── bintree_aa.inl │ ├── bintree_avl.h │ ├── bintree_avl.inl │ ├── bintree_rb.h │ ├── bintree_rb.inl │ ├── bintree_splay.h │ ├── bintree_splay.inl │ ├── flatmap.h │ ├── flatmap.inl │ ├── hashmap.h │ ├── hashmap.inl │ ├── list.h │ ├── list.inl │ ├── queue.h │ ├── queue.inl │ ├── stack.h │ └── stack.inl ├── errors │ ├── exceptions.h │ ├── exceptions.inl │ ├── exceptions_handler.h │ ├── fatal.h │ └── system_error.h ├── filesystem │ ├── directory.h │ ├── directory.inl │ ├── directory_iterator.h │ ├── directory_iterator.inl │ ├── exceptions.h │ ├── file.h │ ├── file.inl │ ├── filesystem.h │ ├── path.h │ ├── path.inl │ ├── symlink.h │ └── symlink.inl ├── math │ ├── math.h │ └── math.inl ├── memory │ ├── allocator.h │ ├── allocator.inl │ ├── allocator_arena.h │ ├── allocator_arena.inl │ ├── allocator_heap.h │ ├── allocator_heap.inl │ ├── allocator_null.h │ ├── allocator_null.inl │ ├── allocator_pool.h │ ├── allocator_pool.inl │ ├── allocator_stack.h │ ├── allocator_stack.inl │ ├── memory.h │ ├── memory.inl │ ├── memory_leaks.h │ └── memory_leaks_debug.h ├── string │ ├── encoding.h │ ├── format.h │ ├── format.inl │ ├── string_utils.h │ └── string_utils.inl ├── system │ ├── console.h │ ├── console.inl │ ├── cpu.h │ ├── dll.h │ ├── dll.inl │ ├── environment.h │ ├── exceptions.h │ ├── pipe.h │ ├── pipe.inl │ ├── process.h │ ├── process.inl │ ├── shared_memory.h │ ├── shared_type.h │ ├── shared_type.inl │ ├── source_location.h │ ├── source_location.inl │ ├── stack_trace.h │ ├── stack_trace.inl │ ├── stack_trace_manager.h │ ├── stream.h │ ├── stream.inl │ ├── uuid.h │ └── uuid.inl ├── threads │ ├── barrier.h │ ├── condition_variable.h │ ├── condition_variable.inl │ ├── critical_section.h │ ├── event_auto_reset.h │ ├── event_manual_reset.h │ ├── file_lock.h │ ├── latch.h │ ├── latch.inl │ ├── locker.h │ ├── mpmc_ring_queue.h │ ├── mpmc_ring_queue.inl │ ├── mpsc_linked_batcher.h │ ├── mpsc_linked_batcher.inl │ ├── mpsc_linked_queue.h │ ├── mpsc_linked_queue.inl │ ├── mpsc_ring_buffer.h │ ├── mpsc_ring_buffer.inl │ ├── mpsc_ring_queue.h │ ├── mpsc_ring_queue.inl │ ├── mutex.h │ ├── named_condition_variable.h │ ├── named_condition_variable.inl │ ├── named_critical_section.h │ ├── named_event_auto_reset.h │ ├── named_event_manual_reset.h │ ├── named_mutex.h │ ├── named_rw_lock.h │ ├── named_semaphore.h │ ├── rw_lock.h │ ├── semaphore.h │ ├── seq_lock.h │ ├── seq_lock.inl │ ├── spin_barrier.h │ ├── spin_barrier.inl │ ├── spin_lock.h │ ├── spin_lock.inl │ ├── spsc_ring_buffer.h │ ├── spsc_ring_buffer.inl │ ├── spsc_ring_queue.h │ ├── spsc_ring_queue.inl │ ├── thread.h │ ├── thread.inl │ ├── wait_batcher.h │ ├── wait_batcher.inl │ ├── wait_queue.h │ ├── wait_queue.inl │ ├── wait_ring.h │ └── wait_ring.inl ├── time │ ├── time.h │ ├── time.inl │ ├── timespan.h │ ├── timespan.inl │ ├── timestamp.h │ ├── timestamp.inl │ ├── timezone.h │ └── timezone.inl └── utility │ ├── countof.h │ ├── endian.h │ ├── endian.inl │ ├── iostream.h │ ├── resource.h │ ├── singleton.h │ ├── static_constructor.h │ ├── static_constructor.inl │ └── validate_aligned_storage.h ├── modules ├── CMakeLists.txt ├── Catch2.cmake ├── CppBenchmark.cmake ├── fmt.cmake └── vld.cmake ├── performance ├── common_function.cpp ├── containers_bintree.cpp ├── containers_flatmap.cpp ├── containers_hashmap.cpp ├── filesystem_file.cpp ├── flat_hash_map │ ├── bytell_hash_map.hpp │ └── flat_hash_map.hpp ├── hopscotch-map │ ├── bhopscotch_map.h │ ├── bhopscotch_set.h │ ├── hopscotch_growth_policy.h │ ├── hopscotch_hash.h │ ├── hopscotch_map.h │ └── hopscotch_set.h ├── memory_managers.cpp ├── ordered-map │ ├── ordered_hash.h │ ├── ordered_map.h │ └── ordered_set.h ├── robin-map │ ├── robin_growth_policy.h │ ├── robin_hash.h │ ├── robin_map.h │ └── robin_set.h ├── sparse-map │ ├── sparse_growth_policy.h │ ├── sparse_hash.h │ ├── sparse_map.h │ └── sparse_set.h ├── string_format.cpp ├── system_pipe.cpp ├── system_stack_trace.cpp ├── system_uuid.cpp ├── threads_critical_section.cpp ├── threads_file_lock.cpp ├── threads_mpmc_ring_queue.cpp ├── threads_mpsc_linked_batcher.cpp ├── threads_mpsc_linked_queue.cpp ├── threads_mpsc_ring_buffer.cpp ├── threads_mpsc_ring_queue.cpp ├── threads_mutex.cpp ├── threads_named_critical_section.cpp ├── threads_named_mutex.cpp ├── threads_named_rw_lock.cpp ├── threads_named_semaphore.cpp ├── threads_rw_lock.cpp ├── threads_semaphore.cpp ├── threads_seq_lock.cpp ├── threads_spin_lock.cpp ├── threads_spsc_ring_buffer.cpp ├── threads_spsc_ring_queue.cpp ├── threads_thread.cpp ├── threads_wait_batcher.cpp ├── threads_wait_queue.cpp ├── threads_wait_ring.cpp ├── time_time.cpp ├── time_timestamp.cpp └── time_timezone.cpp ├── plugins ├── function │ └── function.cpp └── interface │ ├── interface.cpp │ └── interface.h ├── source ├── algorithms │ └── token_bucket.cpp ├── cache │ └── filecache.cpp ├── common │ ├── reader.cpp │ ├── uint128.cpp │ ├── uint256.cpp │ └── writer.cpp ├── errors │ ├── exceptions.cpp │ ├── exceptions_handler.cpp │ ├── fatal.cpp │ └── system_error.cpp ├── filesystem │ ├── directory.cpp │ ├── directory_iterator.cpp │ ├── exceptions.cpp │ ├── file.cpp │ ├── path.cpp │ └── symlink.cpp ├── math │ └── math.cpp ├── memory │ └── memory.cpp ├── string │ ├── encoding.cpp │ └── string_utils.cpp ├── system │ ├── console.cpp │ ├── cpu.cpp │ ├── dll.cpp │ ├── environment.cpp │ ├── pipe.cpp │ ├── process.cpp │ ├── shared_memory.cpp │ ├── stack_trace.cpp │ ├── stack_trace_manager.cpp │ ├── stream.cpp │ └── uuid.cpp ├── threads │ ├── barrier.cpp │ ├── condition_variable.cpp │ ├── critical_section.cpp │ ├── event_auto_reset.cpp │ ├── event_manual_reset.cpp │ ├── file_lock.cpp │ ├── latch.cpp │ ├── mutex.cpp │ ├── named_condition_variable.cpp │ ├── named_critical_section.cpp │ ├── named_event_auto_reset.cpp │ ├── named_event_manual_reset.cpp │ ├── named_mutex.cpp │ ├── named_rw_lock.cpp │ ├── named_semaphore.cpp │ ├── rw_lock.cpp │ ├── semaphore.cpp │ └── thread.cpp └── time │ ├── time.cpp │ ├── timestamp.cpp │ └── timezone.cpp └── tests ├── test.cpp ├── test.h ├── test_algorithms_token_bucket.cpp ├── test_cache_filecache.cpp ├── test_cache_memcache.cpp ├── test_common_flags.cpp ├── test_common_function.cpp ├── test_common_uint.cpp ├── test_containers_bintree.cpp ├── test_containers_flatmap.cpp ├── test_containers_hashmap.cpp ├── test_containers_list.cpp ├── test_containers_queue.cpp ├── test_containers_stack.cpp ├── test_errors_system_error.cpp ├── test_filesystem_directory.cpp ├── test_filesystem_file.cpp ├── test_filesystem_path.cpp ├── test_filesystem_symlink.cpp ├── test_math_math.cpp ├── test_memory_allocators.cpp ├── test_memory_memory.cpp ├── test_string_encoding.cpp ├── test_string_format.cpp ├── test_string_utils.cpp ├── test_system_cpu.cpp ├── test_system_dll.cpp ├── test_system_environment.cpp ├── test_system_pipe.cpp ├── test_system_process.cpp ├── test_system_shared_memory.cpp ├── test_system_shared_type.cpp ├── test_system_source_location.cpp ├── test_system_stack_trace.cpp ├── test_system_uuid.cpp ├── test_threads_barrier.cpp ├── test_threads_condition_variable.cpp ├── test_threads_critical_section.cpp ├── test_threads_event_auto_reset.cpp ├── test_threads_event_manual_reset.cpp ├── test_threads_file_lock.cpp ├── test_threads_latch.cpp ├── test_threads_mpmc_ring_queue.cpp ├── test_threads_mpsc_linked_batcher.cpp ├── test_threads_mpsc_linked_queue.cpp ├── test_threads_mpsc_ring_buffer.cpp ├── test_threads_mpsc_ring_queue.cpp ├── test_threads_mutex.cpp ├── test_threads_named_critical_section.cpp ├── test_threads_named_event_auto_reset.cpp ├── test_threads_named_event_manual_reset.cpp ├── test_threads_named_mutex.cpp ├── test_threads_named_rw_lock.cpp ├── test_threads_named_semaphore.cpp ├── test_threads_rw_lock.cpp ├── test_threads_semaphore.cpp ├── test_threads_seq_lock.cpp ├── test_threads_spin_barrier.cpp ├── test_threads_spin_lock.cpp ├── test_threads_spsc_ring_buffer.cpp ├── test_threads_spsc_ring_queue.cpp ├── test_threads_thread.cpp ├── test_threads_wait_batcher.cpp ├── test_threads_wait_queue.cpp ├── test_threads_wait_ring.cpp ├── test_time_time.cpp ├── test_time_timespan.cpp ├── test_time_timestamp.cpp ├── test_time_timezone.cpp ├── test_utility_endian.cpp ├── test_utility_singleton.cpp └── test_utility_static_constructor.cpp /.gitattributes: -------------------------------------------------------------------------------- 1 | bin/* linguist-vendored 2 | build/* linguist-vendored 3 | cmake/* linguist-vendored 4 | documents/* linguist-vendored 5 | images/* linguist-vendored 6 | modules/* linguist-vendored 7 | temp/* linguist-vendored 8 | -------------------------------------------------------------------------------- /.github/workflows/build-linux-clang.yml: -------------------------------------------------------------------------------- 1 | name: Linux (clang) 2 | 3 | on: 4 | push: 5 | pull_request: 6 | workflow_dispatch: 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v4 13 | 14 | - name: "Setup required packages" 15 | run: sudo apt-get install -y binutils-dev libc++-dev libssl-dev uuid-dev 16 | 17 | - name: "Setup clang" 18 | uses: egor-tensin/setup-clang@v1 19 | 20 | - name: "Setup cmake" 21 | run: cmake --version 22 | 23 | - name: "Setup gil" 24 | run: | 25 | pip3 install gil 26 | gil update 27 | 28 | - name: "Build" 29 | run: | 30 | cd build 31 | ./unix.sh 32 | -------------------------------------------------------------------------------- /.github/workflows/build-linux-gcc.yml: -------------------------------------------------------------------------------- 1 | name: Linux (gcc) 2 | 3 | on: 4 | push: 5 | pull_request: 6 | workflow_dispatch: 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v4 13 | 14 | - name: "Setup required packages" 15 | run: sudo apt-get install -y binutils-dev libssl-dev uuid-dev 16 | 17 | - name: "Setup gcc" 18 | uses: egor-tensin/setup-gcc@v1 19 | 20 | - name: "Setup cmake" 21 | run: cmake --version 22 | 23 | - name: "Setup gil" 24 | run: | 25 | pip3 install gil 26 | gil update 27 | 28 | - name: "Build" 29 | run: | 30 | cd build 31 | ./unix.sh 32 | -------------------------------------------------------------------------------- /.github/workflows/build-macos.yml: -------------------------------------------------------------------------------- 1 | name: MacOS 2 | 3 | on: 4 | push: 5 | pull_request: 6 | workflow_dispatch: 7 | 8 | jobs: 9 | build: 10 | runs-on: macos-latest 11 | steps: 12 | - uses: actions/checkout@v4 13 | 14 | - name: "Setup python" 15 | uses: actions/setup-python@v4 16 | with: 17 | python-version: '3.x' 18 | 19 | - name: "Setup cmake" 20 | run: cmake --version 21 | 22 | - name: "Setup gil" 23 | run: | 24 | pip3 install gil 25 | gil update 26 | 27 | - name: "Build" 28 | run: | 29 | cd build 30 | ./unix.sh 31 | -------------------------------------------------------------------------------- /.github/workflows/build-windows-cygwin.yml: -------------------------------------------------------------------------------- 1 | name: Windows (Cygwin) 2 | 3 | on: 4 | push: 5 | pull_request: 6 | workflow_dispatch: 7 | 8 | jobs: 9 | build: 10 | runs-on: windows-latest 11 | defaults: 12 | run: 13 | shell: C:\cygwin\bin\bash.exe --login -o igncr {0} 14 | steps: 15 | - name: "Setup git" 16 | shell: cmd 17 | run: git config --global core.autocrlf input 18 | 19 | - uses: actions/checkout@v4 20 | 21 | - name: "Setup Cygwin" 22 | uses: cygwin/cygwin-install-action@v2 23 | with: 24 | check-sig: false 25 | platform: x86_64 26 | packages: automake make cmake gcc-g++ doxygen graphviz libssl-devel libuuid-devel 27 | 28 | - name: "Setup cmake" 29 | run: cmake --version 30 | 31 | - name: "Setup gil" 32 | shell: cmd 33 | run: | 34 | pip3 install gil 35 | gil update 36 | 37 | - name: "Build" 38 | run: | 39 | cd $GITHUB_WORKSPACE/build 40 | ./unix.sh 41 | -------------------------------------------------------------------------------- /.github/workflows/build-windows-mingw.yml: -------------------------------------------------------------------------------- 1 | name: Windows (MinGW) 2 | 3 | on: 4 | push: 5 | pull_request: 6 | workflow_dispatch: 7 | 8 | jobs: 9 | build: 10 | runs-on: windows-latest 11 | steps: 12 | - uses: actions/checkout@v4 13 | 14 | - name: "Setup cmake" 15 | run: cmake --version 16 | 17 | - name: "Setup gil" 18 | run: | 19 | pip3 install gil 20 | gil update 21 | 22 | - name: "Build" 23 | env: 24 | INCLUDE: C:\mingw64\x86_64-w64-mingw32\include 25 | LIB: C:\mingw64\x86_64-w64-mingw32\lib 26 | run: | 27 | cd build 28 | ./mingw.bat 29 | -------------------------------------------------------------------------------- /.github/workflows/build-windows-msys2.yml: -------------------------------------------------------------------------------- 1 | name: Windows (MSYS2) 2 | 3 | on: 4 | push: 5 | pull_request: 6 | workflow_dispatch: 7 | 8 | jobs: 9 | build: 10 | runs-on: windows-latest 11 | defaults: 12 | run: 13 | shell: msys2 {0} 14 | steps: 15 | - uses: actions/checkout@v4 16 | 17 | - name: "Setup MSYS2" 18 | uses: msys2/setup-msys2@v2 19 | with: 20 | msystem: UCRT64 21 | release: false 22 | install: >- 23 | git 24 | make 25 | mingw-w64-ucrt-x86_64-cmake 26 | mingw-w64-ucrt-x86_64-gcc 27 | mingw-w64-ucrt-x86_64-doxygen 28 | mingw-w64-ucrt-x86_64-graphviz 29 | msys2-w32api-runtime 30 | python-pip 31 | 32 | - name: "Setup cmake" 33 | run: cmake --version 34 | 35 | - name: "Setup gil" 36 | run: | 37 | pip3 install gil --break-system-packages 38 | gil update 39 | 40 | - name: "Build" 41 | env: 42 | INCLUDE: C:\msys64\usr\include\w32api 43 | LIB: C:\msys64\usr\lib\w32api 44 | run: | 45 | cd build 46 | ./unix.sh 47 | -------------------------------------------------------------------------------- /.github/workflows/build-windows-vs.yml: -------------------------------------------------------------------------------- 1 | name: Windows (Visual Studio) 2 | 3 | on: 4 | push: 5 | pull_request: 6 | workflow_dispatch: 7 | 8 | jobs: 9 | build: 10 | runs-on: windows-latest 11 | steps: 12 | - uses: actions/checkout@v4 13 | 14 | - name: "Setup Visual Studio" 15 | uses: egor-tensin/vs-shell@v2 16 | 17 | - name: "Setup cmake" 18 | run: cmake --version 19 | 20 | - name: "Setup gil" 21 | run: | 22 | pip3 install gil 23 | gil update 24 | 25 | - name: "Build" 26 | run: | 27 | cd build 28 | ./vs.bat 29 | -------------------------------------------------------------------------------- /.github/workflows/doxygen.yml: -------------------------------------------------------------------------------- 1 | name: Doxygen 2 | 3 | on: 4 | push: 5 | pull_request: 6 | workflow_dispatch: 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: "Setup git" 13 | run: | 14 | git config --global user.name "${{ github.actor }}" 15 | git config --global user.email "${{ github.actor }}@users.noreply.github.com" 16 | 17 | - uses: actions/checkout@v4 18 | 19 | - name: "Setup cmake" 20 | run: cmake --version 21 | 22 | - name: "Setup doxygen" 23 | run: | 24 | sudo apt-get -y install doxygen graphviz binutils-dev 25 | doxygen --version 26 | dot -V 27 | 28 | - name: "Setup gil" 29 | run: | 30 | pip3 install gil 31 | gil update 32 | 33 | - name: "Doxygen" 34 | env: 35 | GITHUB_ACTOR: ${{ github.actor }} 36 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 37 | run: | 38 | cd build/Unix 39 | ./01-generate.sh 40 | ./05-doxygen.sh 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Build 2 | build 3 | 4 | # CMake 5 | build 6 | cmake 7 | cmake-build-* 8 | 9 | # Ctags files 10 | tags 11 | tags.idx 12 | 13 | # Modules 14 | modules/* 15 | !modules/CMakeLists.txt 16 | !modules/*.cmake 17 | 18 | # Temporary 19 | .idea 20 | temp 21 | -------------------------------------------------------------------------------- /.gitlinks: -------------------------------------------------------------------------------- 1 | # Modules 2 | Catch2 modules/Catch2 https://github.com/catchorg/Catch2.git devel 3 | CppBenchmark modules/CppBenchmark https://github.com/chronoxor/CppBenchmark.git master 4 | fmt modules/fmt https://github.com/fmtlib/fmt.git master 5 | vld modules/vld https://github.com/chronoxor/vld.git master 6 | 7 | # Scripts 8 | build build https://github.com/chronoxor/CppBuildScripts.git master 9 | cmake cmake https://github.com/chronoxor/CppCMakeScripts.git master 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016-2024 Ivan Shynkarenka 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | # CppCommon todo 2 | -------------------------------------------------------------------------------- /bin/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore 5 | -------------------------------------------------------------------------------- /examples/algorithms_token_bucket.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file algorithms_token_bucket.cpp 3 | \brief Token bucket rate limit algorithm example 4 | \author Ivan Shynkarenka 5 | \date 16.08.2017 6 | \copyright MIT License 7 | */ 8 | 9 | #include "algorithms/token_bucket.h" 10 | 11 | #include "threads/thread.h" 12 | #include "time/timestamp.h" 13 | 14 | #include 15 | #include 16 | 17 | int main(int argc, char** argv) 18 | { 19 | std::cout << "Press Enter to stop..." << std::endl; 20 | 21 | // Token bucket with one token per second rate and ten burst tokens 22 | CppCommon::TokenBucket tb(1, 10); 23 | 24 | std::atomic stop(false); 25 | std::thread worker = std::thread([&stop, &tb]() 26 | { 27 | while (!stop) 28 | { 29 | if (tb.Consume()) 30 | std::cout << (CppCommon::UtcTimestamp().seconds() % 60) << " - Token consumed" << std::endl; 31 | else 32 | CppCommon::Thread::Yield(); 33 | } 34 | }); 35 | 36 | // Wait for input 37 | std::cin.get(); 38 | 39 | // Stop the worker thread 40 | stop = true; 41 | 42 | // Wait for the worker thread 43 | worker.join(); 44 | 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /examples/cache_filecache.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file cache_filecache.cpp 3 | \brief File cache example 4 | \author Ivan Shynkarenka 5 | \date 14.05.2019 6 | \copyright MIT License 7 | */ 8 | 9 | #include "cache/filecache.h" 10 | #include "threads/thread.h" 11 | 12 | #include 13 | 14 | int main(int argc, char** argv) 15 | { 16 | CppCommon::FileCache cache; 17 | 18 | // Fill the file cache 19 | cache.insert("123", "123"); 20 | cache.insert("456", "456", CppCommon::Timespan::milliseconds(100)); 21 | 22 | std::pair result; 23 | 24 | // Get the memory cache values 25 | result = cache.find("123"); 26 | if (result.first) 27 | std::cout << "Found: " << result.second << std::endl; 28 | result = cache.find("456"); 29 | if (result.first) 30 | std::cout << "Found: " << result.second << std::endl; 31 | 32 | // Sleep for a while... 33 | CppCommon::Thread::SleepFor(CppCommon::Timespan::milliseconds(200)); 34 | 35 | // Watchdog the memory cache to erase entries with timeout 36 | cache.watchdog(); 37 | 38 | // Get the memory cache values 39 | result = cache.find("123"); 40 | if (result.first) 41 | std::cout << "Found: " << result.second << std::endl; 42 | result = cache.find("456"); 43 | if (result.first) 44 | std::cout << "Found: " << result.second << std::endl; 45 | 46 | return 0; 47 | } 48 | -------------------------------------------------------------------------------- /examples/cache_memcache.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file cache_memcache.cpp 3 | \brief Memory cache example 4 | \author Ivan Shynkarenka 5 | \date 14.05.2019 6 | \copyright MIT License 7 | */ 8 | 9 | #include "cache/memcache.h" 10 | #include "threads/thread.h" 11 | 12 | #include 13 | 14 | int main(int argc, char** argv) 15 | { 16 | CppCommon::MemCache cache; 17 | 18 | // Fill the memory cache 19 | cache.insert("123", 123); 20 | cache.insert("456", 456, CppCommon::Timespan::milliseconds(100)); 21 | 22 | int result; 23 | 24 | // Get the memory cache values 25 | if (cache.find("123", result)) 26 | std::cout << "Found: " << result << std::endl; 27 | if (cache.find("456", result)) 28 | std::cout << "Found: " << result << std::endl; 29 | 30 | // Sleep for a while... 31 | CppCommon::Thread::SleepFor(CppCommon::Timespan::milliseconds(200)); 32 | 33 | // Watchdog the memory cache to erase entries with timeout 34 | cache.watchdog(); 35 | 36 | // Get the memory cache values 37 | if (cache.find("123", result)) 38 | std::cout << "Found: " << result << std::endl; 39 | if (cache.find("456", result)) 40 | std::cout << "Found: " << result << std::endl; 41 | 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /examples/common_flags.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file common_flags.cpp 3 | \brief Enum-based flags example 4 | \author Ivan Shynkarenka 5 | \date 25.08.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "common/flags.h" 10 | 11 | #include 12 | 13 | enum class MyFlags 14 | { 15 | None = 0x0, 16 | One = 0x1, 17 | Two = 0x2, 18 | Three = 0x4, 19 | Four = 0x8 20 | }; 21 | 22 | // Register enum as flags to enable AND/OR/XOR logical operators with enum values! 23 | ENUM_FLAGS(MyFlags) 24 | 25 | int main(int argc, char** argv) 26 | { 27 | auto mask = MyFlags::One | MyFlags::Two | MyFlags::Three; 28 | if (mask & MyFlags::One) 29 | std::cout << "MyFlags::One is set" << std::endl; 30 | if (mask & MyFlags::Two) 31 | std::cout << "MyFlags::Two is set" << std::endl; 32 | if (mask & MyFlags::Three) 33 | std::cout << "MyFlags::Three is set" << std::endl; 34 | if (mask & MyFlags::Four) 35 | std::cout << "MyFlags::Four is set" << std::endl; 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /examples/common_function.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file common_function.cpp 3 | \brief Allocation free function example 4 | \author Ivan Shynkarenka 5 | \date 18.08.2017 6 | \copyright MIT License 7 | */ 8 | 9 | #include "common/function.h" 10 | 11 | #include 12 | 13 | int test(int v) 14 | { 15 | return v + 100; 16 | } 17 | 18 | class Class 19 | { 20 | public: 21 | int operator()(int v) { return v + 200; } 22 | int test(int v) { return v + 300; } 23 | static int static_test(int v) { return v + 400; } 24 | }; 25 | 26 | int main(int argc, char** argv) 27 | { 28 | CppCommon::Function function; 29 | 30 | // Simple function call 31 | function = test; 32 | std::cout << "test(11) = " << function(11) << std::endl; 33 | 34 | Class instance; 35 | 36 | // Class operator() call 37 | function = instance; 38 | std::cout << "Class::operator(22) = " << function(22) << std::endl; 39 | 40 | // Class method call 41 | function = std::bind(&Class::test, &instance, std::placeholders::_1); 42 | std::cout << "Class::test(33) = " << function(33) << std::endl; 43 | 44 | // Class static method call 45 | function = Class::static_test; 46 | std::cout << "Class::static_test(44) = " << function(44) << std::endl; 47 | 48 | // Lambda function call 49 | auto lambda = [=](int v) { return v + 500; }; 50 | function = lambda; 51 | std::cout << "lambda(55) = " << function(55) << std::endl; 52 | 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /examples/common_uint128.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file common_uint128.cpp 3 | \brief Unsigned 128-bit integer type example 4 | \author Ivan Shynkarenka 5 | \date 13.10.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "common/uint128.h" 10 | 11 | #include 12 | 13 | int main(int argc, char** argv) 14 | { 15 | CppCommon::uint128_t a(0xABCDEFull); 16 | CppCommon::uint128_t b(0x12345ull, 0xFEDBCA9876543210ull); 17 | 18 | std::cout << a << " * " << b << " = " << (a * b) << std::endl; 19 | std::cout << b << " / " << a << " = " << (b / a) << std::endl; 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /examples/common_uint256.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file common_uint128.cpp 3 | \brief Unsigned 128-bit integer type example 4 | \author Ivan Shynkarenka 5 | \date 13.10.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "common/uint256.h" 10 | 11 | #include 12 | 13 | int main(int argc, char** argv) 14 | { 15 | CppCommon::uint256_t a(0xFEDBCA9876543210ull); 16 | CppCommon::uint256_t b(0ull, 0ull, 0xFEDBCA9876543210ull, 0xFEDBCA9876543210ull); 17 | 18 | std::cout << a << " * " << b << " = " << (a * b) << std::endl; 19 | std::cout << b << " / " << a << " = " << (b / a) << std::endl; 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /examples/containers_bintree.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file containers_bintree.cpp 3 | \brief Intrusive binary tree container example 4 | \author Ivan Shynkarenka 5 | \date 22.06.2017 6 | \copyright MIT License 7 | */ 8 | 9 | #include "containers/bintree.h" 10 | 11 | #include 12 | 13 | struct MyBinTreeNode : public CppCommon::BinTree::Node 14 | { 15 | int value; 16 | MyBinTreeNode(int v) : value(v) {} 17 | friend bool operator<(const MyBinTreeNode& node1, const MyBinTreeNode& node2) 18 | { return node1.value < node2.value; } 19 | }; 20 | 21 | int main(int argc, char** argv) 22 | { 23 | assert("Duplicate node can not be inserted into the binary tree!"); 24 | 25 | CppCommon::BinTree bintree; 26 | 27 | MyBinTreeNode item1(1); 28 | MyBinTreeNode item2(2); 29 | MyBinTreeNode item3(3); 30 | MyBinTreeNode item4(4); 31 | MyBinTreeNode item5(5); 32 | MyBinTreeNode item6(6); 33 | MyBinTreeNode item7(7); 34 | MyBinTreeNode item8(8); 35 | MyBinTreeNode item9(9); 36 | 37 | bintree.insert(item6); 38 | bintree.insert(item3); 39 | bintree.insert(item7); 40 | bintree.insert(item2); 41 | bintree.insert(item8); 42 | bintree.insert(item1); 43 | bintree.insert(item4); 44 | bintree.insert(item9); 45 | bintree.insert(item5); 46 | 47 | std::cout << "bintree:" << std::endl; 48 | for (const auto& item : bintree) 49 | std::cout << item.value << std::endl; 50 | 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /examples/containers_flatmap.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file containers_flatmap.cpp 3 | \brief Flat map container example 4 | \author Ivan Shynkarenka 5 | \date 27.07.2017 6 | \copyright MIT License 7 | */ 8 | 9 | #include "containers/flatmap.h" 10 | 11 | #include 12 | #include 13 | 14 | int main(int argc, char** argv) 15 | { 16 | CppCommon::FlatMap flatmap; 17 | 18 | flatmap["item6"] = 6; 19 | flatmap["item3"] = 3; 20 | flatmap["item7"] = 7; 21 | flatmap["item2"] = 2; 22 | flatmap["item8"] = 8; 23 | flatmap["item1"] = 1; 24 | flatmap["item4"] = 4; 25 | flatmap["item9"] = 9; 26 | flatmap["item5"] = 5; 27 | 28 | std::cout << "flatmap:" << std::endl; 29 | for (const auto& item : flatmap) 30 | std::cout << item.first << " => " << item.second << std::endl; 31 | 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /examples/containers_hashmap.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file containers_hashmap.cpp 3 | \brief Hash map container example 4 | \author Ivan Shynkarenka 5 | \date 13.07.2017 6 | \copyright MIT License 7 | */ 8 | 9 | #include "containers/hashmap.h" 10 | 11 | #include 12 | #include 13 | 14 | int main(int argc, char** argv) 15 | { 16 | CppCommon::HashMap hashmap; 17 | 18 | hashmap["item6"] = 6; 19 | hashmap["item3"] = 3; 20 | hashmap["item7"] = 7; 21 | hashmap["item2"] = 2; 22 | hashmap["item8"] = 8; 23 | hashmap["item1"] = 1; 24 | hashmap["item4"] = 4; 25 | hashmap["item9"] = 9; 26 | hashmap["item5"] = 5; 27 | 28 | std::cout << "hashmap:" << std::endl; 29 | for (const auto& item : hashmap) 30 | std::cout << item.first << " => " << item.second << std::endl; 31 | 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /examples/containers_list.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file containers_list.cpp 3 | \brief Intrusive list container example 4 | \author Ivan Shynkarenka 5 | \date 20.06.2017 6 | \copyright MIT License 7 | */ 8 | 9 | #include "containers/list.h" 10 | 11 | #include 12 | 13 | struct MyListNode : public CppCommon::List::Node 14 | { 15 | int value; 16 | MyListNode(int v) : value(v) {} 17 | }; 18 | 19 | int main(int argc, char** argv) 20 | { 21 | CppCommon::List list; 22 | 23 | MyListNode item1(123); 24 | MyListNode item2(456); 25 | MyListNode item3(789); 26 | 27 | list.push_front(item1); 28 | list.push_back(item2); 29 | list.push_next(item2, item3); 30 | 31 | while (list) 32 | std::cout << "list.pop_front() = " << list.pop_front()->value << std::endl; 33 | 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /examples/containers_queue.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file containers_queue.cpp 3 | \brief Intrusive queue container example 4 | \author Ivan Shynkarenka 5 | \date 20.06.2017 6 | \copyright MIT License 7 | */ 8 | 9 | #include "containers/queue.h" 10 | 11 | #include 12 | 13 | struct MyQueueNode : public CppCommon::Queue::Node 14 | { 15 | int value; 16 | 17 | explicit MyQueueNode(int v) : value(v) {} 18 | }; 19 | 20 | int main(int argc, char** argv) 21 | { 22 | CppCommon::Queue queue; 23 | 24 | MyQueueNode item1(123); 25 | MyQueueNode item2(456); 26 | MyQueueNode item3(789); 27 | 28 | queue.push(item1); 29 | queue.push(item2); 30 | queue.push(item3); 31 | 32 | while (queue) 33 | std::cout << "queue.pop() = " << queue.pop()->value << std::endl; 34 | 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /examples/containers_stack.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file containers_stack.cpp 3 | \brief Intrusive stack container example 4 | \author Ivan Shynkarenka 5 | \date 20.06.2017 6 | \copyright MIT License 7 | */ 8 | 9 | #include "containers/stack.h" 10 | 11 | #include 12 | 13 | struct MyStackNode : public CppCommon::Stack::Node 14 | { 15 | int value; 16 | 17 | explicit MyStackNode(int v) : value(v) {} 18 | }; 19 | 20 | int main(int argc, char** argv) 21 | { 22 | CppCommon::Stack stack; 23 | 24 | MyStackNode item1(123); 25 | MyStackNode item2(456); 26 | MyStackNode item3(789); 27 | 28 | stack.push(item1); 29 | stack.push(item2); 30 | stack.push(item3); 31 | 32 | while (stack) 33 | std::cout << "stack.pop() = " << stack.pop()->value << std::endl; 34 | 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /examples/errors_fatal.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file errors_fatal.cpp 3 | \brief Fatal abort execution example 4 | \author Ivan Shynkarenka 5 | \date 04.04.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "errors/fatal.h" 10 | 11 | int main(int argc, char** argv) 12 | { 13 | fatality("My fatal error!"); 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /examples/errors_system_error.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file errors_system_error.cpp 3 | \brief System error example 4 | \author Ivan Shynkarenka 5 | \date 10.02.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "errors/system_error.h" 10 | 11 | #include 12 | 13 | int main(int argc, char** argv) 14 | { 15 | std::cout << "Last system error: " << CppCommon::SystemError::GetLast() << std::endl; 16 | std::cout << "Last system description: " << CppCommon::SystemError::Description() << std::endl; 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /examples/filesystem_directory.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file filesystem_directory.cpp 3 | \brief Filesystem directory example 4 | \author Ivan Shynkarenka 5 | \date 05.09.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "filesystem/directory.h" 10 | 11 | #include 12 | 13 | int main(int argc, char** argv) 14 | { 15 | // Get the current directory 16 | CppCommon::Directory current("."); 17 | 18 | // Iterate through all directory entries 19 | for (const auto& entry : current) 20 | std::cout << entry.filename() << std::endl; 21 | 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /examples/filesystem_file.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file filesystem_file.cpp 3 | \brief Filesystem file example 4 | \author Ivan Shynkarenka 5 | \date 04.09.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "filesystem/file.h" 10 | #include "utility/countof.h" 11 | 12 | #include 13 | 14 | int main(int argc, char** argv) 15 | { 16 | char buffer[] = "The quick brown fox jumps over the lazy dog"; 17 | 18 | // Create file for writing 19 | CppCommon::File file("example.txt"); 20 | file.Create(false, true); 21 | 22 | // Write buffer into the file 23 | file.Write(buffer, CppCommon::countof(buffer) - 1); 24 | 25 | // Flush the file 26 | file.Flush(); 27 | 28 | // Close the file 29 | file.Close(); 30 | 31 | std::cout << "File size: " << file.size() << std::endl; 32 | 33 | // Read all text from the file 34 | std::string text = CppCommon::File::ReadAllText(file); 35 | 36 | std::cout << "File content: " << text << std::endl; 37 | 38 | // Remove file 39 | CppCommon::File::Remove(file); 40 | 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /examples/filesystem_path.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file filesystem_path.cpp 3 | \brief Filesystem path example 4 | \author Ivan Shynkarenka 5 | \date 17.08.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "filesystem/path.h" 10 | 11 | #include 12 | 13 | int main(int argc, char** argv) 14 | { 15 | std::cout << "Path deprecated: " << CppCommon::Path::deprecated() << std::endl; 16 | std::cout << "Path separator: " << CppCommon::Path::separator() << std::endl; 17 | std::cout << "Initial path: " << CppCommon::Path::initial() << std::endl; 18 | std::cout << "Current path: " << CppCommon::Path::current() << std::endl; 19 | std::cout << "Executable path: " << CppCommon::Path::executable() << std::endl; 20 | std::cout << "Home path: " << CppCommon::Path::home() << std::endl; 21 | std::cout << "Temporary path: " << CppCommon::Path::temp() << std::endl; 22 | std::cout << "Unique filename: " << CppCommon::Path::unique() << std::endl; 23 | 24 | std::cout << std::endl; 25 | 26 | std::cout << "Filesystem capacity: " << CppCommon::Path::current().space().capacity << std::endl; 27 | std::cout << "Filesystem free: " << CppCommon::Path::current().space().free << std::endl; 28 | std::cout << "Filesystem available: " << CppCommon::Path::current().space().available << std::endl; 29 | 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /examples/filesystem_symlink.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file filesystem_symlink.cpp 3 | \brief Filesystem symlink example 4 | \author Ivan Shynkarenka 5 | \date 04.09.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "filesystem/symlink.h" 10 | 11 | #include 12 | 13 | int main(int argc, char** argv) 14 | { 15 | CppCommon::Symlink symlink("example.lnk"); 16 | 17 | // Create a new symbolic link from the executable path 18 | CppCommon::Symlink::CreateSymlink(CppCommon::Path::executable(), symlink); 19 | 20 | // Read symbolic link target 21 | std::cout << "Symbolic link target: " << symlink.target() << std::endl; 22 | 23 | // Remove symbolic link 24 | CppCommon::Symlink::Remove(symlink); 25 | 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /examples/filesystem_touch.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file filesystem_touch.cpp 3 | \brief Filesystem touch example 4 | \author Ivan Shynkarenka 5 | \date 21.03.2019 6 | \copyright MIT License 7 | */ 8 | 9 | #include "filesystem/path.h" 10 | #include "time/timestamp.h" 11 | 12 | #include 13 | 14 | int main(int argc, char** argv) 15 | { 16 | if (argc < 2) 17 | { 18 | std::cout << "Touch path is required!" << std::endl; 19 | return -1; 20 | } 21 | 22 | CppCommon::Path::Touch(argv[1]); 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /examples/math_math.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file math_math.cpp 3 | \brief Math example 4 | \author Ivan Shynkarenka 5 | \date 01.09.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "math/math.h" 10 | 11 | #include 12 | 13 | int main(int argc, char** argv) 14 | { 15 | uint64_t a = 4984198405165151231; 16 | uint64_t b = 6132198419878046132; 17 | uint64_t c = 9156498145135109843; 18 | std::cout << "Math::MulDiv64(" << a << " * " << b << " / " << c << ") = " << CppCommon::Math::MulDiv64(a, b, c) << std::endl; 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /examples/memory_arena.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file memory_arena.cpp 3 | \brief Arena memory allocator example 4 | \author Ivan Shynkarenka 5 | \date 15.05.2017 6 | \copyright MIT License 7 | */ 8 | 9 | #include "memory/allocator_arena.h" 10 | 11 | #include 12 | 13 | int main(int argc, char** argv) 14 | { 15 | CppCommon::DefaultMemoryManager auxiliary; 16 | CppCommon::ArenaMemoryManager manger(auxiliary); 17 | CppCommon::ArenaAllocator alloc(manger); 18 | 19 | int* v = alloc.Create(123); 20 | std::cout << "v = " << *v << std::endl; 21 | alloc.Release(v); 22 | 23 | int* a = alloc.CreateArray(3, 123); 24 | std::cout << "a[0] = " << a[0] << std::endl; 25 | std::cout << "a[1] = " << a[1] << std::endl; 26 | std::cout << "a[2] = " << a[2] << std::endl; 27 | alloc.ReleaseArray(a); 28 | 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /examples/memory_leaks.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file memory_leaks.cpp 3 | \brief Memory leaks detection example 4 | \author Ivan Shynkarenka 5 | \date 26.02.2018 6 | \copyright MIT License 7 | */ 8 | 9 | #include "memory/memory_leaks.h" 10 | 11 | #include 12 | 13 | int main(int argc, char** argv) 14 | { 15 | [[maybe_unused]] int* ptr = nullptr; 16 | 17 | // Make some memory leaks 18 | ptr = new int; 19 | ptr = new int[100]; 20 | 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /examples/memory_memory.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file memory_memory.cpp 3 | \brief Memory management example 4 | \author Ivan Shynkarenka 5 | \date 27.07.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "memory/memory.h" 10 | 11 | #include 12 | 13 | int main(int argc, char** argv) 14 | { 15 | std::cout << "Total RAM: " << CppCommon::Memory::RamTotal() << " bytes" << std::endl; 16 | std::cout << "Free RAM: " << CppCommon::Memory::RamFree() << " bytes" << std::endl; 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /examples/memory_pool.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file memory_pool.cpp 3 | \brief Pool memory allocator example 4 | \author Ivan Shynkarenka 5 | \date 15.05.2017 6 | \copyright MIT License 7 | */ 8 | 9 | #include "memory/allocator_pool.h" 10 | 11 | #include 12 | 13 | int main(int argc, char** argv) 14 | { 15 | CppCommon::DefaultMemoryManager auxiliary; 16 | CppCommon::PoolMemoryManager manger(auxiliary); 17 | CppCommon::PoolAllocator alloc(manger); 18 | 19 | int* v = alloc.Create(123); 20 | std::cout << "v = " << *v << std::endl; 21 | alloc.Release(v); 22 | 23 | int* a = alloc.CreateArray(3, 123); 24 | std::cout << "a[0] = " << a[0] << std::endl; 25 | std::cout << "a[1] = " << a[1] << std::endl; 26 | std::cout << "a[2] = " << a[2] << std::endl; 27 | alloc.ReleaseArray(a); 28 | 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /examples/string_encoding.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file string_encoding.cpp 3 | \brief Encoding utilities example 4 | \author Ivan Shynkarenka 5 | \date 13.08.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "string/encoding.h" 10 | 11 | #include 12 | 13 | #if defined(unix) || defined(__unix) || defined(__unix__) 14 | #include 15 | #elif defined(_WIN32) || defined(_WIN64) 16 | #include 17 | #include 18 | #include 19 | #define CP_UTF16 65002 20 | #endif 21 | 22 | int main(int argc, char** argv) 23 | { 24 | // Allow the console to output Unicode strings using std::wcout 25 | #if defined(unix) || defined(__unix) || defined(__unix__) 26 | setlocale(LC_ALL, ""); 27 | #elif defined(_WIN32) || defined(_WIN64) 28 | _setmode(_fileno(stdin), _O_U16TEXT); 29 | _setmode(_fileno(stdout), _O_U16TEXT); 30 | _setmode(_fileno(stderr), _O_U16TEXT); 31 | SetConsoleCP(CP_UTF16); 32 | SetConsoleOutputCP(CP_UTF16); 33 | #endif 34 | 35 | std::string utf8 = "\xD0\x9F\xD1\x80\xD0\xB8\xD0\xB2\xD0\xB5\xD1\x82\x20\xD0\xBC\xD0\xB8\xD1\x80\x21"; 36 | std::wstring sys = CppCommon::Encoding::FromUTF8(utf8); 37 | std::wcout << sys << std::endl; 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /examples/system_console.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file system_console.cpp 3 | \brief Console management example 4 | \author Ivan Shynkarenka 5 | \date 27.07.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "system/console.h" 10 | 11 | #include 12 | #include 13 | 14 | int main(int argc, char** argv) 15 | { 16 | for (int i = (int)CppCommon::Color::BLACK; i <= (int)CppCommon::Color::WHITE; ++i) 17 | { 18 | for (int j = (int)CppCommon::Color::BLACK; j <= (int)CppCommon::Color::WHITE; ++j) 19 | { 20 | std::cout << std::make_pair((CppCommon::Color)i, (CppCommon::Color)j); 21 | std::cout << " "; 22 | std::cout << std::setfill('0') << std::setw(2) << i; 23 | std::cout << " / "; 24 | std::cout << std::setfill('0') << std::setw(2) << j; 25 | std::cout << " "; 26 | CppCommon::Console::SetColor(CppCommon::Color::WHITE, CppCommon::Color::BLACK); 27 | } 28 | std::cout << std::endl; 29 | } 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /examples/system_cpu.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file system_cpu.cpp 3 | \brief CPU management example 4 | \author Ivan Shynkarenka 5 | \date 27.07.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "system/cpu.h" 10 | 11 | #include 12 | 13 | int main(int argc, char** argv) 14 | { 15 | std::cout << "CPU architecture: " << CppCommon::CPU::Architecture() << std::endl; 16 | std::cout << "CPU affinity: " << CppCommon::CPU::Affinity() << std::endl; 17 | std::cout << "CPU logical cores: " << CppCommon::CPU::LogicalCores() << std::endl; 18 | std::cout << "CPU physical cores: " << CppCommon::CPU::PhysicalCores() << std::endl; 19 | std::cout << "CPU clock speed: " << CppCommon::CPU::ClockSpeed() << " Hz" << std::endl; 20 | std::cout << "CPU Hyper-Threading: " << (CppCommon::CPU::HyperThreading() ? "enabled" : "disabled") << std::endl; 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /examples/system_environment.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file system_environment.cpp 3 | \brief Environment management example 4 | \author Ivan Shynkarenka 5 | \date 27.07.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "system/environment.h" 10 | 11 | #include 12 | 13 | int main(int argc, char** argv) 14 | { 15 | std::cout << "32-bit OS: " << (CppCommon::Environment::Is32BitOS() ? "true" : "false") << std::endl; 16 | std::cout << "64-bit OS: " << (CppCommon::Environment::Is64BitOS() ? "true" : "false") << std::endl; 17 | std::cout << "32-bit process: " << (CppCommon::Environment::Is32BitProcess() ? "true" : "false") << std::endl; 18 | std::cout << "64-bit process: " << (CppCommon::Environment::Is64BitProcess() ? "true" : "false") << std::endl; 19 | std::cout << "Debug build: " << (CppCommon::Environment::IsDebug() ? "true" : "false") << std::endl; 20 | std::cout << "Release build: " << (CppCommon::Environment::IsRelease() ? "true" : "false") << std::endl; 21 | std::cout << "Big endian system: " << (CppCommon::Environment::IsBigEndian() ? "true" : "false") << std::endl; 22 | std::cout << "Little endian system: " << (CppCommon::Environment::IsLittleEndian() ? "true" : "false") << std::endl; 23 | std::cout << "OS version: " << CppCommon::Environment::OSVersion() << std::endl; 24 | 25 | std::cout << std::endl << "Environment variables: " << std::endl; 26 | for (const auto& envar : CppCommon::Environment::envars()) 27 | std::cout << envar.first << "=" << envar.second << std::endl; 28 | 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /examples/system_pipe.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file system_pipe.cpp 3 | \brief Pipe example 4 | \author Ivan Shynkarenka 5 | \date 30.11.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "system/pipe.h" 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | int main(int argc, char** argv) 16 | { 17 | std::cout << "Please enter some integer numbers. Enter '0' to exit..." << std::endl; 18 | 19 | // Create communication pipe 20 | CppCommon::Pipe pipe; 21 | 22 | // Start consumer thread 23 | auto consumer = std::thread([&pipe]() 24 | { 25 | int item; 26 | 27 | do 28 | { 29 | // Read the item form the pipe 30 | if (pipe.Read(&item, sizeof(item)) != sizeof(item)) 31 | break; 32 | 33 | // Consume the item 34 | std::cout << "Your entered number: " << item << std::endl; 35 | } while (item != 0); 36 | }); 37 | 38 | // Perform text input 39 | std::string line; 40 | while (getline(std::cin, line)) 41 | { 42 | int item = std::stoi(line); 43 | 44 | // Write the item into the pipe 45 | if (pipe.Write(&item, sizeof(item)) != sizeof(item)) 46 | break; 47 | 48 | if (item == 0) 49 | break; 50 | } 51 | 52 | // Wait for the consumer thread 53 | consumer.join(); 54 | 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /examples/system_process.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file system_process.cpp 3 | \brief Process example 4 | \author Ivan Shynkarenka 5 | \date 01.12.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "system/process.h" 10 | 11 | #include 12 | 13 | int main(int argc, char** argv) 14 | { 15 | if (argc > 1) 16 | { 17 | std::cout << "Executing child process..." << std::endl; 18 | CppCommon::Process child = CppCommon::Process::Execute(argv[1]); 19 | int result = child.Wait(); 20 | std::cout << "Executed child process! Result = " << result << std::endl; 21 | return 0; 22 | } 23 | 24 | std::cout << "Current process Id: " << CppCommon::Process::CurrentProcessId() << std::endl; 25 | std::cout << "Parent process Id: " << CppCommon::Process::ParentProcessId() << std::endl; 26 | return 123; 27 | } 28 | -------------------------------------------------------------------------------- /examples/system_process_pipes.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file system_process_pipes.cpp 3 | \brief Process pipes example 4 | \author Ivan Shynkarenka 5 | \date 07.12.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "system/environment.h" 10 | #include "system/process.h" 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | int main(int argc, char** argv) 17 | { 18 | if (argc > 1) 19 | { 20 | std::string message = "test message"; 21 | std::string endline = CppCommon::Environment::EndLine(); 22 | 23 | std::cout << "Executing child process..." << std::endl; 24 | CppCommon::Pipe input; 25 | CppCommon::Pipe output; 26 | CppCommon::Pipe error; 27 | CppCommon::Process child = CppCommon::Process::Execute(argv[1], nullptr, nullptr, nullptr, &input, &output, &error); 28 | input.Write(message); 29 | input.Write(endline); 30 | std::string out = output.ReadAllText(); 31 | std::string err = error.ReadAllText(); 32 | int result = child.Wait(); 33 | std::cout << "Executed child process! Result = " << result << std::endl; 34 | std::cout << "stdout: " << out << std::endl; 35 | std::cout << "stderr: " << err << std::endl; 36 | return 0; 37 | } 38 | 39 | std::string line; 40 | if (getline(std::cin, line)) 41 | { 42 | std::cout << line << std::endl; 43 | std::reverse(line.begin(), line.end()); 44 | std::cerr << line << std::endl; 45 | } 46 | return 123; 47 | } 48 | -------------------------------------------------------------------------------- /examples/system_shared_memory.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file system_shared_memory.cpp 3 | \brief Shared memory manager example 4 | \author Ivan Shynkarenka 5 | \date 19.04.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "system/shared_memory.h" 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | int main(int argc, char** argv) 16 | { 17 | // Create or open a shared memory buffer 18 | CppCommon::SharedMemory buffer("shared_memory_example", 1024); 19 | if (buffer.owner()) 20 | std::cout << "SharedMemory created!" << std::endl; 21 | else 22 | std::cout << "SharedMemory opened! Value = " << (char*)buffer.ptr() << std::endl; 23 | 24 | // Show help message 25 | std::cout << "Please enter anything to put into shared memory (several processes support). Enter '0' to exit..." << std::endl; 26 | 27 | // Perform text input 28 | std::string line; 29 | while (getline(std::cin, line)) 30 | { 31 | if (line == "0") 32 | break; 33 | 34 | // Show the old shared memory buffer content 35 | std::cout << "Old shared memory value = " << (char*)buffer.ptr() << std::endl; 36 | 37 | // Write text input into the shared memory buffer 38 | std::memcpy(buffer.ptr(), line.c_str(), std::min(line.size() + 1, buffer.size())); 39 | 40 | // Show the new shared memory buffer content 41 | std::cout << "New shared memory value = " << (char*)buffer.ptr() << std::endl; 42 | } 43 | 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /examples/system_shared_type.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file system_shared_type.cpp 3 | \brief Shared memory type example 4 | \author Ivan Shynkarenka 5 | \date 23.05.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "system/shared_type.h" 10 | 11 | #include 12 | #include 13 | 14 | int main(int argc, char** argv) 15 | { 16 | // Create or open a shared memory type 17 | CppCommon::SharedType shared("shared_type_example"); 18 | if (shared.owner()) 19 | std::cout << "SharedType created!" << std::endl; 20 | else 21 | std::cout << "SharedType opened! Value = " << *shared << std::endl; 22 | 23 | // Show help message 24 | std::cout << "Please enter any integer number to put into shared memory type (several processes support). Enter '0' to exit..." << std::endl; 25 | 26 | // Perform text input 27 | std::string line; 28 | while (getline(std::cin, line)) 29 | { 30 | int item = std::stoi(line); 31 | 32 | // Check for exit 33 | if (item == 0) 34 | break; 35 | 36 | // Show the old shared memory type content 37 | std::cout << "Old shared memory type value = " << *shared << std::endl; 38 | 39 | // Write new integer value into the shared memory type 40 | *shared = item; 41 | 42 | // Show the new shared memory type content 43 | std::cout << "New shared memory type value = " << *shared << std::endl; 44 | } 45 | 46 | return 0; 47 | } 48 | -------------------------------------------------------------------------------- /examples/system_source_location.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file system_source_location.cpp 3 | \brief Source location example 4 | \author Ivan Shynkarenka 5 | \date 09.02.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "system/source_location.h" 10 | 11 | #include 12 | 13 | int main(int argc, char** argv) 14 | { 15 | std::cout << "Source location: " << __LOCATION__ << std::endl; 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /examples/system_stack_trace.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file system_stack_trace.cpp 3 | \brief Stack trace snapshot provider example 4 | \author Ivan Shynkarenka 5 | \date 11.02.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "system/stack_trace.h" 10 | #include "system/stack_trace_manager.h" 11 | #include "threads/thread.h" 12 | 13 | #include 14 | #include 15 | 16 | void function1() 17 | { 18 | std::cout << "Thread Id: " << __THREAD__ << std::endl; 19 | std::cout << "Stack trace: " << std::endl << __STACK__ << std::endl; 20 | } 21 | 22 | void function2() 23 | { 24 | function1(); 25 | } 26 | 27 | void function3() 28 | { 29 | function2(); 30 | } 31 | 32 | int main(int argc, char** argv) 33 | { 34 | // Initialize stack trace manager of the current process 35 | CppCommon::StackTraceManager::Initialize(); 36 | 37 | // Show the stack trace from the main thread 38 | function3(); 39 | 40 | // Show the stack trace from the child thread 41 | std::thread(function3).join(); 42 | 43 | // Cleanup stack trace manager of the current process 44 | CppCommon::StackTraceManager::Cleanup(); 45 | 46 | return 0; 47 | } 48 | -------------------------------------------------------------------------------- /examples/system_uuid.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file system_uuid.cpp 3 | \brief Universally unique identifier (UUID) example 4 | \author Ivan Shynkarenka 5 | \date 19.08.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "system/uuid.h" 10 | 11 | #include 12 | 13 | int main(int argc, char** argv) 14 | { 15 | std::cout << "UUID::Nil(): " << CppCommon::UUID::Nil() << std::endl; 16 | std::cout << "UUID::Sequential(): " << CppCommon::UUID::Sequential() << std::endl; 17 | std::cout << "UUID::Random(): " << CppCommon::UUID::Random() << std::endl; 18 | std::cout << "UUID::Secure(): " << CppCommon::UUID::Secure() << std::endl; 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /examples/threads_barrier.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file threads_barrier.cpp 3 | \brief Barrier synchronization primitive example 4 | \author Ivan Shynkarenka 5 | \date 17.03.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "threads/barrier.h" 10 | #include "threads/thread.h" 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | int main(int argc, char** argv) 17 | { 18 | int concurrency = 8; 19 | 20 | CppCommon::Barrier barrier(concurrency); 21 | 22 | // Start some threads 23 | std::vector threads; 24 | for (int thread = 0; thread < concurrency; ++thread) 25 | { 26 | threads.emplace_back([&barrier, thread]() 27 | { 28 | std::cout << "Thread " << thread << " initialized!" << std::endl; 29 | 30 | // Sleep for a while... 31 | CppCommon::Thread::SleepFor(CppCommon::Timespan::milliseconds(thread * 10)); 32 | 33 | std::cout << "Thread " << thread << " before barrier!" << std::endl; 34 | 35 | // Wait for all other threads at the barrier 36 | bool last = barrier.Wait(); 37 | 38 | std::cout << "Thread " << thread << " after barrier!" << (last ? " Last one!" : "") << std::endl; 39 | }); 40 | } 41 | 42 | // Wait for all threads 43 | for (auto& thread : threads) 44 | thread.join(); 45 | 46 | return 0; 47 | } 48 | -------------------------------------------------------------------------------- /examples/threads_critical_section.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file threads_critical_section.cpp 3 | \brief Critical section synchronization primitive example 4 | \author Ivan Shynkarenka 5 | \date 28.01.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "threads/critical_section.h" 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | int main(int argc, char** argv) 17 | { 18 | std::cout << "Press Enter to stop..." << std::endl; 19 | 20 | CppCommon::CriticalSection lock; 21 | 22 | // Start some threads 23 | std::atomic stop(false); 24 | std::vector threads; 25 | for (int thread = 0; thread < 4; ++thread) 26 | { 27 | threads.emplace_back([&lock, &stop, thread]() 28 | { 29 | while (!stop) 30 | { 31 | // Use locker with critical section to protect the output 32 | CppCommon::Locker locker(lock); 33 | 34 | std::cout << "Random value from thread " << thread << ": " << rand() << std::endl; 35 | } 36 | }); 37 | } 38 | 39 | // Wait for input 40 | std::cin.get(); 41 | 42 | // Stop threads 43 | stop = true; 44 | 45 | // Wait for all threads 46 | for (auto& thread : threads) 47 | thread.join(); 48 | 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /examples/threads_event_auto_reset.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file threads_event_auto_reset.cpp 3 | \brief Auto-reset event synchronization primitive example 4 | \author Ivan Shynkarenka 5 | \date 14.04.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "threads/event_auto_reset.h" 10 | #include "threads/thread.h" 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | int main(int argc, char** argv) 17 | { 18 | int concurrency = 8; 19 | 20 | CppCommon::EventAutoReset event; 21 | 22 | // Start some threads 23 | std::vector threads; 24 | for (int thread = 0; thread < concurrency; ++thread) 25 | { 26 | threads.emplace_back([&event, thread]() 27 | { 28 | std::cout << "Thread " << thread << " initialized!" << std::endl; 29 | 30 | // Sleep for a while... 31 | CppCommon::Thread::SleepFor(CppCommon::Timespan::milliseconds(thread * 10)); 32 | 33 | std::cout << "Thread " << thread << " waiting for the event!" << std::endl; 34 | 35 | // Wait for the event 36 | event.Wait(); 37 | 38 | std::cout << "Thread " << thread << " signaled!" << std::endl; 39 | }); 40 | } 41 | 42 | // Allow threads to start 43 | CppCommon::Thread::SleepFor(CppCommon::Timespan::milliseconds(100)); 44 | 45 | // Signal the event for each thread that waits 46 | for (int thread = 0; thread < concurrency; ++thread) 47 | { 48 | std::cout << "Signal event!" << std::endl; 49 | event.Signal(); 50 | } 51 | 52 | // Wait for all threads 53 | for (auto& thread : threads) 54 | thread.join(); 55 | 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /examples/threads_event_manual_reset.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file threads_event_manual_reset.cpp 3 | \brief Manual-reset event synchronization primitive example 4 | \author Ivan Shynkarenka 5 | \date 14.04.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "threads/event_manual_reset.h" 10 | #include "threads/thread.h" 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | int main(int argc, char** argv) 17 | { 18 | int concurrency = 8; 19 | 20 | CppCommon::EventManualReset event; 21 | 22 | // Start some threads 23 | std::vector threads; 24 | for (int thread = 0; thread < concurrency; ++thread) 25 | { 26 | threads.emplace_back([&event, thread]() 27 | { 28 | std::cout << "Thread " << thread << " initialized!" << std::endl; 29 | 30 | // Sleep for a while... 31 | CppCommon::Thread::SleepFor(CppCommon::Timespan::milliseconds(thread * 10)); 32 | 33 | std::cout << "Thread " << thread << " waiting for the event!" << std::endl; 34 | 35 | // Wait for the event 36 | event.Wait(); 37 | 38 | std::cout << "Thread " << thread << " signaled!" << std::endl; 39 | }); 40 | } 41 | 42 | // Allow threads to start 43 | CppCommon::Thread::SleepFor(CppCommon::Timespan::milliseconds(100)); 44 | 45 | // Signal the event 46 | std::cout << "Signal event!" << std::endl; 47 | event.Signal(); 48 | 49 | // Wait for all threads 50 | for (auto& thread : threads) 51 | thread.join(); 52 | 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /examples/threads_latch_multi.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file threads_latch_multi.cpp 3 | \brief Latch synchronization primitive example for multiple threads waiting 4 | \author Ivan Shynkarenka 5 | \date 25.03.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "threads/latch.h" 10 | #include "threads/thread.h" 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | int main(int argc, char** argv) 17 | { 18 | int concurrency = 8; 19 | 20 | CppCommon::Latch latch(concurrency); 21 | 22 | // Start some threads 23 | std::vector threads; 24 | for (int thread = 0; thread < concurrency; ++thread) 25 | { 26 | threads.emplace_back([&latch, thread]() 27 | { 28 | std::cout << "Thread " << thread << " initialized!" << std::endl; 29 | 30 | // Sleep for a while... 31 | CppCommon::Thread::SleepFor(CppCommon::Timespan::milliseconds(thread * 10)); 32 | 33 | // Count down the latch 34 | latch.CountDown(); 35 | 36 | std::cout << "Thread " << thread << " latch count down!" << std::endl; 37 | }); 38 | } 39 | 40 | std::cout << "Main thread is waiting for the latch..." << std::endl; 41 | 42 | // Wait until work is done 43 | latch.Wait(); 44 | 45 | std::cout << "Main thread continue!" << std::endl; 46 | 47 | // Wait for all threads 48 | for (auto& thread : threads) 49 | thread.join(); 50 | 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /examples/threads_latch_single.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file threads_latch_single.cpp 3 | \brief Latch synchronization primitive example for single threads waiting 4 | \author Ivan Shynkarenka 5 | \date 25.03.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "threads/latch.h" 10 | #include "threads/thread.h" 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | int main(int argc, char** argv) 17 | { 18 | int concurrency = 8; 19 | 20 | CppCommon::Latch latch(1); 21 | 22 | // Start some threads 23 | std::vector threads; 24 | for (int thread = 0; thread < concurrency; ++thread) 25 | { 26 | threads.emplace_back([&latch, thread]() 27 | { 28 | std::cout << "Thread " << thread << " waiting for the latch..." << std::endl; 29 | 30 | // Wait for the latch 31 | latch.Wait(); 32 | 33 | std::cout << "Thread " << thread << " continue!" << std::endl; 34 | 35 | // Sleep for a while... 36 | CppCommon::Thread::SleepFor(CppCommon::Timespan::milliseconds(thread * 10)); 37 | }); 38 | } 39 | 40 | // Perform some initialization 41 | CppCommon::Thread::SleepFor(CppCommon::Timespan::milliseconds(100)); 42 | 43 | std::cout << "Main thread initialized!" << std::endl; 44 | 45 | // Threads can now start processing 46 | latch.CountDown(); 47 | 48 | // Wait for all threads 49 | for (auto& thread : threads) 50 | thread.join(); 51 | 52 | return 0; 53 | } 54 | -------------------------------------------------------------------------------- /examples/threads_mpmc_ring_queue.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file threads_mpmc_bounded_queue.cpp 3 | \brief Multiple producers / multiple consumers wait-free ring queue example 4 | \author Ivan Shynkarenka 5 | \date 19.01.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "threads/mpmc_ring_queue.h" 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | int main(int argc, char** argv) 16 | { 17 | std::cout << "Please enter some integer numbers. Enter '0' to exit..." << std::endl; 18 | 19 | // Create multiple producers / multiple consumers wait-free ring queue 20 | CppCommon::MPMCRingQueue queue(1024); 21 | 22 | // Start consumer thread 23 | auto consumer = std::thread([&queue]() 24 | { 25 | int item; 26 | 27 | do 28 | { 29 | // Dequeue using yield waiting strategy 30 | while (!queue.Dequeue(item)) 31 | std::this_thread::yield(); 32 | 33 | // Consume the item 34 | std::cout << "Your entered number: " << item << std::endl; 35 | } while (item != 0); 36 | }); 37 | 38 | // Perform text input 39 | std::string line; 40 | while (getline(std::cin, line)) 41 | { 42 | int item = std::stoi(line); 43 | 44 | // Enqueue using yield waiting strategy 45 | while (!queue.Enqueue(item)) 46 | std::this_thread::yield(); 47 | 48 | if (item == 0) 49 | break; 50 | } 51 | 52 | // Wait for the consumer thread 53 | consumer.join(); 54 | 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /examples/threads_mpsc_linked_queue.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file threads_mpsc_linked_queue.cpp 3 | \brief Multiple producers / single consumer wait-free linked queue example 4 | \author Ivan Shynkarenka 5 | \date 19.01.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "threads/mpsc_linked_queue.h" 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | int main(int argc, char** argv) 16 | { 17 | std::cout << "Please enter some integer numbers. Enter '0' to exit..." << std::endl; 18 | 19 | // Create multiple producers / single consumer wait-free linked queue 20 | CppCommon::MPSCLinkedQueue queue; 21 | 22 | // Start consumer thread 23 | auto consumer = std::thread([&queue]() 24 | { 25 | int item; 26 | 27 | do 28 | { 29 | // Dequeue using yield waiting strategy 30 | while (!queue.Dequeue(item)) 31 | std::this_thread::yield(); 32 | 33 | // Consume the item 34 | std::cout << "Your entered number: " << item << std::endl; 35 | } while (item != 0); 36 | }); 37 | 38 | // Perform text input 39 | std::string line; 40 | while (getline(std::cin, line)) 41 | { 42 | int item = std::stoi(line); 43 | 44 | // Enqueue using yield waiting strategy 45 | while (!queue.Enqueue(item)) 46 | std::this_thread::yield(); 47 | 48 | if (item == 0) 49 | break; 50 | } 51 | 52 | // Wait for the consumer thread 53 | consumer.join(); 54 | 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /examples/threads_mpsc_ring_buffer.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file threads_mpsc_ring_buffer.cpp 3 | \brief Multiple producers / single consumer wait-free ring buffer example 4 | \author Ivan Shynkarenka 5 | \date 26 .01.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "threads/mpsc_ring_buffer.h" 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | int main(int argc, char** argv) 16 | { 17 | std::cout << "Please enter some text. Enter '#' to exit..." << std::endl; 18 | 19 | // Create multiple producers / single consumer wait-free ring buffer 20 | CppCommon::MPSCRingBuffer buffer(1024); 21 | 22 | // Start consumer thread 23 | auto consumer = std::thread([&buffer]() 24 | { 25 | // Use local buffer for batch processing 26 | const size_t local_capacity = 1024; 27 | char local_buffer[local_capacity]; 28 | size_t local_size; 29 | 30 | do 31 | { 32 | // Dequeue with yield waiting strategy 33 | while (!buffer.Dequeue(local_buffer, local_size = local_capacity)) 34 | std::this_thread::yield(); 35 | 36 | // Consume items 37 | std::cout << "Your entered: "; 38 | std::cout.write(local_buffer, local_size); 39 | std::cout << std::endl; 40 | } while (memchr(local_buffer, '#', local_size) == nullptr); 41 | }); 42 | 43 | // Perform text input 44 | std::string line; 45 | while (getline(std::cin, line)) 46 | { 47 | // Enqueue using yield waiting strategy 48 | while (!buffer.Enqueue(line.c_str(), line.size())) 49 | std::this_thread::yield(); 50 | 51 | if (line.find('#') != std::string::npos) 52 | break; 53 | } 54 | 55 | // Wait for the consumer thread 56 | consumer.join(); 57 | 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /examples/threads_mpsc_ring_queue.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file threads_mpsc_ring_queue.cpp 3 | \brief Multiple producers / single consumer wait-free ring queue example 4 | \author Ivan Shynkarenka 5 | \date 22.01.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "threads/mpsc_ring_queue.h" 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | int main(int argc, char** argv) 16 | { 17 | std::cout << "Please enter some integer numbers. Enter '0' to exit..." << std::endl; 18 | 19 | // Create multiple producers / single consumer wait-free ring queue 20 | CppCommon::MPSCRingQueue queue(1024); 21 | 22 | // Start consumer thread 23 | auto consumer = std::thread([&queue]() 24 | { 25 | int item; 26 | 27 | do 28 | { 29 | // Dequeue using yield waiting strategy 30 | while (!queue.Dequeue(item)) 31 | std::this_thread::yield(); 32 | 33 | // Consume the item 34 | std::cout << "Your entered number: " << item << std::endl; 35 | } while (item != 0); 36 | }); 37 | 38 | // Perform text input 39 | std::string line; 40 | while (getline(std::cin, line)) 41 | { 42 | int item = std::stoi(line); 43 | 44 | // Enqueue using yield waiting strategy 45 | while (!queue.Enqueue(item)) 46 | std::this_thread::yield(); 47 | 48 | if (item == 0) 49 | break; 50 | } 51 | 52 | // Wait for the consumer thread 53 | consumer.join(); 54 | 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /examples/threads_mutex.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file threads_mutex.cpp 3 | \brief Mutex synchronization primitive example 4 | \author Ivan Shynkarenka 5 | \date 04.04.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "threads/mutex.h" 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | int main(int argc, char** argv) 17 | { 18 | std::cout << "Press Enter to stop..." << std::endl; 19 | 20 | CppCommon::Mutex lock; 21 | 22 | // Start some threads 23 | std::atomic stop(false); 24 | std::vector threads; 25 | for (int thread = 0; thread < 4; ++thread) 26 | { 27 | threads.emplace_back([&lock, &stop, thread]() 28 | { 29 | while (!stop) 30 | { 31 | // Use locker with mutex to protect the output 32 | CppCommon::Locker locker(lock); 33 | 34 | std::cout << "Random value from thread " << thread << ": " << rand() << std::endl; 35 | } 36 | }); 37 | } 38 | 39 | // Wait for input 40 | std::cin.get(); 41 | 42 | // Stop threads 43 | stop = true; 44 | 45 | // Wait for all threads 46 | for (auto& thread : threads) 47 | thread.join(); 48 | 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /examples/threads_named_critical_section.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file threads_critical_section.cpp 3 | \brief Named critical section synchronization primitive example 4 | \author Ivan Shynkarenka 5 | \date 26.05.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "threads/named_critical_section.h" 10 | 11 | #include 12 | #include 13 | 14 | int main(int argc, char** argv) 15 | { 16 | std::string help = "Please enter '+' to lock and '-' to unlock the named critical section (several processes support). Enter '0' to exit..."; 17 | 18 | // Show help message 19 | std::cout << help << std::endl; 20 | 21 | // Create named critical section 22 | CppCommon::NamedCriticalSection lock("named_cs_example"); 23 | 24 | // Perform text input 25 | std::string line; 26 | while (getline(std::cin, line)) 27 | { 28 | if (line == "+") 29 | { 30 | if (lock.TryLock()) 31 | std::cout << "Critical section successfully locked!" << std::endl; 32 | else 33 | std::cout << "Failed to lock critical section!" << std::endl; 34 | } 35 | else if (line == "-") 36 | { 37 | try 38 | { 39 | lock.Unlock(); 40 | std::cout << "Critical section successfully unlocked!" << std::endl; 41 | } 42 | catch (const CppCommon::SystemException&) 43 | { 44 | std::cout << "Failed to unlock critical section!" << std::endl; 45 | } 46 | } 47 | else if (line == "0") 48 | break; 49 | else 50 | std::cout << help << std::endl; 51 | } 52 | 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /examples/threads_named_mutex.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file threads_named_mutex.cpp 3 | \brief Named mutex synchronization primitive example 4 | \author Ivan Shynkarenka 5 | \date 15.04.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "threads/named_mutex.h" 10 | 11 | #include 12 | #include 13 | 14 | int main(int argc, char** argv) 15 | { 16 | std::string help = "Please enter '+' to lock and '-' to unlock the named mutex (several processes support). Enter '0' to exit..."; 17 | 18 | // Show help message 19 | std::cout << help << std::endl; 20 | 21 | // Create named mutex 22 | CppCommon::NamedMutex mutex("named_mutex_example"); 23 | 24 | // Perform text input 25 | std::string line; 26 | while (getline(std::cin, line)) 27 | { 28 | if (line == "+") 29 | { 30 | if (mutex.TryLock()) 31 | std::cout << "Mutex successfully locked!" << std::endl; 32 | else 33 | std::cout << "Failed to lock mutex!" << std::endl; 34 | } 35 | else if (line == "-") 36 | { 37 | try 38 | { 39 | mutex.Unlock(); 40 | std::cout << "Mutex successfully unlocked!" << std::endl; 41 | } 42 | catch (const CppCommon::SystemException&) 43 | { 44 | std::cout << "Failed to unlock mutex!" << std::endl; 45 | } 46 | } 47 | else if (line == "0") 48 | break; 49 | else 50 | std::cout << help << std::endl; 51 | } 52 | 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /examples/threads_named_semaphore.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file threads_named_semaphore.cpp 3 | \brief Named semaphore synchronization primitive example 4 | \author Ivan Shynkarenka 5 | \date 15.04.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "threads/named_semaphore.h" 10 | 11 | #include 12 | #include 13 | 14 | int main(int argc, char** argv) 15 | { 16 | std::string help = "Please enter '+' to lock and '-' to unlock the named semaphore (several processes support). Enter '0' to exit..."; 17 | 18 | // Show help message 19 | std::cout << help << std::endl; 20 | 21 | // Assume we have four resources 22 | int resources = 4; 23 | 24 | // Create named semaphore for our resources 25 | CppCommon::NamedSemaphore semaphore("named_semaphore_example", resources); 26 | 27 | // Perform text input 28 | std::string line; 29 | while (getline(std::cin, line)) 30 | { 31 | if (line == "+") 32 | { 33 | if (semaphore.TryLock()) 34 | std::cout << "Semaphore successfully locked!" << std::endl; 35 | else 36 | std::cout << "Failed to lock semaphore! Semaphore resources exceeded..." << std::endl; 37 | } 38 | else if (line == "-") 39 | { 40 | try 41 | { 42 | semaphore.Unlock(); 43 | std::cout << "Semaphore successfully unlocked!" << std::endl; 44 | } 45 | catch (const CppCommon::SystemException&) 46 | { 47 | std::cout << "Failed to unlock semaphore! Semaphore is fully unlocked..." << std::endl; 48 | } 49 | } 50 | else if (line == "0") 51 | break; 52 | else 53 | std::cout << help << std::endl; 54 | } 55 | 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /examples/threads_semaphore.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file threads_semaphore.cpp 3 | \brief Semaphore synchronization primitive example 4 | \author Ivan Shynkarenka 5 | \date 12.04.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "threads/semaphore.h" 10 | 11 | #include 12 | #include 13 | 14 | int main(int argc, char** argv) 15 | { 16 | std::string help = "Please enter '+' to lock and '-' to unlock the semaphore. Enter '0' to exit..."; 17 | 18 | // Show help message 19 | std::cout << help << std::endl; 20 | 21 | // Assume we have four resources 22 | int resources = 4; 23 | 24 | // Create semaphore for our resources 25 | CppCommon::Semaphore semaphore(resources); 26 | 27 | // Perform text input 28 | std::string line; 29 | while (getline(std::cin, line)) 30 | { 31 | if (line == "+") 32 | { 33 | if (semaphore.TryLock()) 34 | std::cout << "Semaphore successfully locked!" << std::endl; 35 | else 36 | std::cout << "Failed to lock semaphore! Semaphore resources exceeded..." << std::endl; 37 | } 38 | else if (line == "-") 39 | { 40 | try 41 | { 42 | semaphore.Unlock(); 43 | std::cout << "Semaphore successfully unlocked!" << std::endl; 44 | } 45 | catch (const CppCommon::SystemException&) 46 | { 47 | std::cout << "Failed to unlock semaphore! Semaphore is fully unlocked..." << std::endl; 48 | } 49 | } 50 | else if (line == "0") 51 | break; 52 | else 53 | std::cout << help << std::endl; 54 | } 55 | 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /examples/threads_seq_lock.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file threads_seq_lock.cpp 3 | \brief Sequential lock synchronization primitive example 4 | \author Ivan Shynkarenka 5 | \date 17.08.2017 6 | \copyright MIT License 7 | */ 8 | 9 | #include "threads/seq_lock.h" 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | struct Data 17 | { 18 | int a; 19 | int b; 20 | int c; 21 | }; 22 | 23 | int main(int argc, char** argv) 24 | { 25 | CppCommon::SeqLock lock(Data{ 0, 0, 0 }); 26 | 27 | std::cout << "Press Enter to stop..." << std::endl; 28 | 29 | // Start some threads 30 | std::vector threads; 31 | for (int thread = 0; thread < 4; ++thread) 32 | { 33 | threads.emplace_back([&lock, thread]() 34 | { 35 | for (;;) 36 | { 37 | Data data = lock.Read(); 38 | if ((data.a == 100) && (data.b == 200) && (data.c == 300)) 39 | { 40 | std::cout << "Thread " << thread << " stopped!" << std::endl; 41 | return; 42 | } 43 | } 44 | }); 45 | } 46 | 47 | // Wait for input 48 | std::cin.get(); 49 | 50 | // Stop threads 51 | lock = Data{ 100, 200, 300 }; 52 | 53 | // Wait for all threads 54 | for (auto& thread : threads) 55 | thread.join(); 56 | 57 | return 0; 58 | } 59 | -------------------------------------------------------------------------------- /examples/threads_spin_barrier.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file threads_spin_barrier.cpp 3 | \brief Spin barrier synchronization primitive example 4 | \author Ivan Shynkarenka 5 | \date 17.03.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "threads/spin_barrier.h" 10 | #include "threads/thread.h" 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | int main(int argc, char** argv) 17 | { 18 | int concurrency = 8; 19 | 20 | CppCommon::SpinBarrier barrier(concurrency); 21 | 22 | // Start some threads 23 | std::vector threads; 24 | for (int thread = 0; thread < concurrency; ++thread) 25 | { 26 | threads.emplace_back([&barrier, thread]() 27 | { 28 | std::cout << "Thread " << thread << " initialized!" << std::endl; 29 | 30 | // Sleep for a while... 31 | CppCommon::Thread::SleepFor(CppCommon::Timespan::milliseconds(thread * 10)); 32 | 33 | std::cout << "Thread " << thread << " before barrier!" << std::endl; 34 | 35 | // Wait for all other threads at the barrier 36 | bool last = barrier.Wait(); 37 | 38 | std::cout << "Thread " << thread << " after barrier!" << (last ? " Last one!" : "") << std::endl; 39 | }); 40 | } 41 | 42 | // Wait for all threads 43 | for (auto& thread : threads) 44 | thread.join(); 45 | 46 | return 0; 47 | } 48 | -------------------------------------------------------------------------------- /examples/threads_spin_lock.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file threads_spin_lock.cpp 3 | \brief Spin-lock synchronization primitive example 4 | \author Ivan Shynkarenka 5 | \date 22.01.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "threads/spin_lock.h" 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | int main(int argc, char** argv) 17 | { 18 | CppCommon::SpinLock lock; 19 | 20 | std::cout << "Press Enter to stop..." << std::endl; 21 | 22 | // Start some threads 23 | std::atomic stop(false); 24 | std::vector threads; 25 | for (int thread = 0; thread < 4; ++thread) 26 | { 27 | threads.emplace_back([&lock, &stop, thread]() 28 | { 29 | while (!stop) 30 | { 31 | // Use locker with spin-lock to protect the output 32 | CppCommon::Locker locker(lock); 33 | 34 | std::cout << "Random value from thread " << thread << ": " << rand() << std::endl; 35 | } 36 | }); 37 | } 38 | 39 | // Wait for input 40 | std::cin.get(); 41 | 42 | // Stop threads 43 | stop = true; 44 | 45 | // Wait for all threads 46 | for (auto& thread : threads) 47 | thread.join(); 48 | 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /examples/threads_spsc_ring_buffer.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file threads_spsc_ring_buffer.cpp 3 | \brief Single producer / single consumer wait-free ring buffer example 4 | \author Ivan Shynkarenka 5 | \date 16.01.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "threads/spsc_ring_buffer.h" 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | int main(int argc, char** argv) 16 | { 17 | std::cout << "Please enter some text. Enter '#' to exit..." << std::endl; 18 | 19 | // Create single producer / single consumer wait-free ring buffer 20 | CppCommon::SPSCRingBuffer buffer(1024); 21 | 22 | // Start consumer thread 23 | auto consumer = std::thread([&buffer]() 24 | { 25 | // Use local buffer for batch processing 26 | const size_t local_capacity = 1024; 27 | char local_buffer[local_capacity]; 28 | size_t local_size; 29 | 30 | do 31 | { 32 | // Dequeue with yield waiting strategy 33 | while (!buffer.Dequeue(local_buffer, local_size = local_capacity)) 34 | std::this_thread::yield(); 35 | 36 | // Consume items 37 | std::cout << "Your entered: "; 38 | std::cout.write(local_buffer, local_size); 39 | std::cout << std::endl; 40 | } while (memchr(local_buffer, '#', local_size) == nullptr); 41 | }); 42 | 43 | // Perform text input 44 | std::string line; 45 | while (getline(std::cin, line)) 46 | { 47 | // Enqueue using yield waiting strategy 48 | while (!buffer.Enqueue(line.c_str(), line.size())) 49 | std::this_thread::yield(); 50 | 51 | if (line.find('#') != std::string::npos) 52 | break; 53 | } 54 | 55 | // Wait for the consumer thread 56 | consumer.join(); 57 | 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /examples/threads_spsc_ring_queue.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file threads_spsc_ring_queue.cpp 3 | \brief Single producer / single consumer wait-free ring queue example 4 | \author Ivan Shynkarenka 5 | \date 16.01.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "threads/spsc_ring_queue.h" 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | int main(int argc, char** argv) 16 | { 17 | std::cout << "Please enter some integer numbers. Enter '0' to exit..." << std::endl; 18 | 19 | // Create single producer / single consumer wait-free ring queue 20 | CppCommon::SPSCRingQueue queue(1024); 21 | 22 | // Start consumer thread 23 | auto consumer = std::thread([&queue]() 24 | { 25 | int item; 26 | 27 | do 28 | { 29 | // Dequeue using yield waiting strategy 30 | while (!queue.Dequeue(item)) 31 | std::this_thread::yield(); 32 | 33 | // Consume the item 34 | std::cout << "Your entered number: " << item << std::endl; 35 | } while (item != 0); 36 | }); 37 | 38 | // Perform text input 39 | std::string line; 40 | while (getline(std::cin, line)) 41 | { 42 | int item = std::stoi(line); 43 | 44 | // Enqueue using yield waiting strategy 45 | while (!queue.Enqueue(item)) 46 | std::this_thread::yield(); 47 | 48 | if (item == 0) 49 | break; 50 | } 51 | 52 | // Wait for the consumer thread 53 | consumer.join(); 54 | 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /examples/threads_wait_batcher.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file threads_wait_batcher.cpp 3 | \brief Multiple producers / multiple consumers wait batcher example 4 | \author Ivan Shynkarenka 5 | \date 13.03.2019 6 | \copyright MIT License 7 | */ 8 | 9 | #include "threads/wait_batcher.h" 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | int main(int argc, char** argv) 17 | { 18 | std::cout << "Please enter some string. Enter the empty string to exit..." << std::endl; 19 | 20 | // Create multiple producers / multiple consumers wait batcher 21 | CppCommon::WaitBatcher batcher; 22 | 23 | // Start consumer thread 24 | auto consumer = std::thread([&batcher]() 25 | { 26 | std::vector items; 27 | 28 | // Dequeue items until the batcher is closed 29 | while (batcher.Dequeue(items)) 30 | { 31 | std::cout << "Your entered: "; 32 | std::copy(items.begin(), items.end(), std::ostream_iterator(std::cout, "")); 33 | std::cout << std::endl; 34 | } 35 | }); 36 | 37 | // Perform text input 38 | std::string line; 39 | while (getline(std::cin, line)) 40 | { 41 | // Enqueue the item or end produce 42 | if (!batcher.Enqueue(line.begin(), line.end())) 43 | break; 44 | 45 | if (line.empty()) 46 | { 47 | // Close the wait batcher 48 | batcher.Close(); 49 | break; 50 | } 51 | } 52 | 53 | // Wait for the consumer thread 54 | consumer.join(); 55 | 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /examples/threads_wait_queue.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file threads_wait_queue.cpp 3 | \brief Multiple producers / multiple consumers wait queue example 4 | \author Ivan Shynkarenka 5 | \date 05.10.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "threads/wait_queue.h" 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | int main(int argc, char** argv) 16 | { 17 | std::cout << "Please enter some integer numbers. Enter '0' to exit..." << std::endl; 18 | 19 | // Create multiple producers / multiple consumers wait queue 20 | CppCommon::WaitQueue queue; 21 | 22 | // Start consumer thread 23 | auto consumer = std::thread([&queue]() 24 | { 25 | int item; 26 | 27 | do 28 | { 29 | // Dequeue the item or end consume 30 | if (!queue.Dequeue(item)) 31 | break; 32 | 33 | // Consume the item 34 | std::cout << "Your entered number: " << item << std::endl; 35 | } while (item != 0); 36 | }); 37 | 38 | // Perform text input 39 | std::string line; 40 | while (getline(std::cin, line)) 41 | { 42 | int item = std::stoi(line); 43 | 44 | // Enqueue the item or end produce 45 | if (!queue.Enqueue(item)) 46 | break; 47 | 48 | if (item == 0) 49 | { 50 | // Close the wait queue 51 | queue.Close(); 52 | break; 53 | } 54 | } 55 | 56 | // Wait for the consumer thread 57 | consumer.join(); 58 | 59 | return 0; 60 | } 61 | -------------------------------------------------------------------------------- /examples/threads_wait_ring.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file threads_wait_ring.cpp 3 | \brief Multiple producers / multiple consumers wait ring example 4 | \author Ivan Shynkarenka 5 | \date 05.10.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "threads/wait_ring.h" 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | int main(int argc, char** argv) 16 | { 17 | std::cout << "Please enter some integer numbers. Enter '0' to exit..." << std::endl; 18 | 19 | // Create multiple producers / multiple consumers wait ring 20 | CppCommon::WaitRing ring(1024); 21 | 22 | // Start consumer thread 23 | auto consumer = std::thread([&ring]() 24 | { 25 | int item; 26 | 27 | do 28 | { 29 | // Dequeue the item or end consume 30 | if (!ring.Dequeue(item)) 31 | break; 32 | 33 | // Consume the item 34 | std::cout << "Your entered number: " << item << std::endl; 35 | } while (item != 0); 36 | }); 37 | 38 | // Perform text input 39 | std::string line; 40 | while (getline(std::cin, line)) 41 | { 42 | int item = std::stoi(line); 43 | 44 | // Enqueue the item or end produce 45 | if (!ring.Enqueue(item)) 46 | break; 47 | 48 | if (item == 0) 49 | { 50 | // Close the wait ring 51 | ring.Close(); 52 | break; 53 | } 54 | } 55 | 56 | // Wait for the consumer thread 57 | consumer.join(); 58 | 59 | return 0; 60 | } 61 | -------------------------------------------------------------------------------- /examples/time_time.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file time_time.cpp 3 | \brief Time example 4 | \author Ivan Shynkarenka 5 | \date 13.07.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "time/time.h" 10 | 11 | #include 12 | 13 | void show(const CppCommon::Time& time) 14 | { 15 | std::cout << "Time.year() = " << time.year() << std::endl; 16 | std::cout << "Time.month() = " << time.month() << std::endl; 17 | std::cout << "Time.day() = " << time.day() << std::endl; 18 | std::cout << "Time.hour() = " << time.hour() << std::endl; 19 | std::cout << "Time.minute() = " << time.minute() << std::endl; 20 | std::cout << "Time.second() = " << time.second() << std::endl; 21 | std::cout << "Time.millisecond() = " << time.millisecond() << std::endl; 22 | std::cout << "Time.microsecond() = " << time.microsecond() << std::endl; 23 | std::cout << "Time.nanosecond() = " << time.nanosecond() << std::endl; 24 | std::cout << std::endl; 25 | } 26 | 27 | int main(int argc, char** argv) 28 | { 29 | std::cout << "UTC time:" << std::endl; 30 | show(CppCommon::UtcTime()); 31 | 32 | std::cout << "Local time:" << std::endl; 33 | show(CppCommon::LocalTime()); 34 | 35 | std::cout << "Min time:" << std::endl; 36 | show(CppCommon::UtcTime(CppCommon::Timestamp(0))); 37 | 38 | std::cout << "Max time:" << std::endl; 39 | show(CppCommon::UtcTime(CppCommon::Timestamp(0xFFFFFFFFFFFFFFFF))); 40 | 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /examples/time_timespan.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file time_timespan.cpp 3 | \brief Timespan example 4 | \author Ivan Shynkarenka 5 | \date 11.07.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "time/timespan.h" 10 | 11 | #include 12 | #include 13 | 14 | int main(int argc, char** argv) 15 | { 16 | std::cout << "Please enter timespan milliseconds as an integer number..." << std::endl; 17 | 18 | std::string line; 19 | getline(std::cin, line); 20 | int milliseconds = std::stoi(line); 21 | 22 | CppCommon::Timespan timespan = CppCommon::Timespan::milliseconds(milliseconds); 23 | 24 | std::cout << "Timespan.days() = " << timespan.days() << std::endl; 25 | std::cout << "Timespan.hours() = " << (timespan.hours() % 24) << std::endl; 26 | std::cout << "Timespan.minutes() = " << (timespan.minutes() % 60) << std::endl; 27 | std::cout << "Timespan.seconds() = " << (timespan.seconds() % 60) << std::endl; 28 | std::cout << "Timespan.milliseconds() = " << (timespan.milliseconds() % 1000) << std::endl; 29 | 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /examples/time_timezone.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file time_timezone.cpp 3 | \brief Timezone example 4 | \author Ivan Shynkarenka 5 | \date 18.07.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "time/timezone.h" 10 | 11 | #include 12 | 13 | void show(const CppCommon::Timezone& time_zone) 14 | { 15 | std::cout << "Time.name() = " << time_zone.name() << std::endl; 16 | std::cout << "Time.offset() = " << time_zone.offset().seconds() << std::endl; 17 | std::cout << "Time.daylight() = " << time_zone.daylight().seconds() << std::endl; 18 | std::cout << std::endl; 19 | } 20 | 21 | int main(int argc, char** argv) 22 | { 23 | std::cout << "UTC timezone:" << std::endl; 24 | show(CppCommon::Timezone::utc()); 25 | 26 | std::cout << "Local timezone:" << std::endl; 27 | show(CppCommon::Timezone::local()); 28 | 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /examples/utility_singleton.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file utility_singleton.cpp 3 | \brief Singleton example 4 | \author Ivan Shynkarenka 5 | \date 31.08.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "utility/singleton.h" 10 | 11 | #include 12 | 13 | class MySingleton : public CppCommon::Singleton 14 | { 15 | friend CppCommon::Singleton; 16 | 17 | public: 18 | void Test() { std::cout << "MySingleton::Test()" << std::endl; } 19 | 20 | private: 21 | MySingleton() { std::cout << "MySingleton::MySingleton()" << std::endl; } 22 | ~MySingleton() { std::cout << "MySingleton::~MySingleton()" << std::endl; } 23 | }; 24 | 25 | int main(int argc, char** argv) 26 | { 27 | MySingleton::GetInstance().Test(); 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /examples/utility_static_constructor.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file utility_static_constructor.cpp 3 | \brief Static constructor pattern example 4 | \author Ivan Shynkarenka 5 | \date 31.08.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "utility/static_constructor.h" 10 | 11 | #include 12 | 13 | class MyClass 14 | { 15 | public: 16 | MyClass() { std::cout << "MyClass::MyClass() - MyClass::value = " << value << std::endl; } 17 | ~MyClass() { std::cout << "MyClass::~MyClass() - MyClass::value = " << value << std::endl; } 18 | 19 | void Test() { std::cout << "MyClass::Test() - MyClass::value = " << value << std::endl; } 20 | 21 | private: 22 | static int value; 23 | 24 | static void StaticConstructor() 25 | { 26 | CppCommon::StaticConstructor<&MyClass::StaticConstructor, &MyClass::StaticDestructor>::instance(); 27 | 28 | value = 123; 29 | std::cout << "MyClass::StaticConstructor() - MyClass::value = " << value << std::endl; 30 | } 31 | 32 | static void StaticDestructor() 33 | { 34 | value = 0; 35 | std::cout << "MyClass::StaticDestructor() - MyClass::value = " << value << std::endl; 36 | } 37 | }; 38 | 39 | int MyClass::value = 0; 40 | 41 | int main(int argc, char** argv) 42 | { 43 | MyClass instance; 44 | instance.Test(); 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /images/BinTree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronoxor/CppCommon/3c1cbdc42f09f2010ef3698fd0db1d48fe3140f8/images/BinTree.png -------------------------------------------------------------------------------- /images/BinTreeRB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronoxor/CppCommon/3c1cbdc42f09f2010ef3698fd0db1d48fe3140f8/images/BinTreeRB.png -------------------------------------------------------------------------------- /images/BinTreeSplay-Zig.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronoxor/CppCommon/3c1cbdc42f09f2010ef3698fd0db1d48fe3140f8/images/BinTreeSplay-Zig.png -------------------------------------------------------------------------------- /images/BinTreeSplay-Zigzag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronoxor/CppCommon/3c1cbdc42f09f2010ef3698fd0db1d48fe3140f8/images/BinTreeSplay-Zigzag.png -------------------------------------------------------------------------------- /images/BinTreeSplay-Zigzig.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronoxor/CppCommon/3c1cbdc42f09f2010ef3698fd0db1d48fe3140f8/images/BinTreeSplay-Zigzig.png -------------------------------------------------------------------------------- /images/List.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronoxor/CppCommon/3c1cbdc42f09f2010ef3698fd0db1d48fe3140f8/images/List.png -------------------------------------------------------------------------------- /images/Queue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronoxor/CppCommon/3c1cbdc42f09f2010ef3698fd0db1d48fe3140f8/images/Queue.png -------------------------------------------------------------------------------- /images/Stack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronoxor/CppCommon/3c1cbdc42f09f2010ef3698fd0db1d48fe3140f8/images/Stack.png -------------------------------------------------------------------------------- /images/TokenBucket.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronoxor/CppCommon/3c1cbdc42f09f2010ef3698fd0db1d48fe3140f8/images/TokenBucket.png -------------------------------------------------------------------------------- /include/algorithms/token_bucket.inl: -------------------------------------------------------------------------------- 1 | /*! 2 | \file token_bucket.inl 3 | \brief Token bucket rate limit algorithm inline implementation 4 | \author Ivan Shynkarenka 5 | \date 07.12.2016 6 | \copyright MIT License 7 | */ 8 | 9 | namespace CppCommon { 10 | 11 | inline TokenBucket::TokenBucket(uint64_t rate, uint64_t burst) 12 | : _time(0), 13 | _time_per_token(1000000000 / rate), 14 | _time_per_burst(burst * _time_per_token) 15 | { 16 | 17 | } 18 | 19 | inline TokenBucket::TokenBucket(const TokenBucket& tb) 20 | : _time(tb._time.load()), 21 | _time_per_token(tb._time_per_token.load()), 22 | _time_per_burst(tb._time_per_burst.load()) 23 | { 24 | } 25 | 26 | inline TokenBucket& TokenBucket::operator=(const TokenBucket& tb) 27 | { 28 | _time = tb._time.load(); 29 | _time_per_token = tb._time_per_token.load(); 30 | _time_per_burst = tb._time_per_burst.load(); 31 | return *this; 32 | } 33 | 34 | } // namespace CppCommon 35 | -------------------------------------------------------------------------------- /include/cache/filecache.inl: -------------------------------------------------------------------------------- 1 | /*! 2 | \file filecache.inl 3 | \brief File cache inline implementation 4 | \author Ivan Shynkarenka 5 | \date 14.05.2019 6 | \copyright MIT License 7 | */ 8 | 9 | namespace CppCommon { 10 | 11 | inline bool FileCache::empty() const 12 | { 13 | std::shared_lock locker(_lock); 14 | return _entries_by_key.empty(); 15 | } 16 | 17 | inline size_t FileCache::size() const 18 | { 19 | std::shared_lock locker(_lock); 20 | return _entries_by_key.size(); 21 | } 22 | 23 | inline void swap(FileCache& cache1, FileCache& cache2) noexcept 24 | { 25 | cache1.swap(cache2); 26 | } 27 | 28 | } // namespace CppCommon 29 | -------------------------------------------------------------------------------- /include/common/flags.inl: -------------------------------------------------------------------------------- 1 | /*! 2 | \file flags.inl 3 | \brief Enum-based flags inline implementation 4 | \author Ivan Shynkarenka 5 | \date 25.08.2016 6 | \copyright MIT License 7 | */ 8 | 9 | namespace CppCommon { 10 | 11 | template 12 | inline void swap(Flags& flags1, Flags& flags2) noexcept 13 | { 14 | flags1.swap(flags2); 15 | } 16 | 17 | template 18 | constexpr auto operator&(TEnum value1, TEnum value2) noexcept -> typename std::enable_if::value, Flags>::type 19 | { 20 | return Flags(value1) & value2; 21 | } 22 | 23 | template 24 | constexpr auto operator|(TEnum value1, TEnum value2) noexcept -> typename std::enable_if::value, Flags>::type 25 | { 26 | return Flags(value1) | value2; 27 | } 28 | 29 | template 30 | constexpr auto operator^(TEnum value1, TEnum value2) noexcept -> typename std::enable_if::value, Flags>::type 31 | { 32 | return Flags(value1) ^ value2; 33 | } 34 | 35 | } // namespace CppCommon 36 | -------------------------------------------------------------------------------- /include/common/reader.h: -------------------------------------------------------------------------------- 1 | /*! 2 | \file reader.h 3 | \brief Reader interface definition 4 | \author Ivan Shynkarenka 5 | \date 07.12.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #ifndef CPPCOMMON_READER_H 10 | #define CPPCOMMON_READER_H 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | namespace CppCommon { 17 | 18 | //! Reader interface 19 | /*! 20 | Reader interface is based on a read byte buffer method and provides 21 | functionality to read all bytes, text or text lines. 22 | */ 23 | class Reader 24 | { 25 | public: 26 | Reader() noexcept = default; 27 | Reader(const Reader&) noexcept = default; 28 | Reader(Reader&&) noexcept = default; 29 | virtual ~Reader() noexcept = default; 30 | 31 | Reader& operator=(const Reader&) noexcept = default; 32 | Reader& operator=(Reader&&) noexcept = default; 33 | 34 | //! Read a bytes buffer base method 35 | /*! 36 | \param buffer - Buffer to read 37 | \param size - Buffer size 38 | \return Count of read bytes 39 | */ 40 | virtual size_t Read(void* buffer, size_t size) = 0; 41 | 42 | //! Read all bytes 43 | /*! 44 | \return Bytes buffer 45 | */ 46 | std::vector ReadAllBytes(); 47 | //! Read all text 48 | /*! 49 | \return Text string 50 | */ 51 | std::string ReadAllText(); 52 | //! Read all text lines 53 | /*! 54 | \return Text lines 55 | */ 56 | std::vector ReadAllLines(); 57 | }; 58 | 59 | } // namespace CppCommon 60 | 61 | #endif // CPPCOMMON_READER_H 62 | -------------------------------------------------------------------------------- /include/common/version.h: -------------------------------------------------------------------------------- 1 | /*! 2 | \file version.h 3 | \brief Version definition 4 | \author Ivan Shynkarenka 5 | \date 18.01.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #ifndef CPPCOMMON_VERSION_H 10 | #define CPPCOMMON_VERSION_H 11 | 12 | /*! \mainpage C++ Common Library 13 | 14 | C++ Common Library contains reusable components and patterns for error and 15 | exceptions handling, filesystem manipulations, math, string format and 16 | encoding, shared memory, threading, time management and others. 17 | 18 | This document contains CppCommon API references. 19 | 20 | Library description, features, requirements and usage examples can be find on 21 | GitHub: https://github.com/chronoxor/CppCommon 22 | 23 | */ 24 | 25 | /*! 26 | \namespace CppCommon 27 | \brief C++ Common project definitions 28 | */ 29 | namespace CppCommon { 30 | 31 | //! Project version 32 | const char version[] = "1.0.5.0"; 33 | 34 | } // namespace CppCommon 35 | 36 | #endif // CPPCOMMON_VERSION_H 37 | -------------------------------------------------------------------------------- /include/common/writer.h: -------------------------------------------------------------------------------- 1 | /*! 2 | \file writer.h 3 | \brief Writer interface definition 4 | \author Ivan Shynkarenka 5 | \date 07.12.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #ifndef CPPCOMMON_WRITER_H 10 | #define CPPCOMMON_WRITER_H 11 | 12 | #include 13 | #include 14 | 15 | namespace CppCommon { 16 | 17 | //! Writer interface 18 | /*! 19 | Writer interface is based on a write byte buffer method and provides 20 | functionality to write bytes buffer, text or text lines. 21 | */ 22 | class Writer 23 | { 24 | public: 25 | Writer() noexcept = default; 26 | Writer(const Writer&) noexcept = default; 27 | Writer(Writer&&) noexcept = default; 28 | virtual ~Writer() noexcept = default; 29 | 30 | Writer& operator=(const Writer&) noexcept = default; 31 | Writer& operator=(Writer&&) noexcept = default; 32 | 33 | //! Write a byte buffer base method 34 | /*! 35 | \param buffer - Buffer to write 36 | \param size - Buffer size 37 | \return Count of written bytes 38 | */ 39 | virtual size_t Write(const void* buffer, size_t size) = 0; 40 | 41 | //! Write a text string 42 | /*! 43 | \param text - Text string 44 | \return Count of written characters 45 | */ 46 | size_t Write(const std::string& text); 47 | //! Write text lines 48 | /*! 49 | \param lines - Text lines 50 | \return Count of written lines 51 | */ 52 | size_t Write(const std::vector& lines); 53 | 54 | //! Flush the writer 55 | virtual void Flush() {} 56 | }; 57 | 58 | } // namespace CppCommon 59 | 60 | #endif // CPPCOMMON_WRITER_H 61 | -------------------------------------------------------------------------------- /include/errors/exceptions.inl: -------------------------------------------------------------------------------- 1 | /*! 2 | \file include/errors/exceptions.inl 3 | \brief Exceptions inline implementation 4 | \author Ivan Shynkarenka 5 | \date 09.02.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #if defined(FMT_VERSION) 10 | template <> 11 | struct fmt::formatter : formatter 12 | { 13 | template 14 | auto format(const CppCommon::Exception& value, FormatContext& ctx) const 15 | { 16 | return formatter::format(value.string(), ctx); 17 | } 18 | }; 19 | #endif 20 | -------------------------------------------------------------------------------- /include/filesystem/directory.inl: -------------------------------------------------------------------------------- 1 | /*! 2 | \file directory.inl 3 | \brief Filesystem directory inline implementation 4 | \author Ivan Shynkarenka 5 | \date 30.08.2016 6 | \copyright MIT License 7 | */ 8 | 9 | namespace CppCommon { 10 | 11 | inline void Directory::swap(Directory& directory) noexcept 12 | { 13 | using std::swap; 14 | Path::swap(directory); 15 | } 16 | 17 | inline void swap(Directory& directory1, Directory& directory2) noexcept 18 | { 19 | directory1.swap(directory2); 20 | } 21 | 22 | } // namespace CppCommon 23 | -------------------------------------------------------------------------------- /include/filesystem/directory_iterator.inl: -------------------------------------------------------------------------------- 1 | /*! 2 | \file directory_iterator.inl 3 | \brief Filesystem directory iterator inline implementation 4 | \author Ivan Shynkarenka 5 | \date 04.09.2016 6 | \copyright MIT License 7 | */ 8 | 9 | namespace CppCommon { 10 | 11 | inline bool operator==(const DirectoryIterator& it1, const DirectoryIterator& it2) noexcept 12 | { 13 | return it1._current == it2._current; 14 | } 15 | 16 | inline bool operator!=(const DirectoryIterator& it1, const DirectoryIterator& it2) noexcept 17 | { 18 | return it1._current != it2._current; 19 | } 20 | 21 | inline const Path& DirectoryIterator::operator*() const noexcept 22 | { 23 | return _current; 24 | } 25 | 26 | inline const Path* DirectoryIterator::operator->() const noexcept 27 | { 28 | return &_current; 29 | } 30 | 31 | inline void DirectoryIterator::swap(DirectoryIterator& it) noexcept 32 | { 33 | using std::swap; 34 | _pimpl.swap(it._pimpl); 35 | } 36 | 37 | inline void swap(DirectoryIterator& it1, DirectoryIterator& it2) noexcept 38 | { 39 | it1.swap(it2); 40 | } 41 | 42 | } // namespace CppCommon 43 | -------------------------------------------------------------------------------- /include/filesystem/exceptions.h: -------------------------------------------------------------------------------- 1 | /*! 2 | \file include/filesystem/exceptions.h 3 | \brief File system exceptions definition 4 | \author Ivan Shynkarenka 5 | \date 24.08.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #ifndef CPPCOMMON_FILESYSTEM_EXCEPTIONS_H 10 | #define CPPCOMMON_FILESYSTEM_EXCEPTIONS_H 11 | 12 | #include "errors/exceptions.h" 13 | #include "filesystem/path.h" 14 | 15 | namespace CppCommon { 16 | 17 | //! File system exception 18 | class FileSystemException : public SystemException 19 | { 20 | public: 21 | using SystemException::SystemException; 22 | 23 | //! Get exception path 24 | const Path& path() const noexcept { return _path; } 25 | 26 | //! Get string from the current exception 27 | std::string string() const override; 28 | 29 | //! Attach the given path to the exception 30 | /*! 31 | \param path - Exception path 32 | */ 33 | FileSystemException& Attach(const Path& path) 34 | { _path = path; return *this; } 35 | //! Attach the given source and destination paths to the exception 36 | /*! 37 | \param src - Exception source path 38 | \param dst - Exception destination path 39 | */ 40 | FileSystemException& Attach(const Path& src, const Path& dst) 41 | { _src = src; _dst = dst; return *this; } 42 | 43 | protected: 44 | //! Filesystem exception path 45 | Path _path; 46 | //! Filesystem exception source path 47 | Path _src; 48 | //! Filesystem exception destination path 49 | Path _dst; 50 | }; 51 | 52 | } // namespace CppCommon 53 | 54 | #endif // CPPCOMMON_FILESYSTEM_EXCEPTIONS_H 55 | -------------------------------------------------------------------------------- /include/filesystem/file.inl: -------------------------------------------------------------------------------- 1 | /*! 2 | \file file.inl 3 | \brief Filesystem file inline implementation 4 | \author Ivan Shynkarenka 5 | \date 29.08.2016 6 | \copyright MIT License 7 | */ 8 | 9 | namespace CppCommon { 10 | 11 | inline void swap(File& file1, File& file2) noexcept 12 | { 13 | file1.swap(file2); 14 | } 15 | 16 | } // namespace CppCommon 17 | -------------------------------------------------------------------------------- /include/filesystem/filesystem.h: -------------------------------------------------------------------------------- 1 | /*! 2 | \file filesystem.h 3 | \brief Filesystem definition 4 | \author Ivan Shynkarenka 5 | \date 07.09.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #ifndef CPPCOMMON_FILESYSTEM_H 10 | #define CPPCOMMON_FILESYSTEM_H 11 | 12 | #include "filesystem/directory.h" 13 | #include "filesystem/exceptions.h" 14 | #include "filesystem/file.h" 15 | #include "filesystem/path.h" 16 | #include "filesystem/symlink.h" 17 | 18 | #endif // CPPCOMMON_FILESYSTEM_H 19 | -------------------------------------------------------------------------------- /include/filesystem/path.inl: -------------------------------------------------------------------------------- 1 | /*! 2 | \file path.inl 3 | \brief Filesystem path inline implementation 4 | \author Ivan Shynkarenka 5 | \date 11.08.2016 6 | \copyright MIT License 7 | */ 8 | 9 | ENUM_FLAGS(CppCommon::FileAttributes) 10 | ENUM_FLAGS(CppCommon::FilePermissions) 11 | 12 | namespace CppCommon { 13 | 14 | inline bool Path::IsOther() const 15 | { 16 | FileType t = type(); 17 | return ((t != FileType::NONE) && (t != FileType::REGULAR) && (t != FileType::DIRECTORY) && (t != FileType::SYMLINK)); 18 | } 19 | 20 | inline Path& Path::Assign(const Path& path) 21 | { 22 | _path = path._path; 23 | return *this; 24 | } 25 | 26 | inline Path& Path::Concat(const Path& path) 27 | { 28 | _path.append(path._path); 29 | return *this; 30 | } 31 | 32 | inline void Path::swap(Path& path) noexcept 33 | { 34 | using std::swap; 35 | swap(_path, path._path); 36 | } 37 | 38 | inline void swap(Path& path1, Path& path2) noexcept 39 | { 40 | path1.swap(path2); 41 | } 42 | 43 | } // namespace CppCommon 44 | 45 | #if defined(FMT_VERSION) 46 | template <> 47 | struct fmt::formatter : formatter 48 | { 49 | template 50 | auto format(const CppCommon::Path& value, FormatContext& ctx) const 51 | { 52 | return formatter::format(value.string(), ctx); 53 | } 54 | }; 55 | #endif 56 | -------------------------------------------------------------------------------- /include/filesystem/symlink.inl: -------------------------------------------------------------------------------- 1 | /*! 2 | \file symlink.inl 3 | \brief Filesystem symlink inline implementation 4 | \author Ivan Shynkarenka 5 | \date 30.08.2016 6 | \copyright MIT License 7 | */ 8 | 9 | namespace CppCommon { 10 | 11 | inline void Symlink::swap(Symlink& symlink) noexcept 12 | { 13 | using std::swap; 14 | Path::swap(symlink); 15 | } 16 | 17 | inline void swap(Symlink& symlink1, Symlink& symlink2) noexcept 18 | { 19 | symlink1.swap(symlink2); 20 | } 21 | 22 | } // namespace CppCommon 23 | -------------------------------------------------------------------------------- /include/math/math.h: -------------------------------------------------------------------------------- 1 | /*! 2 | \file math.h 3 | \brief Math definition 4 | \author Ivan Shynkarenka 5 | \date 01.09.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #ifndef CPPCOMMON_MATH_MATH_H 10 | #define CPPCOMMON_MATH_MATH_H 11 | 12 | #include 13 | 14 | namespace CppCommon { 15 | 16 | //! Math static class 17 | /*! 18 | Contains useful math functions. 19 | 20 | Thread-safe. 21 | */ 22 | class Math 23 | { 24 | public: 25 | Math() = delete; 26 | Math(const Math&) = delete; 27 | Math(Math&&) = delete; 28 | ~Math() = delete; 29 | 30 | Math& operator=(const Math&) = delete; 31 | Math& operator=(Math&&) = delete; 32 | 33 | //! Computes the greatest common divisor of a and b 34 | /*! 35 | \param a - Value a 36 | \param b - Value b 37 | \return Greatest common divisor of a and b 38 | */ 39 | template 40 | static T GCD(T a, T b); 41 | 42 | //! Finds the smallest value x >= a such that x % k == 0 43 | /*! 44 | \param a - Value a 45 | \param k - Value k 46 | \return Value x 47 | */ 48 | template 49 | static T RoundUp(T a, T k); 50 | 51 | //! Calculate (operant * multiplier / divider) with 64-bit unsigned integer values 52 | /*! 53 | \param operant - Operant 54 | \param multiplier - Multiplier 55 | \param divider - Divider 56 | \return Calculated value of (operant * multiplier / divider) expression 57 | */ 58 | static uint64_t MulDiv64(uint64_t operant, uint64_t multiplier, uint64_t divider); 59 | }; 60 | 61 | /*! \example math_math.cpp Math example */ 62 | 63 | } // namespace CppCommon 64 | 65 | #include "math.inl" 66 | 67 | #endif // CPPCOMMON_MATH_MATH_H 68 | -------------------------------------------------------------------------------- /include/math/math.inl: -------------------------------------------------------------------------------- 1 | /*! 2 | \file math.inl 3 | \brief Math inline implementation 4 | \author Ivan Shynkarenka 5 | \date 01.09.2016 6 | \copyright MIT License 7 | */ 8 | 9 | namespace CppCommon { 10 | 11 | template 12 | inline T GCD(T a, T b) 13 | { 14 | T c = a % b; 15 | 16 | while (c != 0) 17 | { 18 | a = b; 19 | b = c; 20 | c = a % b; 21 | } 22 | 23 | return b; 24 | } 25 | 26 | template 27 | inline T Math::RoundUp(T a, T k) 28 | { 29 | return ((a + k - 1) / k) * k; 30 | } 31 | 32 | } // namespace CppCommon 33 | -------------------------------------------------------------------------------- /include/memory/allocator_heap.inl: -------------------------------------------------------------------------------- 1 | /*! 2 | \file allocator_heap.inl 3 | \brief Heap memory allocator inline implementation 4 | \author Ivan Shynkarenka 5 | \date 07.06.2017 6 | \copyright MIT License 7 | */ 8 | 9 | namespace CppCommon { 10 | 11 | inline void* HeapMemoryManager::malloc(size_t size, size_t alignment) 12 | { 13 | assert((size > 0) && "Allocated block size must be greater than zero!"); 14 | assert(Memory::IsValidAlignment(alignment) && "Alignment must be valid!"); 15 | 16 | #if defined(_WIN32) || defined(_WIN64) 17 | void* result = HeapAlloc(GetProcessHeap(), 0, size); 18 | #else 19 | void* result = std::malloc(size); 20 | #endif 21 | if (result != nullptr) 22 | { 23 | // Update allocation statistics 24 | _allocated += size; 25 | ++_allocations; 26 | } 27 | return result; 28 | } 29 | 30 | inline void HeapMemoryManager::free(void* ptr, size_t size) 31 | { 32 | assert((ptr != nullptr) && "Deallocated block must be valid!"); 33 | 34 | if (ptr != nullptr) 35 | { 36 | #if defined(_WIN32) || defined(_WIN64) 37 | HeapFree(GetProcessHeap(), 0, (LPVOID)ptr); 38 | #else 39 | std::free(ptr); 40 | #endif 41 | 42 | // Update allocation statistics 43 | _allocated -= size; 44 | --_allocations; 45 | } 46 | } 47 | 48 | inline void HeapMemoryManager::reset() 49 | { 50 | assert((_allocated == 0) && "Memory leak detected! Allocated memory size must be zero!"); 51 | assert((_allocations == 0) && "Memory leak detected! Count of active memory allocations must be zero!"); 52 | } 53 | 54 | } // namespace CppCommon 55 | -------------------------------------------------------------------------------- /include/memory/allocator_null.inl: -------------------------------------------------------------------------------- 1 | /*! 2 | \file allocator_null.inl 3 | \brief Null memory allocator inline implementation 4 | \author Ivan Shynkarenka 5 | \date 17.04.2017 6 | \copyright MIT License 7 | */ 8 | 9 | namespace CppCommon { 10 | 11 | inline void* NullMemoryManager::malloc(size_t size, size_t alignment) 12 | { 13 | assert((size > 0) && "Allocated block size must be greater than zero!"); 14 | assert(Memory::IsValidAlignment(alignment) && "Alignment must be valid!"); 15 | 16 | // Not enough memory... 17 | return nullptr; 18 | } 19 | 20 | inline void NullMemoryManager::free(void* ptr, size_t size) 21 | { 22 | assert((ptr != nullptr) && "Deallocated block must be valid!"); 23 | 24 | if (ptr != nullptr) 25 | { 26 | // Update allocation statistics 27 | _allocated -= size; 28 | --_allocations; 29 | } 30 | } 31 | 32 | inline void NullMemoryManager::reset() 33 | { 34 | assert((_allocated == 0) && "Memory leak detected! Allocated memory size must be zero!"); 35 | assert((_allocations == 0) && "Memory leak detected! Count of active memory allocations must be zero!"); 36 | } 37 | 38 | } // namespace CppCommon 39 | -------------------------------------------------------------------------------- /include/memory/memory.inl: -------------------------------------------------------------------------------- 1 | /*! 2 | \file memory.inl 3 | \brief Memory management inline implementation 4 | \author Ivan Shynkarenka 5 | \date 27.07.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include 10 | 11 | namespace CppCommon { 12 | 13 | inline bool Memory::IsValidAlignment(size_t alignment) noexcept 14 | { 15 | return ((alignment > 0) && ((alignment & (alignment - 1)) == 0)); 16 | } 17 | 18 | template 19 | inline bool Memory::IsAligned(const T* address, size_t alignment) noexcept 20 | { 21 | assert((address != nullptr) && "Address must be valid!"); 22 | assert(IsValidAlignment(alignment) && "Alignment must be valid!"); 23 | 24 | uintptr_t ptr = (uintptr_t)address; 25 | return (ptr & (alignment - 1)) == 0; 26 | } 27 | 28 | template 29 | inline T* Memory::Align(const T* address, size_t alignment, bool upwards) noexcept 30 | { 31 | assert((address != nullptr) && "Address must be valid!"); 32 | assert(IsValidAlignment(alignment) && "Alignment must be valid!"); 33 | 34 | uintptr_t ptr = (uintptr_t)address; 35 | 36 | if (upwards) 37 | return (T*)((ptr + (alignment - 1)) & -((int)alignment)); 38 | else 39 | return (T*)(ptr & -((int)alignment)); 40 | } 41 | 42 | } // namespace CppCommon 43 | -------------------------------------------------------------------------------- /include/memory/memory_leaks.h: -------------------------------------------------------------------------------- 1 | /*! 2 | \file memory_leaks.h 3 | \brief Memory leaks detecting tool. Include this file to detect memory leaks in release build. 4 | \author Ivan Shynkarenka 5 | \date 26.02.2018 6 | \copyright MIT License 7 | */ 8 | 9 | #ifndef CPPCOMMON_MEMORY_MEMORY_LEAKS_H 10 | #define CPPCOMMON_MEMORY_MEMORY_LEAKS_H 11 | 12 | #if defined(__clang__) 13 | #pragma clang system_header 14 | #elif defined(__GNUC__) 15 | #pragma GCC system_header 16 | #elif defined(_MSC_VER) 17 | #pragma system_header 18 | #endif 19 | 20 | //! @cond INTERNALS 21 | #if defined(_MSC_VER) 22 | #define VLD_FORCE_ENABLE 23 | #include 24 | #endif 25 | //! @endcond 26 | 27 | /*! \example memory_leaks.cpp Memory leaks detection example */ 28 | 29 | #endif // CPPCOMMON_MEMORY_MEMORY_LEAKS_H 30 | -------------------------------------------------------------------------------- /include/memory/memory_leaks_debug.h: -------------------------------------------------------------------------------- 1 | /*! 2 | \file memory_leaks_debug.h 3 | \brief Memory leaks detecting tool. Include this file to detect memory leaks in debug build. 4 | \author Ivan Shynkarenka 5 | \date 26.02.2018 6 | \copyright MIT License 7 | */ 8 | 9 | #ifndef CPPCOMMON_MEMORY_MEMORY_LEAKS_DEBUG_H 10 | #define CPPCOMMON_MEMORY_MEMORY_LEAKS_DEBUG_H 11 | 12 | #if defined(__clang__) 13 | #pragma clang system_header 14 | #elif defined(__GNUC__) 15 | #pragma GCC system_header 16 | #elif defined(_MSC_VER) 17 | #pragma system_header 18 | #endif 19 | 20 | //! @cond INTERNALS 21 | #if defined(_MSC_VER) 22 | #include 23 | #endif 24 | //! @endcond 25 | 26 | #endif // CPPCOMMON_MEMORY_MEMORY_LEAKS_DEBUG_H 27 | -------------------------------------------------------------------------------- /include/string/format.inl: -------------------------------------------------------------------------------- 1 | /*! 2 | \file format.inl 3 | \brief Format string inline implementation 4 | \author Ivan Shynkarenka 5 | \date 16.09.2016 6 | \copyright MIT License 7 | */ 8 | 9 | namespace CppCommon { 10 | 11 | template 12 | inline std::string format(fmt::format_string pattern, T&&... args) 13 | { 14 | return fmt::vformat(pattern, fmt::make_format_args(args...)); 15 | } 16 | 17 | template 18 | inline std::wstring format(fmt::wformat_string pattern, T&&... args) 19 | { 20 | return fmt::vformat(pattern, fmt::make_format_args(args...)); 21 | } 22 | 23 | template 24 | inline void print(fmt::format_string pattern, T&&... args) 25 | { 26 | return fmt::vprint(pattern, fmt::make_format_args(args...)); 27 | } 28 | 29 | template 30 | inline void print(fmt::wformat_string pattern, T&&... args) 31 | { 32 | return fmt::vprint(pattern, fmt::make_format_args(args...)); 33 | } 34 | 35 | template 36 | inline void print(TOutputStream& stream, fmt::format_string pattern, T&&... args) 37 | { 38 | return fmt::vprint(stream, pattern, fmt::make_format_args(args...)); 39 | } 40 | 41 | template 42 | inline void print(TOutputStream& stream, fmt::wformat_string pattern, T&&... args) 43 | { 44 | return fmt::vprint(stream, pattern, fmt::make_format_args(args...)); 45 | } 46 | 47 | } // namespace CppCommon 48 | 49 | //! @cond INTERNALS 50 | 51 | using namespace fmt::literals; 52 | 53 | //! @endcond 54 | -------------------------------------------------------------------------------- /include/system/console.inl: -------------------------------------------------------------------------------- 1 | /*! 2 | \file console.inl 3 | \brief Console management inline implementation 4 | \author Ivan Shynkarenka 5 | \date 27.07.2016 6 | \copyright MIT License 7 | */ 8 | 9 | namespace CppCommon { 10 | 11 | template 12 | inline TOutputStream& operator<<(TOutputStream& stream, Color color) 13 | { 14 | Console::SetColor(color); 15 | return stream; 16 | } 17 | 18 | template 19 | inline TOutputStream& operator<<(TOutputStream& stream, std::pair colors) 20 | { 21 | Console::SetColor(colors.first, colors.second); 22 | return stream; 23 | } 24 | 25 | } // namespace CppCommon 26 | -------------------------------------------------------------------------------- /include/system/cpu.h: -------------------------------------------------------------------------------- 1 | /*! 2 | \file cpu.h 3 | \brief CPU management definition 4 | \author Ivan Shynkarenka 5 | \date 27.07.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #ifndef CPPCOMMON_SYSTEM_CPU_H 10 | #define CPPCOMMON_SYSTEM_CPU_H 11 | 12 | #include 13 | #include 14 | 15 | namespace CppCommon { 16 | 17 | //! CPU management static class 18 | /*! 19 | Provides CPU management functionality such as architecture, cores count, 20 | clock speed, Hyper-Threading feature. 21 | 22 | Thread-safe. 23 | */ 24 | class CPU 25 | { 26 | public: 27 | CPU() = delete; 28 | CPU(const CPU&) = delete; 29 | CPU(CPU&&) = delete; 30 | ~CPU() = delete; 31 | 32 | CPU& operator=(const CPU&) = delete; 33 | CPU& operator=(CPU&&) = delete; 34 | 35 | //! CPU architecture string 36 | static std::string Architecture(); 37 | //! CPU affinity count 38 | static int Affinity(); 39 | //! CPU logical cores count 40 | static int LogicalCores(); 41 | //! CPU physical cores count 42 | static int PhysicalCores(); 43 | //! CPU total cores count 44 | static std::pair TotalCores(); 45 | //! CPU clock speed in Hz 46 | static int64_t ClockSpeed(); 47 | //! Is CPU Hyper-Threading enabled? 48 | static bool HyperThreading(); 49 | }; 50 | 51 | /*! \example system_cpu.cpp CPU management example */ 52 | 53 | } // namespace CppCommon 54 | 55 | #endif // CPPCOMMON_SYSTEM_CPU_H 56 | -------------------------------------------------------------------------------- /include/system/dll.inl: -------------------------------------------------------------------------------- 1 | /*! 2 | \file dll.inl 3 | \brief Dynamic link library inline implementation 4 | \author Ivan Shynkarenka 5 | \date 07.06.2017 6 | \copyright MIT License 7 | */ 8 | 9 | namespace CppCommon { 10 | 11 | template 12 | inline T* DLL::Resolve(const std::string& name) const 13 | { 14 | return (T*)ResolveAddress(name); 15 | } 16 | 17 | inline std::string DLL::prefix() 18 | { 19 | #if defined(__CYGWIN__) 20 | return "cyg"; 21 | #elif defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__) || defined(__MINGW32__) || defined(__MINGW64__) 22 | return "lib"; 23 | #else 24 | return ""; 25 | #endif 26 | } 27 | 28 | inline std::string DLL::extension() 29 | { 30 | #if defined(__APPLE__) 31 | return ".dylib"; 32 | #elif (defined(unix) || defined(__unix) || defined(__unix__)) && !defined(__CYGWIN__) 33 | return ".so"; 34 | #elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__) 35 | return ".dll"; 36 | #else 37 | return ""; 38 | #endif 39 | } 40 | 41 | inline void swap(DLL& dll1, DLL& dll2) noexcept 42 | { 43 | dll1.swap(dll2); 44 | } 45 | 46 | } // namespace CppCommon 47 | -------------------------------------------------------------------------------- /include/system/exceptions.h: -------------------------------------------------------------------------------- 1 | /*! 2 | \file include/system/exceptions.h 3 | \brief System exceptions definition 4 | \author Ivan Shynkarenka 5 | \date 07.06.2017 6 | \copyright MIT License 7 | */ 8 | 9 | #ifndef CPPCOMMON_SYSTEM_EXCEPTIONS_H 10 | #define CPPCOMMON_SYSTEM_EXCEPTIONS_H 11 | 12 | #include "filesystem/exceptions.h" 13 | 14 | namespace CppCommon { 15 | 16 | //! Dynamic link library exception 17 | class DLLException : public FileSystemException 18 | { 19 | public: 20 | using FileSystemException::FileSystemException; 21 | }; 22 | 23 | } // namespace CppCommon 24 | 25 | #endif // CPPCOMMON_SYSTEM_EXCEPTIONS_H 26 | -------------------------------------------------------------------------------- /include/system/pipe.inl: -------------------------------------------------------------------------------- 1 | /*! 2 | \file pipe.inl 3 | \brief Pipe inline implementation 4 | \author Ivan Shynkarenka 5 | \date 30.11.2016 6 | \copyright MIT License 7 | */ 8 | 9 | namespace CppCommon { 10 | 11 | inline void swap(Pipe& pipe1, Pipe& pipe2) noexcept 12 | { 13 | pipe1.swap(pipe2); 14 | } 15 | 16 | } // namespace CppCommon 17 | -------------------------------------------------------------------------------- /include/system/process.inl: -------------------------------------------------------------------------------- 1 | /*! 2 | \file process.inl 3 | \brief Process inline implementation 4 | \author Ivan Shynkarenka 5 | \date 01.12.2016 6 | \copyright MIT License 7 | */ 8 | 9 | namespace CppCommon { 10 | 11 | inline Process Process::CurrentProcess() 12 | { 13 | return Process(CurrentProcessId()); 14 | } 15 | 16 | inline Process Process::ParentProcess() 17 | { 18 | return Process(ParentProcessId()); 19 | } 20 | 21 | inline void swap(Process& process1, Process& process2) noexcept 22 | { 23 | process1.swap(process2); 24 | } 25 | 26 | } // namespace CppCommon 27 | -------------------------------------------------------------------------------- /include/system/shared_type.inl: -------------------------------------------------------------------------------- 1 | /*! 2 | \file shared_type.inl 3 | \brief Shared memory type inline implementation 4 | \author Ivan Shynkarenka 5 | \date 23.05.2016 6 | \copyright MIT License 7 | */ 8 | 9 | namespace CppCommon { 10 | 11 | template 12 | inline SharedType::SharedType(const std::string& name) : _shared(name, sizeof(T)) 13 | { 14 | // Check for the owner flag 15 | if (_shared.owner()) 16 | { 17 | // Call in place constructor 18 | new (_shared.ptr()) T(); 19 | } 20 | } 21 | 22 | } // namespace CppCommon 23 | -------------------------------------------------------------------------------- /include/system/source_location.inl: -------------------------------------------------------------------------------- 1 | /*! 2 | \file source_location.inl 3 | \brief Source location inline implementation 4 | \author Ivan Shynkarenka 5 | \date 09.02.2016 6 | \copyright MIT License 7 | */ 8 | 9 | namespace CppCommon { 10 | 11 | inline std::ostream& operator<<(std::ostream& os, const SourceLocation& source_location) 12 | { 13 | if ((source_location.filename() == nullptr) || (source_location.line() == 0)) 14 | return os; 15 | 16 | return os << source_location.filename() << ':' << source_location.line(); 17 | } 18 | 19 | } // namespace CppCommon 20 | 21 | #if defined(FMT_VERSION) 22 | template <> struct fmt::formatter : ostream_formatter {}; 23 | #endif 24 | -------------------------------------------------------------------------------- /include/system/stack_trace.inl: -------------------------------------------------------------------------------- 1 | /*! 2 | \file stack_trace.inl 3 | \brief Stack trace snapshot provider inline implementation 4 | \author Ivan Shynkarenka 5 | \date 09.02.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #if defined(FMT_VERSION) 10 | template <> struct fmt::formatter : ostream_formatter {}; 11 | #endif 12 | -------------------------------------------------------------------------------- /include/system/stream.inl: -------------------------------------------------------------------------------- 1 | /*! 2 | \file stream.inl 3 | \brief Standard input/output/error stream inline implementation 4 | \author Ivan Shynkarenka 5 | \date 23.07.2017 6 | \copyright MIT License 7 | */ 8 | 9 | namespace CppCommon { 10 | 11 | inline void swap(StdInput& stream1, StdInput& stream2) noexcept 12 | { 13 | stream1.swap(stream2); 14 | } 15 | 16 | inline void swap(StdOutput& stream1, StdOutput& stream2) noexcept 17 | { 18 | stream1.swap(stream2); 19 | } 20 | 21 | inline void swap(StdError& stream1, StdError& stream2) noexcept 22 | { 23 | stream1.swap(stream2); 24 | } 25 | 26 | } // namespace CppCommon 27 | -------------------------------------------------------------------------------- /include/threads/condition_variable.inl: -------------------------------------------------------------------------------- 1 | /*! 2 | \file condition_variable.inl 3 | \brief Condition variable synchronization primitive inline implementation 4 | \author Ivan Shynkarenka 5 | \date 03.10.2016 6 | \copyright MIT License 7 | */ 8 | 9 | namespace CppCommon { 10 | 11 | template 12 | void ConditionVariable::Wait(CriticalSection& cs, TPredicate predicate) 13 | { 14 | while (!predicate()) 15 | Wait(cs); 16 | } 17 | 18 | template 19 | bool ConditionVariable::TryWaitFor(CriticalSection& cs, const Timespan& timespan, TPredicate predicate) 20 | { 21 | Timestamp timeout = UtcTimestamp() + timespan; 22 | while (!predicate()) 23 | if (!TryWaitFor(cs, timeout - UtcTimestamp())) 24 | return predicate(); 25 | return true; 26 | } 27 | 28 | } // namespace CppCommon 29 | -------------------------------------------------------------------------------- /include/threads/latch.inl: -------------------------------------------------------------------------------- 1 | /*! 2 | \file latch.inl 3 | \brief Latch synchronization primitive inline implementation 4 | \author Ivan Shynkarenka 5 | \date 25.03.2016 6 | \copyright MIT License 7 | */ 8 | 9 | namespace CppCommon { 10 | 11 | inline Latch::Latch(int threads) noexcept : _generation(0), _threads(threads) 12 | { 13 | assert((threads > 0) && "Latch threads counter must be greater than zero!"); 14 | } 15 | 16 | inline bool Latch::TryWaitFor(const Timespan& timespan) noexcept 17 | { 18 | std::unique_lock lock(_mutex); 19 | 20 | // Check the latch threads counter value 21 | if (_threads == 0) 22 | return true; 23 | 24 | // Remember the current latch generation 25 | int generation = _generation; 26 | 27 | // Wait for the next latch generation 28 | return _cond.wait_for(lock, timespan.chrono(), [&, this]() { return generation != _generation; }); 29 | } 30 | 31 | inline bool Latch::TryWaitUntil(const Timestamp& timestamp) noexcept 32 | { 33 | std::unique_lock lock(_mutex); 34 | 35 | // Check the latch threads counter value 36 | if (_threads == 0) 37 | return true; 38 | 39 | // Remember the current latch generation 40 | int generation = _generation; 41 | 42 | // Wait for the next latch generation 43 | return _cond.wait_until(lock, timestamp.chrono(), [&, this]() { return generation != _generation; }); 44 | } 45 | 46 | } // namespace CppCommon 47 | -------------------------------------------------------------------------------- /include/threads/mpsc_ring_buffer.inl: -------------------------------------------------------------------------------- 1 | /*! 2 | \file mpsc_ring_buffer.inl 3 | \brief Multiple producers / single consumer wait-free ring buffer class inline implementation 4 | \author Ivan Shynkarenka 5 | \date 26.01.2016 6 | \copyright MIT License 7 | */ 8 | 9 | namespace CppCommon { 10 | 11 | inline MPSCRingBuffer::MPSCRingBuffer(size_t capacity, size_t concurrency) : _capacity(capacity - 1), _concurrency(concurrency), _consumer(0) 12 | { 13 | // Initialize producers' ring buffer 14 | for (size_t i = 0; i < concurrency; ++i) 15 | _producers.push_back(std::make_shared(capacity)); 16 | } 17 | 18 | inline size_t MPSCRingBuffer::size() const noexcept 19 | { 20 | size_t size = 0; 21 | for (const auto& producer : _producers) 22 | size += producer->buffer.size(); 23 | return size; 24 | } 25 | 26 | inline bool MPSCRingBuffer::Enqueue(const void* data, size_t size) 27 | { 28 | // Get producer index for the current thread based on RDTS value 29 | size_t index = Timestamp::rdts() % _concurrency; 30 | 31 | // Lock the chosen producer using its spin-lock 32 | Locker lock(_producers[index]->lock); 33 | 34 | // Enqueue the item into the producer's ring buffer 35 | return _producers[index]->buffer.Enqueue(data, size); 36 | } 37 | 38 | inline bool MPSCRingBuffer::Dequeue(void* data, size_t& size) 39 | { 40 | // Try to dequeue one item from the one of producer's ring buffers 41 | for (size_t i = 0; i < _concurrency; ++i) 42 | { 43 | size_t temp = size; 44 | if (_producers[_consumer++ % _concurrency]->buffer.Dequeue(data, temp)) 45 | { 46 | size = temp; 47 | return true; 48 | } 49 | } 50 | 51 | size = 0; 52 | return false; 53 | } 54 | 55 | } // namespace CppCommon 56 | -------------------------------------------------------------------------------- /include/threads/named_condition_variable.inl: -------------------------------------------------------------------------------- 1 | /*! 2 | \file named_condition_variable.inl 3 | \brief Named condition variable synchronization primitive inline implementation 4 | \author Ivan Shynkarenka 5 | \date 04.10.2016 6 | \copyright MIT License 7 | */ 8 | 9 | namespace CppCommon { 10 | 11 | template 12 | void NamedConditionVariable::Wait(TPredicate predicate) 13 | { 14 | while (!predicate()) 15 | Wait(); 16 | } 17 | 18 | template 19 | bool NamedConditionVariable::TryWaitFor(const Timespan& timespan, TPredicate predicate) 20 | { 21 | Timestamp timeout = UtcTimestamp() + timespan; 22 | while (!predicate()) 23 | if (!TryWaitFor(timeout - UtcTimestamp())) 24 | return predicate(); 25 | return true; 26 | } 27 | 28 | } // namespace CppCommon 29 | -------------------------------------------------------------------------------- /include/threads/seq_lock.inl: -------------------------------------------------------------------------------- 1 | /*! 2 | \file seq_lock.inl 3 | \brief Sequential lock synchronization primitive inline implementation 4 | \author Ivan Shynkarenka 5 | \date 17.08.2017 6 | \copyright MIT License 7 | */ 8 | 9 | namespace CppCommon { 10 | 11 | template 12 | inline SeqLock::SeqLock() : _seq(0) 13 | { 14 | memset(_pad0, 0, sizeof(cache_line_pad)); 15 | memset(_pad1, 0, sizeof(cache_line_pad)); 16 | } 17 | 18 | template 19 | inline SeqLock::SeqLock(const T& data) : SeqLock() 20 | { 21 | _data = data; 22 | } 23 | 24 | template 25 | inline SeqLock& SeqLock::operator=(const T& data) noexcept 26 | { 27 | Write(data); 28 | return *this; 29 | } 30 | 31 | template 32 | inline T SeqLock::Read() const noexcept 33 | { 34 | T data; 35 | size_t seq0; 36 | size_t seq1; 37 | 38 | do 39 | { 40 | seq0 = _seq.load(std::memory_order_acquire); 41 | std::atomic_signal_fence(std::memory_order_acq_rel); 42 | data = _data; 43 | std::atomic_signal_fence(std::memory_order_acq_rel); 44 | seq1 = _seq.load(std::memory_order_acquire); 45 | } while ((seq0 != seq1) || (seq0 & 1)); 46 | 47 | return data; 48 | } 49 | 50 | template 51 | inline void SeqLock::Write(const T& data) noexcept 52 | { 53 | size_t seq0 = _seq.load(std::memory_order_relaxed); 54 | _seq.store(seq0 + 1, std::memory_order_release); 55 | std::atomic_signal_fence(std::memory_order_acq_rel); 56 | _data = data; 57 | std::atomic_signal_fence(std::memory_order_acq_rel); 58 | _seq.store(seq0 + 2, std::memory_order_release); 59 | } 60 | 61 | } // namespace CppCommon 62 | -------------------------------------------------------------------------------- /include/threads/spin_barrier.inl: -------------------------------------------------------------------------------- 1 | /*! 2 | \file spin_barrier.inl 3 | \brief Spin barrier synchronization primitive inline implementation 4 | \author Ivan Shynkarenka 5 | \date 16.03.2016 6 | \copyright MIT License 7 | */ 8 | 9 | namespace CppCommon { 10 | 11 | inline SpinBarrier::SpinBarrier(int threads) noexcept : _counter(threads), _generation(0), _threads(threads) 12 | { 13 | assert((threads > 0) && "Count of barrier threads must be greater than zero!"); 14 | } 15 | 16 | inline bool SpinBarrier::Wait() noexcept 17 | { 18 | // Remember the current barrier generation 19 | int generation = _generation; 20 | 21 | // Decrease the count of waiting threads 22 | if (--_counter == 0) 23 | { 24 | // Increase the current barrier generation 25 | ++_generation; 26 | 27 | // Reset waiting threads counter 28 | _counter = _threads; 29 | 30 | // Notify the last thread that reached the barrier 31 | return true; 32 | } 33 | else 34 | { 35 | // Spin-wait for the next barrier generation 36 | while ((generation == _generation) || (_counter == 0)); 37 | 38 | // Notify each of remaining threads 39 | return false; 40 | } 41 | } 42 | 43 | } // namespace CppCommon 44 | -------------------------------------------------------------------------------- /include/threads/spin_lock.inl: -------------------------------------------------------------------------------- 1 | /*! 2 | \file spin_lock.inl 3 | \brief Spin-lock synchronization primitive inline implementation 4 | \author Ivan Shynkarenka 5 | \date 22.01.2016 6 | \copyright MIT License 7 | */ 8 | 9 | namespace CppCommon { 10 | 11 | inline bool SpinLock::IsLocked() noexcept 12 | { 13 | return _lock.load(std::memory_order_acquire); 14 | } 15 | 16 | inline bool SpinLock::TryLock() noexcept 17 | { 18 | return !_lock.exchange(true, std::memory_order_acquire); 19 | } 20 | 21 | inline bool SpinLock::TryLockSpin(int64_t spin) noexcept 22 | { 23 | // Try to acquire spin-lock at least one time 24 | do 25 | { 26 | if (TryLock()) 27 | return true; 28 | } while (spin-- > 0); 29 | 30 | // Failed to acquire spin-lock 31 | return false; 32 | } 33 | 34 | inline bool SpinLock::TryLockFor(const Timespan& timespan) noexcept 35 | { 36 | // Calculate a finish timestamp 37 | Timestamp finish = NanoTimestamp() + timespan; 38 | 39 | // Try to acquire spin-lock at least one time 40 | do 41 | { 42 | if (TryLock()) 43 | return true; 44 | } while (NanoTimestamp() < finish); 45 | 46 | // Failed to acquire spin-lock 47 | return false; 48 | } 49 | 50 | inline void SpinLock::Lock() noexcept 51 | { 52 | while (_lock.exchange(true, std::memory_order_acquire)); 53 | } 54 | 55 | inline void SpinLock::Unlock() noexcept 56 | { 57 | _lock.store(false, std::memory_order_release); 58 | } 59 | 60 | } // namespace CppCommon 61 | -------------------------------------------------------------------------------- /include/threads/thread.inl: -------------------------------------------------------------------------------- 1 | /*! 2 | \file thread.inl 3 | \brief Thread inline implementation 4 | \author Ivan Shynkarenka 5 | \date 27.01.2016 6 | \copyright MIT License 7 | */ 8 | 9 | namespace CppCommon { 10 | 11 | template 12 | inline TOutputStream& operator<<(TOutputStream& stream, ThreadPriority priority) 13 | { 14 | switch (priority) 15 | { 16 | case ThreadPriority::IDLE: 17 | stream << "IDLE"; 18 | break; 19 | case ThreadPriority::LOWEST: 20 | stream << "LOWEST"; 21 | break; 22 | case ThreadPriority::LOW: 23 | stream << "LOW"; 24 | break; 25 | case ThreadPriority::NORMAL: 26 | stream << "NORMAL"; 27 | break; 28 | case ThreadPriority::HIGH: 29 | stream << "HIGH"; 30 | break; 31 | case ThreadPriority::HIGHEST: 32 | stream << "HIGHEST"; 33 | break; 34 | case ThreadPriority::REALTIME: 35 | stream << "REALTIME"; 36 | break; 37 | default: 38 | stream << ""; 39 | break; 40 | } 41 | return stream; 42 | } 43 | 44 | template 45 | inline std::thread Thread::Start(Fn&& fn, Args&&... args) 46 | { 47 | return std::thread([fn = fn, args...]() 48 | { 49 | // Setup exception handler for the new thread 50 | ExceptionsHandler::SetupThread(); 51 | 52 | // Call the base thread function 53 | fn(std::move(args)...); 54 | }); 55 | } 56 | 57 | } // namespace CppCommon 58 | -------------------------------------------------------------------------------- /include/time/timespan.inl: -------------------------------------------------------------------------------- 1 | /*! 2 | \file timespan.inl 3 | \brief Timespan inline implementation 4 | \author Ivan Shynkarenka 5 | \date 11.07.2016 6 | \copyright MIT License 7 | */ 8 | 9 | namespace CppCommon { 10 | 11 | inline void Timespan::swap(Timespan& timespan) noexcept 12 | { 13 | using std::swap; 14 | swap(_duration, timespan._duration); 15 | } 16 | 17 | inline void swap(Timespan& timespan1, Timespan& timespan2) noexcept 18 | { 19 | timespan1.swap(timespan2); 20 | } 21 | 22 | } // namespace CppCommon 23 | 24 | //! \cond DOXYGEN_SKIP 25 | template <> 26 | struct std::hash 27 | { 28 | typedef CppCommon::Timespan argument_type; 29 | typedef size_t result_type; 30 | 31 | result_type operator() (const argument_type& value) const 32 | { 33 | result_type result = 17; 34 | result = result * 31 + std::hash()(value.total()); 35 | return result; 36 | } 37 | }; 38 | //! \endcond 39 | -------------------------------------------------------------------------------- /include/time/timestamp.inl: -------------------------------------------------------------------------------- 1 | /*! 2 | \file timestamp.inl 3 | \brief Timestamp inline implementation 4 | \author Ivan Shynkarenka 5 | \date 26.01.2016 6 | \copyright MIT License 7 | */ 8 | 9 | namespace CppCommon { 10 | 11 | inline void Timestamp::swap(Timestamp& timestamp) noexcept 12 | { 13 | using std::swap; 14 | swap(_timestamp, timestamp._timestamp); 15 | } 16 | 17 | inline void swap(Timestamp& timestamp1, Timestamp& timestamp2) noexcept 18 | { 19 | timestamp1.swap(timestamp2); 20 | } 21 | 22 | } // namespace CppCommon 23 | 24 | //! \cond DOXYGEN_SKIP 25 | template <> 26 | struct std::hash 27 | { 28 | typedef CppCommon::Timestamp argument_type; 29 | typedef size_t result_type; 30 | 31 | result_type operator() (const argument_type& value) const 32 | { 33 | result_type result = 17; 34 | result = result * 31 + std::hash()(value.total()); 35 | return result; 36 | } 37 | }; 38 | //! \endcond 39 | -------------------------------------------------------------------------------- /include/time/timezone.inl: -------------------------------------------------------------------------------- 1 | /*! 2 | \file timezone.inl 3 | \brief Timezone inline implementation 4 | \author Ivan Shynkarenka 5 | \date 18.07.2016 6 | \copyright MIT License 7 | */ 8 | 9 | namespace CppCommon { 10 | 11 | inline void Timezone::swap(Timezone& timezone) noexcept 12 | { 13 | using std::swap; 14 | swap(_name, timezone._name); 15 | swap(_offset, timezone._offset); 16 | swap(_dstoffset, timezone._dstoffset); 17 | } 18 | 19 | inline void swap(Timezone& timezone1, Timezone& timezone2) noexcept 20 | { 21 | timezone1.swap(timezone2); 22 | } 23 | 24 | } // namespace CppCommon 25 | 26 | //! \cond DOXYGEN_SKIP 27 | template <> 28 | struct std::hash 29 | { 30 | typedef CppCommon::Timezone argument_type; 31 | typedef size_t result_type; 32 | 33 | result_type operator() (const argument_type& value) const 34 | { 35 | result_type result = 17; 36 | result = result * 31 + std::hash()(value.name()); 37 | result = result * 31 + std::hash()(value.offset()); 38 | result = result * 31 + std::hash()(value.daylight()); 39 | return result; 40 | } 41 | }; 42 | //! \endcond 43 | -------------------------------------------------------------------------------- /include/utility/countof.h: -------------------------------------------------------------------------------- 1 | /*! 2 | \file countof.h 3 | \brief Static array countof definition 4 | \author Ivan Shynkarenka 5 | \date 31.08.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #ifndef CPPCOMMON_UTILITY_COUNTOF_H 10 | #define CPPCOMMON_UTILITY_COUNTOF_H 11 | 12 | namespace CppCommon { 13 | 14 | //! Count of elements in static array 15 | template 16 | constexpr size_t countof(const T (&)[N]) noexcept { return N; } 17 | 18 | //! Count of elements in any other STL container 19 | template 20 | size_t countof(const T& container) noexcept { return container.size(); } 21 | 22 | } // namespace CppCommon 23 | 24 | #endif // CPPCOMMON_UTILITY_COUNTOF_H 25 | -------------------------------------------------------------------------------- /include/utility/static_constructor.inl: -------------------------------------------------------------------------------- 1 | /*! 2 | \file static_constructor.inl 3 | \brief Static constructor pattern inline implementation 4 | \author Ivan Shynkarenka 5 | \date 31.08.2016 6 | \copyright MIT License 7 | */ 8 | 9 | namespace CppCommon { 10 | 11 | template 12 | typename StaticConstructor::constructor StaticConstructor::instance; 13 | 14 | } // namespace CppCommon 15 | -------------------------------------------------------------------------------- /include/utility/validate_aligned_storage.h: -------------------------------------------------------------------------------- 1 | /*! 2 | \file validate_aligned_storage.h 3 | \brief Aligned storage validator definition 4 | \author Tarcisio Genaro Rodrigues 5 | \date 29.10.2020 6 | \copyright MIT License 7 | */ 8 | 9 | #ifndef CPPCOMMON_UTILITY_VALIDATE_ALIGNED_STORAGE_H 10 | #define CPPCOMMON_UTILITY_VALIDATE_ALIGNED_STORAGE_H 11 | 12 | namespace CppCommon { 13 | 14 | //! Aligned storage validator 15 | template 16 | class ValidateAlignedStorage; 17 | 18 | //! \cond DOXYGEN_SKIP 19 | //! Aligned storage validator (specialization) 20 | template 21 | class ValidateAlignedStorage= ImplSize) && ((StorageAlign % ImplAlign) == 0)>::type> {}; 22 | //! \endcond 23 | 24 | } // namespace CppCommon 25 | 26 | #endif // CPPCOMMON_UTILITY_VALIDATE_ALIGNED_STORAGE_H 27 | -------------------------------------------------------------------------------- /modules/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include("Catch2.cmake") 2 | include("CppBenchmark.cmake") 3 | include("fmt.cmake") 4 | include("vld.cmake") 5 | -------------------------------------------------------------------------------- /modules/Catch2.cmake: -------------------------------------------------------------------------------- 1 | if(NOT TARGET Catch2) 2 | 3 | # Module library 4 | file(GLOB SOURCE_FILES "Catch2/extras/catch_amalgamated.cpp") 5 | add_library(Catch2 ${SOURCE_FILES}) 6 | target_include_directories(Catch2 PUBLIC "Catch2/extras") 7 | 8 | # Module folder 9 | set_target_properties(Catch2 PROPERTIES FOLDER "modules/Catch2") 10 | 11 | endif() 12 | -------------------------------------------------------------------------------- /modules/CppBenchmark.cmake: -------------------------------------------------------------------------------- 1 | if(NOT TARGET cppbenchmark) 2 | 3 | # Module flag 4 | set(CPPBENCHMARK_MODULE Y) 5 | 6 | # Module subdirectory 7 | add_subdirectory("CppBenchmark") 8 | 9 | # Module folder 10 | set_target_properties(cppbenchmark PROPERTIES FOLDER "modules/CppBenchmark") 11 | 12 | endif() 13 | -------------------------------------------------------------------------------- /modules/fmt.cmake: -------------------------------------------------------------------------------- 1 | if(NOT TARGET fmt) 2 | 3 | # Module library 4 | file(GLOB SOURCE_FILES "fmt/src/*.cc") 5 | list(FILTER SOURCE_FILES EXCLUDE REGEX ".*/fmt.cc") 6 | add_library(fmt ${SOURCE_FILES}) 7 | if(MSVC) 8 | # C4702: unreachable code 9 | set_target_properties(fmt PROPERTIES COMPILE_FLAGS "${PEDANTIC_COMPILE_FLAGS} /wd4702") 10 | else() 11 | set_target_properties(fmt PROPERTIES COMPILE_FLAGS "${PEDANTIC_COMPILE_FLAGS} -Wno-shadow") 12 | endif() 13 | target_include_directories(fmt PUBLIC "fmt/include") 14 | target_link_libraries(fmt) 15 | 16 | # Module folder 17 | set_target_properties(fmt PROPERTIES FOLDER "modules/fmt") 18 | 19 | endif() 20 | -------------------------------------------------------------------------------- /modules/vld.cmake: -------------------------------------------------------------------------------- 1 | if(WIN32 AND NOT TARGET vld) 2 | 3 | # Try to find VLD library and include path. 4 | # Once done this will define 5 | # 6 | # VLD_FOUND 7 | # VLD_INCLUDE_DIR 8 | # VLD_LIBRARIES 9 | 10 | find_path(VLD_INCLUDE_DIR vld.h HINTS vld/bin) 11 | find_library(VLD_LIBRARY vld.lib HINTS vld/bin) 12 | 13 | # Handle the REQUIRED argument and set VLD_FOUND 14 | include(FindPackageHandleStandardArgs) 15 | find_package_handle_standard_args(VLD DEFAULT_MSG VLD_LIBRARY VLD_INCLUDE_DIR) 16 | 17 | mark_as_advanced(VLD_INCLUDE_DIR) 18 | mark_as_advanced(VLD_LIBRARY) 19 | 20 | if(VLD_FOUND) 21 | add_definitions(-DVLD_SUPPORT) 22 | set(VLD_LIBRARIES ${VLD_LIBRARY}) 23 | set(vld ${VLD_INCLUDE_DIR} PARENT_SCOPE) 24 | endif() 25 | 26 | endif() 27 | -------------------------------------------------------------------------------- /performance/common_function.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 18.08.2017 3 | // 4 | 5 | #include "benchmark/cppbenchmark.h" 6 | 7 | #include "common/function.h" 8 | 9 | using namespace CppCommon; 10 | 11 | class Class 12 | { 13 | public: 14 | void test(int64_t data) { _data = data; } 15 | 16 | private: 17 | volatile int64_t _data; 18 | }; 19 | 20 | BENCHMARK("std::function: create & invoke") 21 | { 22 | static Class instance; 23 | 24 | // Create the function 25 | std::function function = std::bind(&Class::test, &instance, std::placeholders::_1); 26 | 27 | // Call the function 28 | function(context.metrics().total_operations()); 29 | } 30 | 31 | BENCHMARK("std::function: invoke") 32 | { 33 | static Class instance; 34 | static std::function function = std::bind(&Class::test, &instance, std::placeholders::_1); 35 | 36 | // Call the function 37 | function(context.metrics().total_operations()); 38 | } 39 | 40 | BENCHMARK("CppCommon::Function: create & invoke") 41 | { 42 | static Class instance; 43 | 44 | // Create the function 45 | CppCommon::Function function = std::bind(&Class::test, &instance, std::placeholders::_1); 46 | 47 | // Call the function 48 | function(context.metrics().total_operations()); 49 | } 50 | 51 | BENCHMARK("CppCommon::Function: invoke") 52 | { 53 | static Class instance; 54 | static CppCommon::Function function = std::bind(&Class::test, &instance, std::placeholders::_1); 55 | 56 | // Call the function 57 | function(context.metrics().total_operations()); 58 | } 59 | 60 | BENCHMARK_MAIN() 61 | -------------------------------------------------------------------------------- /performance/string_format.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 19.09.2016 3 | // 4 | 5 | #include "benchmark/cppbenchmark.h" 6 | 7 | #include "string/format.h" 8 | 9 | using namespace CppCommon; 10 | 11 | BENCHMARK("format(int)") 12 | { 13 | context.metrics().AddBytes(CppCommon::format("test {} test", context.metrics().total_operations()).size()); 14 | } 15 | 16 | BENCHMARK("format(double)") 17 | { 18 | context.metrics().AddBytes(CppCommon::format("test {} test", context.metrics().total_operations() / 1000.0).size()); 19 | } 20 | 21 | BENCHMARK("format(string)") 22 | { 23 | context.metrics().AddBytes(CppCommon::format("test {} test", context.name()).size()); 24 | } 25 | 26 | BENCHMARK("format(int, double, string)") 27 | { 28 | context.metrics().AddBytes(CppCommon::format("test {}.{}.{} test", context.metrics().total_operations(), context.metrics().total_operations() / 1000.0, context.name()).size()); 29 | } 30 | 31 | BENCHMARK_MAIN() 32 | -------------------------------------------------------------------------------- /performance/system_stack_trace.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 15.02.2016 3 | // 4 | 5 | #include "benchmark/cppbenchmark.h" 6 | 7 | #include "system/stack_trace.h" 8 | 9 | using namespace CppCommon; 10 | 11 | const uint64_t operations = 1000000; 12 | 13 | BENCHMARK("StackTrace") 14 | { 15 | uint64_t crc = 0; 16 | 17 | for (uint64_t i = 0; i < operations; ++i) 18 | crc += StackTrace().frames().size(); 19 | 20 | // Update benchmark metrics 21 | context.metrics().AddOperations(operations - 1); 22 | context.metrics().SetCustom("CRC", crc); 23 | } 24 | 25 | BENCHMARK_MAIN() 26 | -------------------------------------------------------------------------------- /performance/system_uuid.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 19.08.2016 3 | // 4 | 5 | #include "benchmark/cppbenchmark.h" 6 | 7 | #include "system/uuid.h" 8 | 9 | using namespace CppCommon; 10 | 11 | BENCHMARK("UUID::Nil()") 12 | { 13 | UUID::Nil(); 14 | } 15 | 16 | BENCHMARK("UUID::Sequential()") 17 | { 18 | UUID::Sequential(); 19 | } 20 | 21 | BENCHMARK("UUID::Random()") 22 | { 23 | UUID::Random(); 24 | } 25 | 26 | BENCHMARK_MAIN() 27 | -------------------------------------------------------------------------------- /performance/threads_critical_section.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 28.01.2016 3 | // 4 | 5 | #include "benchmark/cppbenchmark.h" 6 | 7 | #include "threads/critical_section.h" 8 | 9 | #include 10 | #include 11 | 12 | using namespace CppCommon; 13 | 14 | const uint64_t items_to_produce = 10000000; 15 | const int producers_from = 1; 16 | const int producers_to = 32; 17 | const auto settings = CppBenchmark::Settings().ParamRange(producers_from, producers_to, [](int from, int to, int& result) { int r = result; result *= 2; return r; }); 18 | 19 | void produce(CppBenchmark::Context& context) 20 | { 21 | const int producers_count = context.x(); 22 | uint64_t crc = 0; 23 | 24 | // Create critical section synchronization primitive 25 | CriticalSection lock; 26 | 27 | // Start producer threads 28 | std::vector producers; 29 | for (int producer = 0; producer < producers_count; ++producer) 30 | { 31 | producers.emplace_back([&lock, &crc, producer, producers_count]() 32 | { 33 | uint64_t items = (items_to_produce / producers_count); 34 | for (uint64_t i = 0; i < items; ++i) 35 | { 36 | Locker locker(lock); 37 | crc += (producer * items) + i; 38 | } 39 | }); 40 | } 41 | 42 | // Wait for all producers threads 43 | for (auto& producer : producers) 44 | producer.join(); 45 | 46 | // Update benchmark metrics 47 | context.metrics().AddOperations(items_to_produce - 1); 48 | context.metrics().SetCustom("CRC", crc); 49 | } 50 | 51 | BENCHMARK("CriticalSection", settings) 52 | { 53 | produce(context); 54 | } 55 | 56 | BENCHMARK_MAIN() 57 | -------------------------------------------------------------------------------- /performance/threads_mutex.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 04.04.2016 3 | // 4 | 5 | #include "benchmark/cppbenchmark.h" 6 | 7 | #include "threads/mutex.h" 8 | 9 | #include 10 | #include 11 | 12 | using namespace CppCommon; 13 | 14 | const uint64_t items_to_produce = 1000000; 15 | const int producers_from = 1; 16 | const int producers_to = 32; 17 | const auto settings = CppBenchmark::Settings().ParamRange(producers_from, producers_to, [](int from, int to, int& result) { int r = result; result *= 2; return r; }); 18 | 19 | void produce(CppBenchmark::Context& context) 20 | { 21 | const int producers_count = context.x(); 22 | uint64_t crc = 0; 23 | 24 | // Create mutex synchronization primitive 25 | Mutex lock; 26 | 27 | // Start producer threads 28 | std::vector producers; 29 | for (int producer = 0; producer < producers_count; ++producer) 30 | { 31 | producers.emplace_back([&lock, &crc, producer, producers_count]() 32 | { 33 | uint64_t items = (items_to_produce / producers_count); 34 | for (uint64_t i = 0; i < items; ++i) 35 | { 36 | Locker locker(lock); 37 | crc += (producer * items) + i; 38 | } 39 | }); 40 | } 41 | 42 | // Wait for all producers threads 43 | for (auto& producer : producers) 44 | producer.join(); 45 | 46 | // Update benchmark metrics 47 | context.metrics().AddOperations(items_to_produce - 1); 48 | context.metrics().SetCustom("CRC", crc); 49 | } 50 | 51 | BENCHMARK("Mutex", settings) 52 | { 53 | produce(context); 54 | } 55 | 56 | BENCHMARK_MAIN() 57 | -------------------------------------------------------------------------------- /performance/threads_named_mutex.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 25.05.2016 3 | // 4 | 5 | #include "benchmark/cppbenchmark.h" 6 | 7 | #include "threads/named_mutex.h" 8 | 9 | #include 10 | #include 11 | 12 | using namespace CppCommon; 13 | 14 | const uint64_t items_to_produce = 1000000; 15 | const int producers_from = 1; 16 | const int producers_to = 32; 17 | const auto settings = CppBenchmark::Settings().ParamRange(producers_from, producers_to, [](int from, int to, int& result) { int r = result; result *= 2; return r; }); 18 | 19 | void produce(CppBenchmark::Context& context) 20 | { 21 | const int producers_count = context.x(); 22 | uint64_t crc = 0; 23 | 24 | // Create named mutex master 25 | NamedMutex lock_master("named_mutex_perf"); 26 | 27 | // Start producer threads 28 | std::vector producers; 29 | for (int producer = 0; producer < producers_count; ++producer) 30 | { 31 | producers.emplace_back([&crc, producer, producers_count]() 32 | { 33 | // Create named mutex slave 34 | NamedMutex lock_slave("named_mutex_perf"); 35 | 36 | uint64_t items = (items_to_produce / producers_count); 37 | for (uint64_t i = 0; i < items; ++i) 38 | { 39 | Locker locker(lock_slave); 40 | crc += (producer * items) + i; 41 | } 42 | }); 43 | } 44 | 45 | // Wait for all producers threads 46 | for (auto& producer : producers) 47 | producer.join(); 48 | 49 | // Update benchmark metrics 50 | context.metrics().AddOperations(items_to_produce - 1); 51 | context.metrics().SetCustom("CRC", crc); 52 | } 53 | 54 | BENCHMARK("NamedMutex", settings) 55 | { 56 | produce(context); 57 | } 58 | 59 | BENCHMARK_MAIN() 60 | -------------------------------------------------------------------------------- /performance/threads_spin_lock.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 28.01.2016 3 | // 4 | 5 | #include "benchmark/cppbenchmark.h" 6 | 7 | #include "threads/spin_lock.h" 8 | 9 | #include 10 | #include 11 | 12 | using namespace CppCommon; 13 | 14 | const uint64_t items_to_produce = 10000000; 15 | const int producers_from = 1; 16 | const int producers_to = 32; 17 | const auto settings = CppBenchmark::Settings().ParamRange(producers_from, producers_to, [](int from, int to, int& result) { int r = result; result *= 2; return r; }); 18 | 19 | void produce(CppBenchmark::Context& context) 20 | { 21 | const int producers_count = context.x(); 22 | uint64_t crc = 0; 23 | 24 | // Create spin-lock synchronization primitive 25 | SpinLock lock; 26 | 27 | // Start producer threads 28 | std::vector producers; 29 | for (int producer = 0; producer < producers_count; ++producer) 30 | { 31 | producers.emplace_back([&lock, &crc, producer, producers_count]() 32 | { 33 | uint64_t items = (items_to_produce / producers_count); 34 | for (uint64_t i = 0; i < items; ++i) 35 | { 36 | Locker locker(lock); 37 | crc += (producer * items) + i; 38 | } 39 | }); 40 | } 41 | 42 | // Wait for all producers threads 43 | for (auto& producer : producers) 44 | producer.join(); 45 | 46 | // Update benchmark metrics 47 | context.metrics().AddOperations(items_to_produce - 1); 48 | context.metrics().SetCustom("CRC", crc); 49 | } 50 | 51 | BENCHMARK("SpinLock", settings) 52 | { 53 | produce(context); 54 | } 55 | 56 | BENCHMARK_MAIN() 57 | -------------------------------------------------------------------------------- /performance/time_time.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 13.07.2016 3 | // 4 | 5 | #include "benchmark/cppbenchmark.h" 6 | 7 | #include "time/time.h" 8 | 9 | using namespace CppCommon; 10 | 11 | const uint64_t operations = 10000000; 12 | 13 | BENCHMARK("UtcTime()") 14 | { 15 | uint64_t crc = 0; 16 | 17 | for (uint64_t i = 0; i < operations; ++i) 18 | crc += UtcTime().second(); 19 | 20 | // Update benchmark metrics 21 | context.metrics().AddOperations(operations - 1); 22 | context.metrics().SetCustom("CRC", crc); 23 | } 24 | 25 | BENCHMARK("LocalTime()") 26 | { 27 | uint64_t crc = 0; 28 | 29 | for (uint64_t i = 0; i < operations; ++i) 30 | crc += LocalTime().second(); 31 | 32 | // Update benchmark metrics 33 | context.metrics().AddOperations(operations - 1); 34 | context.metrics().SetCustom("CRC", crc); 35 | } 36 | 37 | BENCHMARK("Time::utcstamp()") 38 | { 39 | uint64_t crc = 0; 40 | 41 | UtcTime time = UtcTime(); 42 | for (uint64_t i = 0; i < operations; ++i) 43 | crc += time.utcstamp().total(); 44 | 45 | // Update benchmark metrics 46 | context.metrics().AddOperations(operations - 1); 47 | context.metrics().SetCustom("CRC", crc); 48 | } 49 | 50 | BENCHMARK("Time::localstamp()") 51 | { 52 | uint64_t crc = 0; 53 | 54 | UtcTime time = UtcTime(); 55 | for (uint64_t i = 0; i < operations; ++i) 56 | crc += time.localstamp().total(); 57 | 58 | // Update benchmark metrics 59 | context.metrics().AddOperations(operations - 1); 60 | context.metrics().SetCustom("CRC", crc); 61 | } 62 | 63 | BENCHMARK_MAIN() 64 | -------------------------------------------------------------------------------- /performance/time_timezone.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 18.07.2016 3 | // 4 | 5 | #include "benchmark/cppbenchmark.h" 6 | 7 | #include "time/timezone.h" 8 | 9 | using namespace CppCommon; 10 | 11 | const uint64_t operations = 10000000; 12 | 13 | BENCHMARK("Timezone::utc()") 14 | { 15 | uint64_t crc = 0; 16 | 17 | for (uint64_t i = 0; i < operations; ++i) 18 | crc += Timezone::utc().total().total(); 19 | 20 | // Update benchmark metrics 21 | context.metrics().AddOperations(operations - 1); 22 | context.metrics().SetCustom("CRC", crc); 23 | } 24 | 25 | BENCHMARK("Timezone::local()") 26 | { 27 | uint64_t crc = 0; 28 | 29 | for (uint64_t i = 0; i < operations; ++i) 30 | crc += Timezone::local().total().total(); 31 | 32 | // Update benchmark metrics 33 | context.metrics().AddOperations(operations - 1); 34 | context.metrics().SetCustom("CRC", crc); 35 | } 36 | 37 | BENCHMARK_MAIN() 38 | -------------------------------------------------------------------------------- /plugins/function/function.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file function.cpp 3 | \brief Random function plugin 4 | \author Ivan Shynkarenka 5 | \date 07.06.2017 6 | \copyright MIT License 7 | */ 8 | 9 | #include "system/dll.h" 10 | 11 | #include 12 | 13 | API int PluginRandom() 14 | { 15 | return std::rand(); 16 | } 17 | -------------------------------------------------------------------------------- /plugins/interface/interface.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file interface.cpp 3 | \brief Random interface implementation 4 | \author Ivan Shynkarenka 5 | \date 08.06.2017 6 | \copyright MIT License 7 | */ 8 | 9 | #include "interface.h" 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | class Random : public IRandom 17 | { 18 | public: 19 | Random(); 20 | virtual ~Random(); 21 | int random() override; 22 | }; 23 | 24 | Random::Random() 25 | { 26 | std::cout << "Random()" << std::endl; 27 | std::srand((unsigned)std::time(nullptr)); 28 | } 29 | 30 | Random::~Random() 31 | { 32 | std::cout << "~Random()" << std::endl; 33 | } 34 | 35 | int Random::random() 36 | { 37 | return std::rand(); 38 | } 39 | 40 | bool PluginRandomCreate(IRandom** ppRandom) 41 | { 42 | if (ppRandom == nullptr) 43 | return false; 44 | 45 | *ppRandom = new Random(); 46 | 47 | return true; 48 | } 49 | 50 | bool PluginRandomRelease(IRandom* pRandom) 51 | { 52 | if (pRandom == nullptr) 53 | return false; 54 | 55 | delete pRandom; 56 | 57 | return true; 58 | } 59 | -------------------------------------------------------------------------------- /plugins/interface/interface.h: -------------------------------------------------------------------------------- 1 | /*! 2 | \file interface.h 3 | \brief Random interface definition 4 | \author Ivan Shynkarenka 5 | \date 08.06.2017 6 | \copyright MIT License 7 | */ 8 | 9 | #include "system/dll.h" 10 | 11 | #include 12 | 13 | class IRandom 14 | { 15 | public: 16 | virtual ~IRandom() = default; 17 | virtual int random() = 0; 18 | }; 19 | 20 | API bool PluginRandomCreate(IRandom** ppRandom); 21 | API bool PluginRandomRelease(IRandom* pRandom); 22 | -------------------------------------------------------------------------------- /source/algorithms/token_bucket.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file token_bucket.cpp 3 | \brief Token bucket rate limit algorithm implementation 4 | \author Ivan Shynkarenka 5 | \date 07.12.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "algorithms/token_bucket.h" 10 | 11 | #include "time/timestamp.h" 12 | 13 | namespace CppCommon { 14 | 15 | bool TokenBucket::Consume(uint64_t tokens) 16 | { 17 | uint64_t now = Timestamp::nano(); 18 | uint64_t delay = tokens * _time_per_token.load(std::memory_order_relaxed); 19 | uint64_t minTime = now - _time_per_burst.load(std::memory_order_relaxed); 20 | uint64_t oldTime = _time.load(std::memory_order_relaxed); 21 | uint64_t newTime = oldTime; 22 | 23 | // Previous consume performed long time ago... Shift the new time to the start of a new burst. 24 | if (minTime > oldTime) 25 | newTime = minTime; 26 | 27 | // Lock-free token consume loop 28 | for (;;) 29 | { 30 | // Consume tokens 31 | newTime += delay; 32 | 33 | // No more tokens left in the bucket 34 | if (newTime > now) 35 | return false; 36 | 37 | // Try to update the current time atomically 38 | if (_time.compare_exchange_weak(oldTime, newTime, std::memory_order_relaxed, std::memory_order_relaxed)) 39 | return true; 40 | 41 | // Failed... Then retry consume tokens with a new time value 42 | newTime = oldTime; 43 | } 44 | } 45 | 46 | } // namespace CppCommon 47 | -------------------------------------------------------------------------------- /source/common/reader.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file reader.cpp 3 | \brief Reader interface implementation 4 | \author Ivan Shynkarenka 5 | \date 07.12.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "common/reader.h" 10 | 11 | #include "utility/countof.h" 12 | 13 | namespace CppCommon { 14 | 15 | std::vector Reader::ReadAllBytes() 16 | { 17 | const size_t PAGE = 8192; 18 | 19 | uint8_t buffer[PAGE]; 20 | std::vector result; 21 | size_t size = 0; 22 | 23 | do 24 | { 25 | size = Read(buffer, countof(buffer)); 26 | result.insert(result.end(), buffer, buffer + size); 27 | } while (size == countof(buffer)); 28 | 29 | return result; 30 | } 31 | 32 | std::string Reader::ReadAllText() 33 | { 34 | std::vector bytes = ReadAllBytes(); 35 | return std::string(bytes.begin(), bytes.end()); 36 | } 37 | 38 | std::vector Reader::ReadAllLines() 39 | { 40 | std::string temp; 41 | std::vector result; 42 | std::vector bytes = ReadAllBytes(); 43 | 44 | for (auto ch : bytes) 45 | { 46 | if ((ch == '\r') || (ch == '\n')) 47 | { 48 | if (!temp.empty()) 49 | { 50 | result.push_back(temp); 51 | temp.clear(); 52 | } 53 | } 54 | else 55 | temp += ch; 56 | } 57 | 58 | return result; 59 | } 60 | 61 | } // namespace CppCommon 62 | -------------------------------------------------------------------------------- /source/common/writer.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file writer.cpp 3 | \brief Writer interface implementation 4 | \author Ivan Shynkarenka 5 | \date 07.12.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "common/writer.h" 10 | 11 | #include "system/environment.h" 12 | 13 | namespace CppCommon { 14 | 15 | size_t Writer::Write(const std::string& text) 16 | { 17 | return Write(text.data(), text.size()); 18 | } 19 | 20 | size_t Writer::Write(const std::vector& lines) 21 | { 22 | static std::string endline = Environment::EndLine(); 23 | 24 | size_t result = 0; 25 | for (const auto& line : lines) 26 | { 27 | if (Write(line.data(), line.size()) != line.size()) 28 | break; 29 | if (Write(endline.data(), endline.size()) != endline.size()) 30 | break; 31 | ++result; 32 | } 33 | return result; 34 | } 35 | 36 | } // namespace CppCommon 37 | -------------------------------------------------------------------------------- /source/errors/exceptions.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file errors/exceptions.cpp 3 | \brief Exceptions implementation 4 | \author Ivan Shynkarenka 5 | \date 09.02.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "errors/exceptions.h" 10 | 11 | #include 12 | 13 | namespace CppCommon { 14 | 15 | const char* Exception::what() const noexcept 16 | { 17 | try 18 | { 19 | if (_cache.empty()) 20 | string(); 21 | return _cache.c_str(); 22 | } 23 | catch (...) 24 | { 25 | return "Out of memory!"; 26 | } 27 | } 28 | 29 | std::string Exception::string() const 30 | { 31 | if (_cache.empty()) 32 | { 33 | std::stringstream stream; 34 | stream << "Exception: " << _message << std::endl; 35 | std::string location = _location.string(); 36 | if (!location.empty()) 37 | stream << "Source location: " << location << std::endl; 38 | _cache = stream.str(); 39 | } 40 | return _cache; 41 | } 42 | 43 | std::string SystemException::string() const 44 | { 45 | if (_cache.empty()) 46 | { 47 | std::stringstream stream; 48 | stream << "System exception: " << _message << std::endl; 49 | stream << "System error: " << _system_error << std::endl; 50 | stream << "System message: " << _system_message << std::endl; 51 | std::string location = _location.string(); 52 | if (!location.empty()) 53 | stream << "Source location: " << location << std::endl; 54 | _cache = stream.str(); 55 | } 56 | return _cache; 57 | } 58 | 59 | } // namespace CppCommon 60 | -------------------------------------------------------------------------------- /source/errors/fatal.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file fatal.cpp 3 | \brief Fatal abort execution implementation 4 | \author Ivan Shynkarenka 5 | \date 04.04.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "errors/fatal.h" 10 | 11 | #include 12 | #include 13 | 14 | namespace CppCommon { 15 | 16 | void fatal(const SourceLocation& location, const StackTrace& trace, const std::string& message, int error) noexcept 17 | { 18 | std::cerr << "Fatal error: " << message << std::endl; 19 | std::cerr << "System error: " << error << std::endl; 20 | std::cerr << "System message: " << SystemError::Description(error) << std::endl; 21 | std::cerr << "Source location: " << location.string() << std::endl; 22 | std::cerr << "Stack trace: " << std::endl << trace.string() << std::endl; 23 | std::abort(); 24 | } 25 | 26 | void fatal(const SourceLocation& location, const StackTrace& trace, const std::exception& fatal) noexcept 27 | { 28 | std::cerr << fatal.what() << std::endl; 29 | std::abort(); 30 | } 31 | 32 | } // namespace CppCommon 33 | -------------------------------------------------------------------------------- /source/filesystem/exceptions.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file filesystem/exceptions.cpp 3 | \brief File system exceptions implementation 4 | \author Ivan Shynkarenka 5 | \date 24.08.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "filesystem/exceptions.h" 10 | 11 | namespace CppCommon { 12 | 13 | std::string FileSystemException::string() const 14 | { 15 | if (_cache.empty()) 16 | { 17 | std::stringstream stream; 18 | stream << "File system exception: " << _message << std::endl; 19 | if (!_path.empty()) 20 | stream << "File system path: " << _path << std::endl; 21 | if (!_src.empty()) 22 | stream << "File system source path: " << _src << std::endl; 23 | if (!_dst.empty()) 24 | stream << "File system destination path: " << _dst << std::endl; 25 | stream << "System error: " << _system_error << std::endl; 26 | stream << "System message: " << _system_message << std::endl; 27 | std::string location = _location.string(); 28 | if (!location.empty()) 29 | stream << "Source location: " << location << std::endl; 30 | _cache = stream.str(); 31 | } 32 | return _cache; 33 | } 34 | 35 | } // namespace CppCommon 36 | -------------------------------------------------------------------------------- /tests/test.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 15.01.2016 3 | // 4 | 5 | #include "test.h" 6 | -------------------------------------------------------------------------------- /tests/test.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 15.01.2016 3 | // 4 | 5 | #include 6 | -------------------------------------------------------------------------------- /tests/test_algorithms_token_bucket.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 16.08.2017 3 | // 4 | 5 | #include "test.h" 6 | 7 | #include "algorithms/token_bucket.h" 8 | #include "threads/thread.h" 9 | #include "time/timestamp.h" 10 | 11 | using namespace CppCommon; 12 | 13 | TEST_CASE("Token bucket", "[CppCommon][Algorithms]") 14 | { 15 | TokenBucket tb(1, 10); 16 | 17 | // Consume all tokens in the bucket 18 | REQUIRE(tb.Consume(10)); 19 | 20 | // Failed to consume tokens at the current second 21 | REQUIRE(!tb.Consume()); 22 | 23 | // Sleep for one second... 24 | Thread::SleepFor(Timespan::seconds(1)); 25 | Thread::SleepFor(Timespan::milliseconds(1)); 26 | 27 | REQUIRE(tb.Consume()); 28 | REQUIRE(!tb.Consume()); 29 | REQUIRE(!tb.Consume(1)); 30 | REQUIRE(!tb.Consume(10)); 31 | 32 | // Sleep for one second... 33 | Thread::SleepFor(Timespan::seconds(1)); 34 | Thread::SleepFor(Timespan::milliseconds(1)); 35 | 36 | REQUIRE(tb.Consume()); 37 | REQUIRE(!tb.Consume()); 38 | REQUIRE(!tb.Consume(1)); 39 | REQUIRE(!tb.Consume(10)); 40 | } 41 | -------------------------------------------------------------------------------- /tests/test_common_flags.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 25.08.2016 3 | // 4 | 5 | #include "test.h" 6 | 7 | #include "common/flags.h" 8 | 9 | using namespace CppCommon; 10 | 11 | enum class MyFlags 12 | { 13 | None = 0x0, 14 | One = 0x1, 15 | Two = 0x2, 16 | Three = 0x4, 17 | Four = 0x8 18 | }; 19 | 20 | ENUM_FLAGS(MyFlags) 21 | 22 | TEST_CASE("Enum-based flags", "[CppCommon][Common]") 23 | { 24 | Flags init; 25 | REQUIRE(init.value() == MyFlags::None); 26 | REQUIRE(init.underlying() == 0); 27 | REQUIRE(init.bitset().to_ulong() == 0); 28 | 29 | Flags single = MyFlags::Two; 30 | REQUIRE(single.value() == MyFlags::Two); 31 | REQUIRE(single.underlying() == 2u); 32 | REQUIRE(single.bitset().to_ulong() == 2u); 33 | 34 | Flags combination = MyFlags::One | MyFlags::Two | MyFlags::Three; 35 | REQUIRE((combination & MyFlags::One)); 36 | REQUIRE((combination & MyFlags::Two)); 37 | REQUIRE((combination & MyFlags::Three)); 38 | REQUIRE(!(combination & MyFlags::Four)); 39 | REQUIRE(combination.underlying() == 7u); 40 | REQUIRE(combination.bitset().to_ulong() == 7u); 41 | 42 | combination = ~combination; 43 | REQUIRE(!(combination & MyFlags::One)); 44 | REQUIRE(!(combination & MyFlags::Two)); 45 | REQUIRE(!(combination & MyFlags::Three)); 46 | REQUIRE((combination & MyFlags::Four)); 47 | REQUIRE(combination.underlying() == ~7u); 48 | REQUIRE(combination.bitset().to_ulong() == ~7u); 49 | } 50 | -------------------------------------------------------------------------------- /tests/test_common_function.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 18.08.2018 3 | // 4 | 5 | #include "test.h" 6 | 7 | #include "common/function.h" 8 | 9 | using namespace CppCommon; 10 | 11 | namespace { 12 | 13 | int test(int v) 14 | { 15 | return v + 100; 16 | } 17 | 18 | class Class 19 | { 20 | public: 21 | int operator()(int v) { return v + 200; } 22 | int test(int v) { return v + 300; } 23 | static int static_test(int v) { return v + 400; } 24 | }; 25 | 26 | } // namespace 27 | 28 | TEST_CASE("Function", "[CppCommon][Common]") 29 | { 30 | CppCommon::Function function; 31 | 32 | // Simple function call 33 | function = test; 34 | REQUIRE(function(11) == 111); 35 | 36 | Class instance; 37 | 38 | // Class operator() call 39 | function = instance; 40 | REQUIRE(function(22) == 222); 41 | 42 | // Class method call 43 | function = std::bind(&Class::test, &instance, std::placeholders::_1); 44 | REQUIRE(function(33) == 333); 45 | 46 | // Class static method call 47 | function = Class::static_test; 48 | REQUIRE(function(44) == 444); 49 | 50 | // Lambda function call 51 | auto lambda = [=](int v) { return v + 500; }; 52 | function = lambda; 53 | REQUIRE(function(55) == 555); 54 | } 55 | -------------------------------------------------------------------------------- /tests/test_errors_system_error.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 10.02.2016 3 | // 4 | 5 | #include "test.h" 6 | 7 | #include "errors/system_error.h" 8 | 9 | using namespace CppCommon; 10 | 11 | TEST_CASE("System error", "[CppCommon][Errors]") 12 | { 13 | SystemError::SetLast(123); 14 | REQUIRE(SystemError::GetLast() == 123); 15 | SystemError::ClearLast(); 16 | 17 | REQUIRE(SystemError::GetLast() == 0); 18 | 19 | REQUIRE(SystemError::Description().size() >= 0); 20 | REQUIRE(SystemError::Description(SystemError::GetLast()).size() >= 0); 21 | } 22 | -------------------------------------------------------------------------------- /tests/test_system_cpu.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 27.07.2016 3 | // 4 | 5 | #include "test.h" 6 | 7 | #include "system/cpu.h" 8 | 9 | using namespace CppCommon; 10 | 11 | TEST_CASE("CPU management", "[CppCommon][System]") 12 | { 13 | REQUIRE(!CPU::Architecture().empty()); 14 | REQUIRE(CPU::Affinity() > 0); 15 | REQUIRE(CPU::LogicalCores() > 0); 16 | REQUIRE(CPU::PhysicalCores() > 0); 17 | REQUIRE(CPU::TotalCores().first == CPU::LogicalCores()); 18 | REQUIRE(CPU::TotalCores().second == CPU::PhysicalCores()); 19 | REQUIRE(CPU::ClockSpeed() > 0); 20 | REQUIRE((CPU::HyperThreading() || !CPU::HyperThreading())); 21 | } 22 | -------------------------------------------------------------------------------- /tests/test_system_environment.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 27.07.2016 3 | // 4 | 5 | #include "test.h" 6 | 7 | #include "system/environment.h" 8 | 9 | using namespace CppCommon; 10 | 11 | TEST_CASE("Environment management", "[CppCommon][System]") 12 | { 13 | REQUIRE((Environment::Is32BitOS() || Environment::Is64BitOS())); 14 | REQUIRE((Environment::Is32BitProcess() || Environment::Is64BitProcess())); 15 | REQUIRE((Environment::IsDebug() || Environment::IsRelease())); 16 | REQUIRE((Environment::IsBigEndian() || Environment::IsLittleEndian())); 17 | REQUIRE(Environment::OSVersion().length() > 0); 18 | REQUIRE(Environment::EndLine().length() > 0); 19 | REQUIRE(Environment::UnixEndLine().length() > 0); 20 | REQUIRE(Environment::WindowsEndLine().length() > 0); 21 | } 22 | 23 | TEST_CASE("Environment variables", "[CppCommon][System]") 24 | { 25 | auto envars = Environment::envars(); 26 | REQUIRE(envars.size() > 0); 27 | for (const auto& envar : envars) 28 | REQUIRE(!envar.first.empty()); 29 | 30 | REQUIRE(Environment::GetEnvar("TestEnvar") == ""); 31 | Environment::SetEnvar("TestEnvar", "123"); 32 | REQUIRE(Environment::GetEnvar("TestEnvar") == "123"); 33 | Environment::ClearEnvar("TestEnvar"); 34 | REQUIRE(Environment::GetEnvar("TestEnvar") == ""); 35 | } 36 | -------------------------------------------------------------------------------- /tests/test_system_pipe.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 30.11.2016 3 | // 4 | 5 | #include "test.h" 6 | 7 | #include "system/pipe.h" 8 | 9 | #include 10 | 11 | using namespace CppCommon; 12 | 13 | TEST_CASE("Pipe", "[CppCommon][System]") 14 | { 15 | Pipe pipe; 16 | 17 | for (int i = 0; i < 1000; ++i) 18 | { 19 | int item = i; 20 | REQUIRE(pipe.Write(&item, sizeof(item)) == sizeof(item)); 21 | REQUIRE(pipe.Read(&item, sizeof(item)) == sizeof(item)); 22 | REQUIRE(item == i); 23 | } 24 | } 25 | 26 | TEST_CASE("Pipe threads", "[CppCommon][System]") 27 | { 28 | int items_to_produce = 10000; 29 | int crc = 0; 30 | 31 | Pipe pipe; 32 | 33 | // Calculate result value 34 | int result = 0; 35 | for (int i = 0; i < items_to_produce; ++i) 36 | result += i; 37 | 38 | // Start producer thread 39 | auto producer = std::thread([&pipe, items_to_produce]() 40 | { 41 | for (int i = 0; i < items_to_produce; ++i) 42 | { 43 | int item = i; 44 | if (pipe.Write(&item, sizeof(item)) != sizeof(item)) 45 | break; 46 | } 47 | }); 48 | 49 | // Consume items 50 | for (int i = 0; i < items_to_produce; ++i) 51 | { 52 | int item; 53 | if (pipe.Read(&item, sizeof(item)) != sizeof(item)) 54 | break; 55 | crc += item; 56 | } 57 | 58 | // Wait for producer thread 59 | producer.join(); 60 | 61 | // Check result 62 | REQUIRE(crc == result); 63 | } 64 | -------------------------------------------------------------------------------- /tests/test_system_process.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 01.12.2016 3 | // 4 | 5 | #include "test.h" 6 | 7 | #include "system/process.h" 8 | 9 | using namespace CppCommon; 10 | 11 | TEST_CASE("Process", "[CppCommon][System]") 12 | { 13 | REQUIRE(Process::CurrentProcessId() > 0); 14 | REQUIRE(Process::ParentProcessId() > 0); 15 | REQUIRE(Process::CurrentProcessId() != Process::ParentProcessId()); 16 | 17 | REQUIRE(Process::CurrentProcess().IsRunning()); 18 | REQUIRE(Process::ParentProcess().IsRunning()); 19 | } 20 | -------------------------------------------------------------------------------- /tests/test_system_shared_memory.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 19.04.2016 3 | // 4 | 5 | #include "test.h" 6 | 7 | #include "system/shared_memory.h" 8 | 9 | #include 10 | 11 | using namespace CppCommon; 12 | 13 | TEST_CASE("Shared memory manager", "[CppCommon][System]") 14 | { 15 | const char* name = "shared_memory_test"; 16 | const char* message = "shared message"; 17 | size_t size = 14; 18 | 19 | // Create new shared memory manager with the given name and size 20 | SharedMemory shared1(name, size); 21 | REQUIRE(shared1.owner()); 22 | REQUIRE(shared1.ptr() != nullptr); 23 | 24 | // Write into the shared memory buffer 25 | std::memcpy(shared1.ptr(), message, size); 26 | 27 | SharedMemory shared2(name, size); 28 | REQUIRE(!shared2.owner()); 29 | REQUIRE(shared2.ptr() != nullptr); 30 | 31 | // Read from the shared memory buffer 32 | REQUIRE(std::memcmp(shared1.ptr(), shared2.ptr(), size) == 0); 33 | } 34 | -------------------------------------------------------------------------------- /tests/test_system_shared_type.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 23.05.2016 3 | // 4 | 5 | #include "test.h" 6 | 7 | #include "system/shared_type.h" 8 | 9 | #include 10 | 11 | using namespace CppCommon; 12 | 13 | TEST_CASE("Shared memory type", "[CppCommon][System]") 14 | { 15 | std::string name = "shared_type_test"; 16 | 17 | // Create new shared memory type with the given name 18 | SharedType shared1(name); 19 | REQUIRE(shared1); 20 | REQUIRE(shared1.owner()); 21 | REQUIRE(shared1.ptr() != nullptr); 22 | 23 | // Assign a new value to the shared memory type 24 | *shared1 = 123; 25 | 26 | SharedType shared2(name); 27 | REQUIRE(shared2); 28 | REQUIRE(!shared2.owner()); 29 | REQUIRE(shared2.ptr() != nullptr); 30 | 31 | // Check the value of the shared memory type 32 | REQUIRE(shared1.ref() == *shared2); 33 | } 34 | -------------------------------------------------------------------------------- /tests/test_system_source_location.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 09.02.2016 3 | // 4 | 5 | #include "test.h" 6 | 7 | #include "system/source_location.h" 8 | 9 | using namespace CppCommon; 10 | 11 | TEST_CASE("Source location", "[CppCommon][System]") 12 | { 13 | auto location = __LOCATION__; 14 | 15 | REQUIRE(location.filename() != nullptr); 16 | REQUIRE(location.filename() == std::string(__FILE__)); 17 | REQUIRE(location.line() == 13); 18 | 19 | REQUIRE(__LOCATION__.string() == (std::string(__FILE__) + ':' + std::to_string(__LINE__))); 20 | } 21 | -------------------------------------------------------------------------------- /tests/test_system_uuid.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 19.08.2016 3 | // 4 | 5 | #include "test.h" 6 | 7 | #include "system/uuid.h" 8 | 9 | using namespace CppCommon; 10 | 11 | TEST_CASE("UUID common", "[CppCommon][System]") 12 | { 13 | REQUIRE(UUID().string() == "00000000-0000-0000-0000-000000000000"); 14 | REQUIRE("{01234567-89ab-cdef-FEDC-BA9876543210}"_uuid.string() == "01234567-89ab-cdef-fedc-ba9876543210"); 15 | REQUIRE(UUID("01234567-89ab-cdef-fedc-ba9876543210").string() == "01234567-89ab-cdef-fedc-ba9876543210"); 16 | REQUIRE(UUID(std::string("01234567-89ab-cdef-fedc-ba9876543210")).string() == "01234567-89ab-cdef-fedc-ba9876543210"); 17 | } 18 | 19 | void test_uuid(const UUID& uuid) 20 | { 21 | REQUIRE(uuid.data().size() == 16); 22 | 23 | std::string uuid_str = uuid.string(); 24 | REQUIRE(uuid_str.size() == 36); 25 | REQUIRE(uuid_str[8] == '-'); 26 | REQUIRE(uuid_str[13] == '-'); 27 | REQUIRE(uuid_str[18] == '-'); 28 | REQUIRE(uuid_str[23] == '-'); 29 | } 30 | 31 | TEST_CASE("UUID generate", "[CppCommon][System]") 32 | { 33 | test_uuid(UUID::Nil()); 34 | test_uuid(UUID::Sequential()); 35 | test_uuid(UUID::Random()); 36 | test_uuid(UUID::Secure()); 37 | } 38 | -------------------------------------------------------------------------------- /tests/test_threads_barrier.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 17.03.2016 3 | // 4 | 5 | #include "test.h" 6 | 7 | #include "threads/barrier.h" 8 | #include "threads/thread.h" 9 | 10 | #include 11 | #include 12 | 13 | using namespace CppCommon; 14 | 15 | TEST_CASE("Barrier single thread", "[CppCommon][Threads]") 16 | { 17 | Barrier barrier(1); 18 | 19 | // Test Wait() method 20 | REQUIRE(barrier.Wait()); 21 | } 22 | 23 | TEST_CASE("Barrier multiple threads", "[CppCommon][Threads]") 24 | { 25 | int concurrency = 8; 26 | std::atomic failed(false); 27 | std::atomic count(0); 28 | std::atomic last(0); 29 | 30 | Barrier barrier(concurrency); 31 | 32 | // Start some threads 33 | std::vector threads; 34 | for (int thread = 0; thread < concurrency; ++thread) 35 | { 36 | threads.emplace_back([&barrier, &count, &last, &failed, concurrency, thread]() 37 | { 38 | // Increment threads counter 39 | ++count; 40 | 41 | // Sleep for a while... 42 | Thread::Sleep(thread * 10); 43 | 44 | // Wait for all other threads at the barrier 45 | if (barrier.Wait()) 46 | ++last; 47 | 48 | // Check result in each thread 49 | if (count != concurrency) 50 | failed = true; 51 | }); 52 | } 53 | 54 | // Wait for all threads to complete 55 | for (auto& thread : threads) 56 | thread.join(); 57 | 58 | // Check results 59 | REQUIRE(count == concurrency); 60 | REQUIRE(last == 1); 61 | REQUIRE(!failed); 62 | } 63 | -------------------------------------------------------------------------------- /tests/test_threads_critical_section.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 27.01.2016 3 | // 4 | 5 | #include "test.h" 6 | 7 | #include "threads/critical_section.h" 8 | 9 | #include 10 | 11 | using namespace CppCommon; 12 | 13 | TEST_CASE("Critical section", "[CppCommon][Threads]") 14 | { 15 | CriticalSection lock; 16 | 17 | // Test TryLock() method 18 | REQUIRE(lock.TryLock()); 19 | lock.Unlock(); 20 | 21 | // Test Lock()/Unlock() methods 22 | lock.Lock(); 23 | lock.Unlock(); 24 | } 25 | 26 | TEST_CASE("Critical section locker", "[CppCommon][Threads]") 27 | { 28 | int items_to_produce = 10000; 29 | int producers_count = 4; 30 | int crc = 0; 31 | 32 | CriticalSection lock; 33 | 34 | // Calculate result value 35 | int result = 0; 36 | for (int i = 0; i < items_to_produce; ++i) 37 | result += i; 38 | 39 | // Start producers threads 40 | std::vector producers; 41 | for (int producer = 0; producer < producers_count; ++producer) 42 | { 43 | producers.emplace_back([&lock, &crc, producer, items_to_produce, producers_count]() 44 | { 45 | int items = (items_to_produce / producers_count); 46 | for (int i = 0; i < items; ++i) 47 | { 48 | Locker locker(lock); 49 | crc += (producer * items) + i; 50 | } 51 | }); 52 | } 53 | 54 | // Wait for all producers threads 55 | for (auto& producer : producers) 56 | producer.join(); 57 | 58 | // Check result 59 | REQUIRE(crc == result); 60 | } 61 | -------------------------------------------------------------------------------- /tests/test_threads_event_auto_reset.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 14.04.2016 3 | // 4 | 5 | #include "test.h" 6 | 7 | #include "threads/event_auto_reset.h" 8 | #include "threads/thread.h" 9 | 10 | #include 11 | #include 12 | 13 | using namespace CppCommon; 14 | 15 | TEST_CASE("Auto-reset event", "[CppCommon][Threads]") 16 | { 17 | int concurrency = 8; 18 | std::atomic count(0); 19 | 20 | EventAutoReset event; 21 | 22 | // Start some threads 23 | std::vector threads; 24 | for (int thread = 0; thread < concurrency; ++thread) 25 | { 26 | threads.emplace_back([&event, &count, thread]() 27 | { 28 | // Sleep for a while... 29 | Thread::Sleep(thread * 10); 30 | 31 | // Wait for the event 32 | event.Wait(); 33 | 34 | // Increment threads counter 35 | ++count; 36 | }); 37 | } 38 | 39 | // Allow threads to start 40 | Thread::Sleep(100); 41 | 42 | // Signal the event for each thread that waits 43 | for (int thread = 0; thread < concurrency; ++thread) 44 | event.Signal(); 45 | 46 | // Wait for all threads to complete 47 | for (auto& thread : threads) 48 | thread.join(); 49 | 50 | // Check results 51 | REQUIRE(count == concurrency); 52 | } 53 | -------------------------------------------------------------------------------- /tests/test_threads_event_manual_reset.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 14.04.2016 3 | // 4 | 5 | #include "test.h" 6 | 7 | #include "threads/event_manual_reset.h" 8 | #include "threads/thread.h" 9 | 10 | #include 11 | #include 12 | 13 | using namespace CppCommon; 14 | 15 | TEST_CASE("Manual-reset event", "[CppCommon][Threads]") 16 | { 17 | int concurrency = 8; 18 | std::atomic count(0); 19 | 20 | EventManualReset event; 21 | 22 | // Start some threads 23 | std::vector threads; 24 | for (int thread = 0; thread < concurrency; ++thread) 25 | { 26 | threads.emplace_back([&event, &count, thread]() 27 | { 28 | // Sleep for a while... 29 | Thread::Sleep(thread * 10); 30 | 31 | // Wait for the event 32 | event.Wait(); 33 | 34 | // Increment threads counter 35 | ++count; 36 | }); 37 | } 38 | 39 | // Allow threads to start 40 | Thread::Sleep(100); 41 | 42 | // Signal the event 43 | event.Signal(); 44 | 45 | // Wait for all threads to complete 46 | for (auto& thread : threads) 47 | thread.join(); 48 | 49 | // Check results 50 | REQUIRE(count == concurrency); 51 | } 52 | -------------------------------------------------------------------------------- /tests/test_threads_mpmc_ring_queue.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 19.01.2016 3 | // 4 | 5 | #include "test.h" 6 | 7 | #include "threads/mpmc_ring_queue.h" 8 | 9 | using namespace CppCommon; 10 | 11 | TEST_CASE("Multiple producers / multiple consumers wait-free ring queue", "[CppCommon][Threads]") 12 | { 13 | MPMCRingQueue queue(4); 14 | 15 | REQUIRE(queue.capacity() == 4); 16 | REQUIRE(queue.size() == 0); 17 | 18 | int v = -1; 19 | 20 | REQUIRE(!queue.Dequeue(v)); 21 | 22 | REQUIRE((queue.Enqueue(0) && (queue.size() == 1))); 23 | REQUIRE((queue.Enqueue(1) && (queue.size() == 2))); 24 | REQUIRE((queue.Enqueue(2) && (queue.size() == 3))); 25 | REQUIRE((queue.Enqueue(3) && (queue.size() == 4))); 26 | REQUIRE(!queue.Enqueue(4)); 27 | 28 | REQUIRE(((queue.Dequeue(v) && (v == 0)) && (queue.size() == 3))); 29 | REQUIRE(((queue.Dequeue(v) && (v == 1)) && (queue.size() == 2))); 30 | REQUIRE(((queue.Dequeue(v) && (v == 2)) && (queue.size() == 1))); 31 | 32 | REQUIRE((queue.Enqueue(4) && (queue.size() == 2))); 33 | REQUIRE((queue.Enqueue(5) && (queue.size() == 3))); 34 | REQUIRE((queue.Enqueue(6) && (queue.size() == 4))); 35 | REQUIRE(!queue.Enqueue(7)); 36 | 37 | REQUIRE(((queue.Dequeue(v) && (v == 3)) && (queue.size() == 3))); 38 | REQUIRE(((queue.Dequeue(v) && (v == 4)) && (queue.size() == 2))); 39 | REQUIRE(((queue.Dequeue(v) && (v == 5)) && (queue.size() == 1))); 40 | REQUIRE(((queue.Dequeue(v) && (v == 6)) && (queue.size() == 0))); 41 | REQUIRE(!queue.Dequeue(v)); 42 | 43 | REQUIRE((queue.Enqueue(7) && (queue.size() == 1))); 44 | 45 | REQUIRE(((queue.Dequeue(v) && (v == 7)) && (queue.size() == 0))); 46 | REQUIRE(!queue.Dequeue(v)); 47 | 48 | REQUIRE(queue.capacity() == 4); 49 | REQUIRE(queue.size() == 0); 50 | } 51 | -------------------------------------------------------------------------------- /tests/test_threads_mpsc_linked_batcher.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 19.01.2016 3 | // 4 | 5 | #include "test.h" 6 | 7 | #include "threads/mpsc_linked_batcher.h" 8 | 9 | using namespace CppCommon; 10 | 11 | TEST_CASE("Multiple producers / single consumer wait-free linked batcher", "[CppCommon][Threads]") 12 | { 13 | MPSCLinkedBatcher batcher; 14 | 15 | REQUIRE(!batcher.Dequeue()); 16 | 17 | REQUIRE(batcher.Enqueue(0)); 18 | REQUIRE(batcher.Enqueue(1)); 19 | REQUIRE(batcher.Enqueue(2)); 20 | 21 | REQUIRE(batcher.Dequeue()); 22 | REQUIRE(!batcher.Dequeue()); 23 | 24 | REQUIRE(batcher.Enqueue(3)); 25 | REQUIRE(batcher.Enqueue(4)); 26 | 27 | REQUIRE(batcher.Dequeue()); 28 | REQUIRE(!batcher.Dequeue()); 29 | 30 | REQUIRE(batcher.Enqueue(5)); 31 | 32 | REQUIRE(batcher.Dequeue()); 33 | REQUIRE(!batcher.Dequeue()); 34 | } 35 | -------------------------------------------------------------------------------- /tests/test_threads_mpsc_linked_queue.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 18.01.2016 3 | // 4 | 5 | #include "test.h" 6 | 7 | #include "threads/mpsc_linked_queue.h" 8 | 9 | using namespace CppCommon; 10 | 11 | TEST_CASE("Multiple producers / single consumer wait-free linked queue", "[CppCommon][Threads]") 12 | { 13 | MPSCLinkedQueue queue; 14 | 15 | int v = -1; 16 | 17 | REQUIRE(!queue.Dequeue(v)); 18 | 19 | REQUIRE(queue.Enqueue(0)); 20 | REQUIRE(queue.Enqueue(1)); 21 | REQUIRE(queue.Enqueue(2)); 22 | 23 | REQUIRE(((queue.Dequeue(v) && (v == 0)))); 24 | REQUIRE(((queue.Dequeue(v) && (v == 1)))); 25 | 26 | REQUIRE(queue.Enqueue(3)); 27 | REQUIRE(queue.Enqueue(4)); 28 | 29 | REQUIRE(((queue.Dequeue(v) && (v == 2)))); 30 | REQUIRE(((queue.Dequeue(v) && (v == 3)))); 31 | REQUIRE(((queue.Dequeue(v) && (v == 4)))); 32 | REQUIRE(!queue.Dequeue(v)); 33 | 34 | REQUIRE(queue.Enqueue(5)); 35 | 36 | REQUIRE((queue.Dequeue(v) && (v == 5))); 37 | REQUIRE(!queue.Dequeue(v)); 38 | } 39 | -------------------------------------------------------------------------------- /tests/test_threads_mpsc_ring_buffer.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 26.01.2016 3 | // 4 | 5 | #include "test.h" 6 | 7 | #include "threads/mpsc_ring_buffer.h" 8 | 9 | using namespace CppCommon; 10 | 11 | TEST_CASE("Multiple producers / single consumer wait-free ring buffer", "[CppCommon][Threads]") 12 | { 13 | MPSCRingBuffer buffer(4); 14 | 15 | REQUIRE(buffer.capacity() == 3); 16 | REQUIRE(buffer.size() == 0); 17 | 18 | char data[4]; 19 | size_t size; 20 | 21 | REQUIRE(!buffer.Dequeue(data, size = 4)); 22 | 23 | REQUIRE(buffer.Enqueue(data, 1)); 24 | REQUIRE(buffer.size() == 1); 25 | 26 | REQUIRE((buffer.Dequeue(data, size = 4) && (size == 1))); 27 | REQUIRE(buffer.size() == 0); 28 | 29 | REQUIRE(buffer.Enqueue(data, 2)); 30 | REQUIRE(buffer.size() == 2); 31 | 32 | REQUIRE((buffer.Dequeue(data, size = 4) && (size == 2))); 33 | REQUIRE(buffer.size() == 0); 34 | 35 | REQUIRE(buffer.Enqueue(data, 3)); 36 | REQUIRE(buffer.size() == 3); 37 | 38 | REQUIRE((buffer.Dequeue(data, size = 4) && (size == 3))); 39 | REQUIRE(buffer.size() == 0); 40 | 41 | REQUIRE(!buffer.Dequeue(data, size = 4)); 42 | 43 | REQUIRE(buffer.capacity() == 3); 44 | REQUIRE(buffer.size() == 0); 45 | } 46 | -------------------------------------------------------------------------------- /tests/test_threads_mutex.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 04.04.2016 3 | // 4 | 5 | #include "test.h" 6 | 7 | #include "threads/mutex.h" 8 | 9 | #include 10 | 11 | using namespace CppCommon; 12 | 13 | TEST_CASE("Mutex", "[CppCommon][Threads]") 14 | { 15 | Mutex lock; 16 | 17 | // Test TryLock() method 18 | REQUIRE(lock.TryLock()); 19 | lock.Unlock(); 20 | 21 | // Test Lock()/Unlock() methods 22 | lock.Lock(); 23 | lock.Unlock(); 24 | } 25 | 26 | TEST_CASE("Mutex locker", "[CppCommon][Threads]") 27 | { 28 | int items_to_produce = 10000; 29 | int producers_count = 4; 30 | int crc = 0; 31 | 32 | Mutex lock; 33 | 34 | // Calculate result value 35 | int result = 0; 36 | for (int i = 0; i < items_to_produce; ++i) 37 | result += i; 38 | 39 | // Start producers threads 40 | std::vector producers; 41 | for (int producer = 0; producer < producers_count; ++producer) 42 | { 43 | producers.emplace_back([&lock, &crc, producer, items_to_produce, producers_count]() 44 | { 45 | int items = (items_to_produce / producers_count); 46 | for (int i = 0; i < items; ++i) 47 | { 48 | Locker locker(lock); 49 | crc += (producer * items) + i; 50 | } 51 | }); 52 | } 53 | 54 | // Wait for all producers threads 55 | for (auto& producer : producers) 56 | producer.join(); 57 | 58 | // Check result 59 | REQUIRE(crc == result); 60 | } 61 | -------------------------------------------------------------------------------- /tests/test_threads_named_event_auto_reset.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 24.05.2016 3 | // 4 | 5 | #include "test.h" 6 | 7 | #include "threads/named_event_auto_reset.h" 8 | #include "threads/thread.h" 9 | 10 | #include 11 | #include 12 | 13 | using namespace CppCommon; 14 | 15 | #if !defined(__APPLE__) 16 | 17 | TEST_CASE("Named auto-reset event", "[CppCommon][Threads]") 18 | { 19 | int concurrency = 8; 20 | std::atomic count(0); 21 | 22 | // Named auto-reset event master 23 | NamedEventAutoReset event_master("named_auto_event_test"); 24 | 25 | // Start some threads 26 | std::vector threads; 27 | for (int thread = 0; thread < concurrency; ++thread) 28 | { 29 | threads.emplace_back([&count, thread]() 30 | { 31 | // Named auto-reset event slave 32 | NamedEventAutoReset event_slave("named_auto_event_test"); 33 | 34 | // Sleep for a while... 35 | Thread::Sleep(thread * 10); 36 | 37 | // Wait for the event 38 | event_slave.Wait(); 39 | 40 | // Increment threads counter 41 | ++count; 42 | }); 43 | } 44 | 45 | // Allow threads to start 46 | Thread::Sleep(100); 47 | 48 | // Signal the event for each thread that waits 49 | for (int thread = 0; thread < concurrency; ++thread) 50 | event_master.Signal(); 51 | 52 | // Wait for all threads to complete 53 | for (auto& thread : threads) 54 | thread.join(); 55 | 56 | // Check results 57 | REQUIRE(count == concurrency); 58 | } 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /tests/test_threads_named_event_manual_reset.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 24.05.2016 3 | // 4 | 5 | #include "test.h" 6 | 7 | #include "threads/named_event_manual_reset.h" 8 | #include "threads/thread.h" 9 | 10 | #include 11 | #include 12 | 13 | using namespace CppCommon; 14 | 15 | #if !defined(__APPLE__) 16 | 17 | TEST_CASE("Named manual-reset event", "[CppCommon][Threads]") 18 | { 19 | int concurrency = 8; 20 | std::atomic count(0); 21 | 22 | // Named manual-reset event master 23 | NamedEventManualReset event_master("named_manual_event_test"); 24 | 25 | // Start some threads 26 | std::vector threads; 27 | for (int thread = 0; thread < concurrency; ++thread) 28 | { 29 | threads.emplace_back([&count, thread]() 30 | { 31 | // Named manual-reset event slave 32 | NamedEventManualReset event_slave("named_manual_event_test"); 33 | 34 | // Sleep for a while... 35 | Thread::Sleep(thread * 10); 36 | 37 | // Wait for the event 38 | event_slave.Wait(); 39 | 40 | // Increment threads counter 41 | ++count; 42 | }); 43 | } 44 | 45 | // Allow threads to start 46 | Thread::Sleep(100); 47 | 48 | // Signal the event 49 | event_master.Signal(); 50 | 51 | // Wait for all threads to complete 52 | for (auto& thread : threads) 53 | thread.join(); 54 | 55 | // Check results 56 | REQUIRE(count == concurrency); 57 | } 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /tests/test_threads_named_mutex.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 15.04.2016 3 | // 4 | 5 | #include "test.h" 6 | 7 | #include "threads/named_mutex.h" 8 | 9 | #include 10 | 11 | using namespace CppCommon; 12 | 13 | #if !defined(__APPLE__) 14 | 15 | TEST_CASE("Named mutex locker", "[CppCommon][Threads]") 16 | { 17 | int items_to_produce = 10000; 18 | int producers_count = 4; 19 | int crc = 0; 20 | 21 | // Calculate result value 22 | int result = 0; 23 | for (int i = 0; i < items_to_produce; ++i) 24 | result += i; 25 | 26 | // Named mutex master 27 | NamedMutex lock_master("named_mutex_test"); 28 | 29 | // Start producers threads 30 | std::vector producers; 31 | for (int producer = 0; producer < producers_count; ++producer) 32 | { 33 | producers.emplace_back([&crc, producer, items_to_produce, producers_count]() 34 | { 35 | // Named mutex slave 36 | NamedMutex lock_slave("named_mutex_test"); 37 | 38 | int items = (items_to_produce / producers_count); 39 | for (int i = 0; i < items; ++i) 40 | { 41 | Locker locker(lock_slave); 42 | crc += (producer * items) + i; 43 | } 44 | }); 45 | } 46 | 47 | // Wait for all producers threads 48 | for (auto& producer : producers) 49 | producer.join(); 50 | 51 | // Check result 52 | REQUIRE(crc == result); 53 | } 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /tests/test_threads_named_semaphore.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 15.04.2016 3 | // 4 | 5 | #include "test.h" 6 | 7 | #include "threads/named_semaphore.h" 8 | 9 | #include 10 | #include 11 | 12 | using namespace CppCommon; 13 | 14 | TEST_CASE("Named semaphore locker", "[CppCommon][Threads]") 15 | { 16 | int items_to_produce = 10000; 17 | int producers_count = 8; 18 | std::atomic crc(0); 19 | 20 | // Calculate result value 21 | int result = 0; 22 | for (int i = 0; i < items_to_produce; ++i) 23 | result += i; 24 | 25 | // Named semaphore master 26 | NamedSemaphore lock_master("named_semaphore_test", 4); 27 | 28 | // Start producers threads 29 | std::vector producers; 30 | for (int producer = 0; producer < producers_count; ++producer) 31 | { 32 | producers.emplace_back([&crc, producer, items_to_produce, producers_count]() 33 | { 34 | // Named semaphore slave 35 | NamedSemaphore lock_slave("named_semaphore_test", 4); 36 | 37 | int items = (items_to_produce / producers_count); 38 | for (int i = 0; i < items; ++i) 39 | { 40 | Locker locker(lock_slave); 41 | crc += (producer * items) + i; 42 | } 43 | }); 44 | } 45 | 46 | // Wait for all producers threads 47 | for (auto& producer : producers) 48 | producer.join(); 49 | 50 | // Check result 51 | REQUIRE(crc == result); 52 | } 53 | -------------------------------------------------------------------------------- /tests/test_threads_spin_barrier.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 17.03.2016 3 | // 4 | 5 | #include "test.h" 6 | 7 | #include "threads/spin_barrier.h" 8 | #include "threads/thread.h" 9 | 10 | #include 11 | #include 12 | 13 | using namespace CppCommon; 14 | 15 | TEST_CASE("Spin barrier single thread", "[CppCommon][Threads]") 16 | { 17 | SpinBarrier barrier(1); 18 | 19 | // Test Wait() method 20 | REQUIRE(barrier.Wait()); 21 | } 22 | 23 | TEST_CASE("Spin barrier multiple threads", "[CppCommon][Threads]") 24 | { 25 | int concurrency = 8; 26 | std::atomic failed(false); 27 | std::atomic count(0); 28 | std::atomic last(0); 29 | 30 | SpinBarrier barrier(concurrency); 31 | 32 | // Start some threads 33 | std::vector threads; 34 | for (int thread = 0; thread < concurrency; ++thread) 35 | { 36 | threads.emplace_back([&barrier, &count, &last, &failed, concurrency, thread]() 37 | { 38 | // Increment threads counter 39 | ++count; 40 | 41 | // Sleep for a while... 42 | Thread::Sleep(thread * 10); 43 | 44 | // Wait for all other threads at the barrier 45 | if (barrier.Wait()) 46 | ++last; 47 | 48 | // Check result in each thread 49 | if (count != concurrency) 50 | failed = true; 51 | }); 52 | } 53 | 54 | // Wait for all threads to complete 55 | for (auto& thread : threads) 56 | thread.join(); 57 | 58 | // Check results 59 | REQUIRE(count == concurrency); 60 | REQUIRE(last == 1); 61 | REQUIRE(!failed); 62 | } 63 | -------------------------------------------------------------------------------- /tests/test_threads_spsc_ring_buffer.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 16.01.2016 3 | // 4 | 5 | #include "test.h" 6 | 7 | #include "threads/spsc_ring_buffer.h" 8 | 9 | using namespace CppCommon; 10 | 11 | TEST_CASE("Single producer / single consumer wait-free ring buffer", "[CppCommon][Threads]") 12 | { 13 | SPSCRingBuffer buffer(4); 14 | 15 | REQUIRE(buffer.capacity() == 4); 16 | REQUIRE(buffer.size() == 0); 17 | 18 | char data[5]; 19 | size_t size; 20 | 21 | REQUIRE(!buffer.Dequeue(data, size = 4)); 22 | 23 | REQUIRE(buffer.Enqueue(data, 1)); 24 | REQUIRE(buffer.size() == 1); 25 | 26 | REQUIRE(!buffer.Enqueue(data, 4)); 27 | 28 | REQUIRE(buffer.Enqueue(data, 1)); 29 | REQUIRE(buffer.size() == 2); 30 | 31 | REQUIRE(!buffer.Enqueue(data, 3)); 32 | 33 | REQUIRE(buffer.Enqueue(data, 2)); 34 | REQUIRE(buffer.size() == 4); 35 | 36 | REQUIRE(!buffer.Enqueue(data, 1)); 37 | 38 | REQUIRE((buffer.Dequeue(data, size = 5) && (size == 4))); 39 | REQUIRE(buffer.size() == 0); 40 | 41 | REQUIRE(!buffer.Dequeue(data, size = 1)); 42 | 43 | REQUIRE(buffer.Enqueue(data, 2)); 44 | REQUIRE(buffer.size() == 2); 45 | 46 | REQUIRE((buffer.Dequeue(data, size = 4) && (size == 2))); 47 | REQUIRE(buffer.size() == 0); 48 | 49 | REQUIRE(!buffer.Dequeue(data, size = 2)); 50 | 51 | REQUIRE(buffer.Enqueue(data, 4)); 52 | REQUIRE(buffer.size() == 4); 53 | 54 | REQUIRE((buffer.Dequeue(data, size = 5) && (size == 4))); 55 | REQUIRE(buffer.size() == 0); 56 | 57 | REQUIRE(!buffer.Dequeue(data, size = 3)); 58 | 59 | REQUIRE(buffer.capacity() == 4); 60 | REQUIRE(buffer.size() == 0); 61 | } 62 | -------------------------------------------------------------------------------- /tests/test_threads_spsc_ring_queue.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 15.01.2016 3 | // 4 | 5 | #include "test.h" 6 | 7 | #include "threads/spsc_ring_queue.h" 8 | 9 | using namespace CppCommon; 10 | 11 | TEST_CASE("Single producer / single consumer wait-free ring queue", "[CppCommon][Threads]") 12 | { 13 | SPSCRingQueue queue(4); 14 | 15 | REQUIRE(queue.capacity() == 3); 16 | REQUIRE(queue.size() == 0); 17 | 18 | int v = -1; 19 | 20 | REQUIRE(!queue.Dequeue(v)); 21 | 22 | REQUIRE((queue.Enqueue(0) && (queue.size() == 1))); 23 | REQUIRE((queue.Enqueue(1) && (queue.size() == 2))); 24 | REQUIRE((queue.Enqueue(2) && (queue.size() == 3))); 25 | REQUIRE(!queue.Enqueue(3)); 26 | 27 | REQUIRE(((queue.Dequeue(v) && (v == 0)) && (queue.size() == 2))); 28 | REQUIRE(((queue.Dequeue(v) && (v == 1)) && (queue.size() == 1))); 29 | 30 | REQUIRE((queue.Enqueue(3) && (queue.size() == 2))); 31 | REQUIRE((queue.Enqueue(4) && (queue.size() == 3))); 32 | REQUIRE(!queue.Enqueue(5)); 33 | 34 | REQUIRE(((queue.Dequeue(v) && (v == 2)) && (queue.size() == 2))); 35 | REQUIRE(((queue.Dequeue(v) && (v == 3)) && (queue.size() == 1))); 36 | REQUIRE(((queue.Dequeue(v) && (v == 4)) && (queue.size() == 0))); 37 | REQUIRE(!queue.Dequeue(v)); 38 | 39 | REQUIRE((queue.Enqueue(5) && (queue.size() == 1))); 40 | 41 | REQUIRE(((queue.Dequeue(v) && (v == 5)) && (queue.size() == 0))); 42 | REQUIRE(!queue.Dequeue(v)); 43 | 44 | REQUIRE(queue.capacity() == 3); 45 | REQUIRE(queue.size() == 0); 46 | } 47 | -------------------------------------------------------------------------------- /tests/test_threads_thread.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 27.01.2016 3 | // 4 | 5 | #include "test.h" 6 | 7 | #include "threads/thread.h" 8 | #include "time/timestamp.h" 9 | 10 | using namespace CppCommon; 11 | 12 | TEST_CASE("Thread", "[CppCommon][Threads]") 13 | { 14 | REQUIRE(Thread::CurrentThreadId() > 0); 15 | REQUIRE(Thread::CurrentThreadAffinity() >= 0); 16 | 17 | // Test Sleep() method 18 | for (int64_t i = 1; i < 10; ++i) 19 | { 20 | int64_t start = Timestamp::nano(); 21 | Thread::Sleep(i); 22 | int64_t stop = Timestamp::nano(); 23 | REQUIRE(((stop - start) >= 0)); 24 | } 25 | 26 | // Test SleepFor() method 27 | for (int64_t i = 1; i < 1000000; i *= 10) 28 | { 29 | int64_t start = Timestamp::nano(); 30 | Thread::SleepFor(Timespan::nanoseconds(i)); 31 | int64_t stop = Timestamp::nano(); 32 | REQUIRE(((stop - start) >= 0)); 33 | } 34 | 35 | // Test SleepUntil() method 36 | for (int64_t i = 1; i < 1000000; i *= 10) 37 | { 38 | int64_t start = Timestamp::nano(); 39 | Thread::SleepUntil(UtcTimestamp() + Timespan::nanoseconds(i)); 40 | int64_t stop = Timestamp::nano(); 41 | REQUIRE(((stop - start) >= 0)); 42 | } 43 | 44 | // Test Yield() method 45 | for (int64_t i = 0; i < 10; ++i) 46 | { 47 | int64_t start = Timestamp::nano(); 48 | Thread::Yield(); 49 | int64_t stop = Timestamp::nano(); 50 | REQUIRE(((stop - start) >= 0)); 51 | } 52 | 53 | // Test thread CPU affinity 54 | std::bitset<64> affinity = Thread::GetAffinity(); 55 | REQUIRE(affinity.to_ullong() > 0); 56 | 57 | // Test thread priority 58 | ThreadPriority priority = Thread::GetPriority(); 59 | REQUIRE(priority == ThreadPriority::NORMAL); 60 | } 61 | -------------------------------------------------------------------------------- /tests/test_time_time.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 13.07.2016 3 | // 4 | 5 | #include "test.h" 6 | 7 | #include "time/time.h" 8 | 9 | #include 10 | 11 | using namespace CppCommon; 12 | 13 | TEST_CASE("Time", "[CppCommon][Time]") 14 | { 15 | Time time1(2016, 7, 13, 11, 22, 33, 123, 456, 789); 16 | REQUIRE(time1.year() == 2016); 17 | REQUIRE(time1.month() == 7); 18 | REQUIRE(time1.day() == 13); 19 | REQUIRE(time1.hour() == 11); 20 | REQUIRE(time1.minute() == 22); 21 | REQUIRE(time1.second() == 33); 22 | REQUIRE(time1.millisecond() == 123); 23 | REQUIRE(time1.microsecond() == 456); 24 | REQUIRE(time1.nanosecond() == 789); 25 | REQUIRE((time1.utcstamp().total() == 1468408953123456789ll)); 26 | 27 | Time time2(time1); 28 | UtcTime time3(time2.utcstamp()); 29 | LocalTime time4(time2.localstamp()); 30 | REQUIRE(time2 == time3); 31 | REQUIRE(time2 == time4); 32 | 33 | Time time5 = Time::epoch(); 34 | REQUIRE(time5 == Time(1970, 1, 1, 0, 0, 0, 0, 0, 0)); 35 | 36 | UtcTime time6; 37 | LocalTime time7(time6); 38 | UtcTime time8(time7); 39 | REQUIRE(time6 == time8); 40 | REQUIRE(time6 > Time::epoch()); 41 | REQUIRE(time7 > Time::epoch()); 42 | REQUIRE(std::abs((time6 - time7).hours()) < 24); 43 | 44 | // Compatibility with std::chrono 45 | UtcTime time9(std::chrono::system_clock::now() + std::chrono::milliseconds(10)); 46 | std::this_thread::sleep_until(time9.chrono()); 47 | } 48 | -------------------------------------------------------------------------------- /tests/test_time_timespan.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 11.07.2016 3 | // 4 | 5 | #include "test.h" 6 | 7 | #include "time/timespan.h" 8 | 9 | #include 10 | 11 | using namespace CppCommon; 12 | 13 | TEST_CASE("Timespan", "[CppCommon][Time]") 14 | { 15 | Timespan span1 = Timespan::days(29) + 16 | Timespan::hours(14) + 17 | Timespan::minutes(45) + 18 | Timespan::seconds(55) + 19 | Timespan::milliseconds(123) + 20 | Timespan::microseconds(456) + 21 | Timespan::nanoseconds(789); 22 | Timespan span2(span1); 23 | 24 | REQUIRE(span1.total() == 2558755123456789ll); 25 | REQUIRE(span1.days() == 29); 26 | REQUIRE((span1.hours() % 24) == 14); 27 | REQUIRE((span1.minutes() % 60) == 45); 28 | REQUIRE((span1.seconds() % 60) == 55); 29 | REQUIRE((span1.milliseconds() % 1000) == 123); 30 | REQUIRE((span1.microseconds() % 1000) == 456); 31 | REQUIRE((span1.nanoseconds() % 1000) == 789); 32 | 33 | REQUIRE(span2.total() == span1.total()); 34 | REQUIRE(span2.days() == span1.days()); 35 | REQUIRE(span2.hours() == (span1.days() * 24 + 14)); 36 | REQUIRE(span2.minutes() == (span1.hours() * 60 + 45)); 37 | REQUIRE(span2.seconds() == (span1.minutes() * 60 + 55)); 38 | REQUIRE(span2.milliseconds() == (span1.seconds() * 1000 + 123)); 39 | REQUIRE(span2.microseconds() == (span1.milliseconds() * 1000 + 456)); 40 | REQUIRE(span2.nanoseconds() == (span1.microseconds() * 1000 + 789)); 41 | 42 | // Compatibility with std::chrono 43 | Timespan span3(std::chrono::milliseconds(10)); 44 | REQUIRE(span3.milliseconds() == 10); 45 | std::this_thread::sleep_for(span3.chrono()); 46 | } 47 | -------------------------------------------------------------------------------- /tests/test_time_timestamp.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 26.01.2016 3 | // 4 | 5 | #include "test.h" 6 | 7 | #include "time/timestamp.h" 8 | 9 | #include 10 | 11 | using namespace CppCommon; 12 | 13 | TEST_CASE("Timestamp", "[CppCommon][Time]") 14 | { 15 | REQUIRE((Timestamp::epoch() == 0)); 16 | REQUIRE((Timestamp::utc() > 0)); 17 | REQUIRE((Timestamp::local() > 0)); 18 | REQUIRE((Timestamp::nano() > 0)); 19 | REQUIRE((Timestamp::rdts() > 0)); 20 | 21 | uint64_t prev_utc = 0; 22 | uint64_t prev_local = 0; 23 | uint64_t prev_nano = 0; 24 | uint64_t prev_rdts = 0; 25 | for (int i = 0; i < 1000; ++i) 26 | { 27 | uint64_t next_utc = Timestamp::utc(); 28 | uint64_t next_local = Timestamp::local(); 29 | uint64_t next_nano = Timestamp::nano(); 30 | uint64_t next_rdts = Timestamp::rdts(); 31 | REQUIRE(prev_utc <= next_utc); 32 | REQUIRE(prev_local <= next_local); 33 | REQUIRE(prev_nano <= next_nano); 34 | REQUIRE(prev_rdts <= next_rdts); 35 | prev_utc = next_utc; 36 | prev_local = next_local; 37 | prev_nano = next_nano; 38 | prev_rdts = next_rdts; 39 | } 40 | 41 | // Compatibility with std::chrono 42 | Timestamp timestamp(std::chrono::system_clock::now() + std::chrono::milliseconds(10)); 43 | std::this_thread::sleep_until(timestamp.chrono()); 44 | } 45 | -------------------------------------------------------------------------------- /tests/test_time_timezone.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 18.07.2016 3 | // 4 | 5 | #include "test.h" 6 | 7 | #include "time/timezone.h" 8 | 9 | using namespace CppCommon; 10 | 11 | TEST_CASE("Timezone", "[CppCommon][Time]") 12 | { 13 | Timezone timezone1("Test", Timespan::hours(-8), Timespan::hours(1)); 14 | REQUIRE(timezone1.name() == "Test"); 15 | REQUIRE(timezone1.offset() == Timespan::hours(-8)); 16 | REQUIRE(timezone1.daylight() == Timespan::hours(1)); 17 | REQUIRE(timezone1.total() == Timespan::hours(-7)); 18 | 19 | Timezone timezone2 = Timezone::utc(); 20 | REQUIRE(timezone2 == Timezone("GMT", Timespan::zero())); 21 | 22 | UtcTime utctime; 23 | LocalTime localtime(utctime); 24 | Timezone timezone3 = Timezone::local(); 25 | REQUIRE(localtime == timezone3.Convert(utctime)); 26 | REQUIRE(utctime == timezone3.Convert(localtime)); 27 | 28 | Timezone timezone4 = Timezone::utc(); 29 | Timezone timezone5 = Timezone::local(); 30 | REQUIRE(std::abs((timezone4.total() - timezone5.total()).hours()) < 24); 31 | } 32 | -------------------------------------------------------------------------------- /tests/test_utility_endian.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 21.07.2017 3 | // 4 | 5 | #include "test.h" 6 | 7 | #include "system/environment.h" 8 | #include "utility/endian.h" 9 | 10 | using namespace CppCommon; 11 | 12 | TEST_CASE("Endian", "[CppCommon][Utility]") 13 | { 14 | // Compile time returned endian value should be equal to calculated environment one! 15 | REQUIRE((Endian::IsBigEndian() == Environment::IsBigEndian())); 16 | REQUIRE((Endian::IsLittleEndian() == Environment::IsLittleEndian())); 17 | } 18 | -------------------------------------------------------------------------------- /tests/test_utility_singleton.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 31.08.2016 3 | // 4 | 5 | #include "test.h" 6 | 7 | #include "utility/singleton.h" 8 | 9 | using namespace CppCommon; 10 | 11 | namespace { 12 | 13 | class TestSingleton : public Singleton 14 | { 15 | friend Singleton; 16 | 17 | public: 18 | bool Test() { return _init; } 19 | 20 | private: 21 | bool _init; 22 | TestSingleton() : _init(true) {} 23 | ~TestSingleton() { _init = false; } 24 | }; 25 | 26 | } // namespace 27 | 28 | TEST_CASE("Singleton", "[CppCommon][Utility]") 29 | { 30 | REQUIRE(TestSingleton::GetInstance().Test()); 31 | } 32 | -------------------------------------------------------------------------------- /tests/test_utility_static_constructor.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 31.08.2016 3 | // 4 | 5 | #include "test.h" 6 | 7 | #include "utility/static_constructor.h" 8 | 9 | using namespace CppCommon; 10 | 11 | namespace { 12 | 13 | class TestConstructor 14 | { 15 | public: 16 | TestConstructor() { REQUIRE(value == 123); } 17 | ~TestConstructor() { REQUIRE(value == 123); } 18 | 19 | int Test() { return value; } 20 | 21 | private: 22 | static int value; 23 | 24 | static void StaticConstructor() 25 | { 26 | CppCommon::StaticConstructor<&TestConstructor::StaticConstructor>::instance(); 27 | value = 123; 28 | } 29 | }; 30 | 31 | int TestConstructor::value = 0; 32 | 33 | class TestDestructor 34 | { 35 | public: 36 | TestDestructor() { REQUIRE(value == 321); } 37 | ~TestDestructor() { REQUIRE(value == 321); } 38 | 39 | int Test() { return value; } 40 | 41 | private: 42 | static int value; 43 | 44 | static void StaticConstructor() 45 | { 46 | CppCommon::StaticConstructor<&TestDestructor::StaticConstructor, &TestDestructor::StaticDestructor>::instance(); 47 | value = 321; 48 | } 49 | 50 | static void StaticDestructor() 51 | { 52 | value = 0; 53 | } 54 | }; 55 | 56 | int TestDestructor::value = 0; 57 | 58 | } // namespace 59 | 60 | TEST_CASE("Static constructor", "[CppCommon][Utility]") 61 | { 62 | TestConstructor test; 63 | REQUIRE(test.Test() == 123); 64 | } 65 | 66 | TEST_CASE("Static constructor and destructor", "[CppCommon][Utility]") 67 | { 68 | TestDestructor test; 69 | REQUIRE(test.Test() == 321); 70 | } 71 | --------------------------------------------------------------------------------