-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit d968f16
Showing
49 changed files
with
1,571 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# https://clang.llvm.org/docs/ClangFormatStyleOptions.html | ||
# https://zed0.co.uk/clang-format-configurator/ | ||
BasedOnStyle: LLVM | ||
CompactNamespaces: true | ||
FixNamespaceComments: false | ||
PointerAlignment: Left |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
root = true | ||
|
||
[*] | ||
end_of_line = lf | ||
trim_trailing_whitespace = true | ||
insert_final_newline = true | ||
charset = utf-8 | ||
indent_style = space | ||
indent_size = 2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
* text=auto eol=lf |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
on: push | ||
|
||
jobs: | ||
build: | ||
runs-on: windows-2022 | ||
steps: | ||
- uses: actions/checkout@v3 | ||
- uses: ilammy/msvc-dev-cmd@v1 | ||
- run: ./build.ps1 | ||
- uses: softprops/action-gh-release@v1 | ||
if: startsWith(github.ref, 'refs/tags/') | ||
env: | ||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
with: | ||
draft: true | ||
files: out/publish/*.zip | ||
fail_on_unmatched_files: true | ||
- uses: actions/upload-artifact@v3 | ||
with: | ||
name: Build artifacts | ||
path: out/publish/*.zip |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
/out/ | ||
.vs/ | ||
.idea/ | ||
CMakeSettings.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
cmake_minimum_required (VERSION 3.17) | ||
project(UtilsHLibrary LANGUAGES CXX) | ||
|
||
include(tools/cmake/compiler_options.cmake) | ||
include(tools/cmake/clang_format.cmake) | ||
include(tools/cmake/catch2_lib.cmake) | ||
|
||
file(GLOB_RECURSE src_files CONFIGURE_DEPENDS "src/*.h" "src/*.cpp") | ||
add_executable(utils_h_test ${src_files}) | ||
target_include_directories(utils_h_test PRIVATE "src") | ||
target_precompile_headers(utils_h_test PRIVATE src/test/precompiled_header.h) | ||
add_clang_format(utils_h_test) | ||
add_catch2_lib(utils_h_test) | ||
add_compiler_options_with_warnings(utils_h_test) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
MIT License | ||
|
||
Copyright (c) 2018 PolarGoose | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
This project contains a small header only C++ library of helpful utilities. | ||
|
||
## How to use this library | ||
As it is a header only library, you only need to add the headers from the "src/utils_h" folder to your project. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
Function Info($msg) { | ||
Write-Host -ForegroundColor DarkGreen "`nINFO: $msg`n" | ||
} | ||
|
||
Function Error($msg) { | ||
Write-Host `n`n | ||
Write-Error $msg | ||
exit 1 | ||
} | ||
|
||
Function CheckReturnCodeOfPreviousCommand($msg) { | ||
if(-Not $?) { | ||
Error "${msg}. Error code: $LastExitCode" | ||
} | ||
} | ||
|
||
Function CreateZipArchive($directory, $archiveFile) { | ||
Info "Create a zip archive from `n '$directory' `n to `n '$archiveFile'" | ||
New-Item $archiveFile -Force -ItemType File > $null | ||
Compress-Archive -Force -Path $directory -DestinationPath $archiveFile | ||
} | ||
|
||
Function ForceCopy($srcFile, $dstFile) { | ||
Info "Copy `n '$srcFile' `n to `n '$dstFile'" | ||
New-Item $dstFile -Force -ItemType File > $null | ||
Copy-Item $srcFile -Destination $dstFile -Force | ||
} | ||
|
||
Set-StrictMode -Version Latest | ||
$ErrorActionPreference = "Stop" | ||
|
||
$root = Resolve-Path $PSScriptRoot | ||
$buildDir = "$root/out" | ||
$publishDir = "$buildDir/publish" | ||
|
||
Info "Build the project using Cmake" | ||
Info "Cmake generation phase" | ||
cmake -S $root -B $buildDir -G Ninja -DCMAKE_BUILD_TYPE=Release | ||
CheckReturnCodeOfPreviousCommand "Cmake generation phase failed" | ||
Info "Cmake build phase" | ||
cmake --build $buildDir | ||
CheckReturnCodeOfPreviousCommand "Cmake building phase failed" | ||
|
||
Info "Run tests" | ||
& $buildDir/utils_h_test.exe | ||
CheckReturnCodeOfPreviousCommand "Tests failed" | ||
|
||
CreateZipArchive $root/src/utils_h $publishDir/utils_h.zip |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
#include "utils_h/bit_cast.h" | ||
#include "utils_h/struct_aliasing_disable.h" | ||
|
||
using namespace utils_h; | ||
|
||
template <typename Source, typename Dest> void bit_cast_test(const Source src) { | ||
const auto dst = bit_cast<Dest>(src); | ||
REQUIRE(memcmp(&dst, &src, sizeof(src)) == 0); | ||
|
||
const auto new_src = bit_cast<Source>(dst); | ||
REQUIRE(memcmp(&new_src, &src, sizeof(src)) == 0); | ||
} | ||
|
||
UTILS_H_DISABLE_STRUCT_ALIASING_BEGIN | ||
struct struct_of_64_bytes { | ||
uint8_t a; | ||
uint32_t b; | ||
uint8_t c; | ||
uint8_t d; | ||
uint8_t e; | ||
}; | ||
UTILS_H_DISABLE_STRUCT_ALIASING_END | ||
|
||
TEST_CASE("bit_cast - Should convert data back and forth") { | ||
bit_cast_test<float, uint32_t>(1.2F); | ||
bit_cast_test<char, uint8_t>('a'); | ||
bit_cast_test<uint64_t, struct_of_64_bytes>(0x12af43db4589a7c4); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
#include "utils_h/circular_buffer.h" | ||
|
||
using namespace utils_h; | ||
|
||
class circular_buffer_test { | ||
protected: | ||
void fill_buffer() { | ||
for (size_t i{0}; i < m_capacity; i++) { | ||
m_buffer.put(i); | ||
} | ||
} | ||
|
||
const size_t m_capacity{100}; | ||
circular_buffer<size_t> m_buffer{m_capacity}; | ||
}; | ||
|
||
TEST_CASE_METHOD(circular_buffer_test, "Capacity should return correct value") { | ||
REQUIRE(m_buffer.capacity() == m_capacity); | ||
} | ||
|
||
TEST_CASE_METHOD( | ||
circular_buffer_test, | ||
"Get method should throw an exception when the buffer is empty") { | ||
REQUIRE(m_buffer.is_empty() == true); | ||
REQUIRE_THROWS_AS(m_buffer.get(), circular_buffer_is_empty_exception); | ||
} | ||
|
||
TEST_CASE_METHOD( | ||
circular_buffer_test, | ||
"Buffer can contain the amount of elements equal to its capacity") { | ||
fill_buffer(); | ||
|
||
REQUIRE(m_buffer.size() == m_capacity); | ||
REQUIRE(m_buffer.is_full() == true); | ||
|
||
for (size_t i{0}; i < m_capacity; i++) { | ||
REQUIRE(m_buffer.get() == i); | ||
} | ||
|
||
REQUIRE(m_buffer.size() == 0); | ||
REQUIRE(m_buffer.is_empty() == true); | ||
} | ||
|
||
TEST_CASE_METHOD(circular_buffer_test, "Adding one element to a full buffer " | ||
"should remove its last added element") { | ||
fill_buffer(); | ||
|
||
m_buffer.put(m_capacity); | ||
|
||
for (size_t i{0}; i < m_capacity; i++) { | ||
REQUIRE(m_buffer.get() == i + 1); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
#include "utils_h/concurrency/dispatcher.h" | ||
|
||
using namespace utils_h; | ||
using namespace utils_h::concurrency; | ||
|
||
class dispatcher_test { | ||
protected: | ||
void wait_while_all_tasks_are_executed() { | ||
_dispatcher.dispatch_and_wait([] {}); | ||
} | ||
|
||
void unhandled_exception_handler() { | ||
_unhandled_exception_handler_was_called = true; | ||
} | ||
|
||
dispatcher _dispatcher{ | ||
[&](auto& /* exception */) { unhandled_exception_handler(); }}; | ||
bool _unhandled_exception_handler_was_called{false}; | ||
}; | ||
|
||
TEST_CASE_METHOD( | ||
dispatcher_test, | ||
"dispatch_and_wait function should work with functions which return void") { | ||
_dispatcher.dispatch_and_wait([&] {}); | ||
} | ||
|
||
TEST_CASE_METHOD(dispatcher_test, "dispatch_and_wait function should work with " | ||
"functions which return value") { | ||
REQUIRE(_dispatcher.dispatch_and_wait([] { return std::string{"string"}; }) == | ||
"string"); | ||
REQUIRE(_dispatcher.dispatch_and_wait([] { return 1; }) == 1); | ||
} | ||
|
||
TEST_CASE_METHOD(dispatcher_test, | ||
"If a dispatched task throws an exception, an unhandled " | ||
"exception handler should be called") { | ||
_dispatcher.dispatch([] { throw std::runtime_error("error"); }); | ||
wait_while_all_tasks_are_executed(); | ||
|
||
REQUIRE(_unhandled_exception_handler_was_called == true); | ||
} | ||
|
||
TEST_CASE_METHOD(dispatcher_test, "Exception during dispatch_and_wait function " | ||
"call should be propagated to the caller") { | ||
REQUIRE_THROWS_AS( | ||
_dispatcher.dispatch_and_wait([] { throw std::runtime_error("error"); }), | ||
std::runtime_error); | ||
} | ||
|
||
TEST_CASE_METHOD(dispatcher_test, | ||
"is_dispatcher_thread function returns true if it is called " | ||
"inside a dispatcher thread") { | ||
REQUIRE(_dispatcher.is_dispatcher_thread() == false); | ||
REQUIRE(_dispatcher.dispatch_and_wait( | ||
[&] { return _dispatcher.is_dispatcher_thread(); }) == true); | ||
} | ||
|
||
TEST_CASE_METHOD( | ||
dispatcher_test, | ||
"Tasks should be executed in the order in which they were dispatched") { | ||
std::vector<size_t> results; | ||
|
||
for (size_t i = 0; i < 100; i++) { | ||
_dispatcher.dispatch([i, &results] { results.push_back(i); }); | ||
} | ||
|
||
wait_while_all_tasks_are_executed(); | ||
REQUIRE(results.size() == 100); | ||
|
||
for (size_t i = 0; i < 100; i++) { | ||
REQUIRE(results[i] == i); | ||
} | ||
} |
92 changes: 92 additions & 0 deletions
92
src/test/concurrency/interruptible_condition_variable_test.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
#include "utils/time_passed_method.h" | ||
#include "utils_h/concurrency/interruptible_condition_variable.h" | ||
|
||
using namespace utils_h; | ||
using namespace utils_h::concurrency; | ||
using namespace std::chrono_literals; | ||
|
||
class interruptible_condition_variable_test : protected has_time_passed_method { | ||
protected: | ||
std::mutex _mutex; | ||
interruptible_condition_variable _cond_var; | ||
}; | ||
|
||
TEST_CASE_METHOD(interruptible_condition_variable_test, | ||
"wait() method should throw an exception on time out") { | ||
std::unique_lock lock{_mutex}; | ||
|
||
REQUIRE_THROWS_AS(_cond_var.wait_for( | ||
lock, [] { return false; }, 10ms), | ||
timed_out_exception); | ||
} | ||
|
||
TEST_CASE_METHOD(interruptible_condition_variable_test, | ||
"wait() method should throw an exception when interrupted") { | ||
auto client_func{[&] { | ||
try { | ||
std::unique_lock lock{_mutex}; | ||
_cond_var.wait_for( | ||
lock, [] { return false; }, 1s); | ||
} catch (const interrupted_exception&) { | ||
return true; | ||
} | ||
return false; | ||
}}; | ||
|
||
auto client1_is_interrupted{false}; | ||
auto client2_is_interrupted{false}; | ||
|
||
std::thread client1{[&] { client1_is_interrupted = client_func(); }}; | ||
std::thread client2{[&] { client2_is_interrupted = client_func(); }}; | ||
|
||
// sleep long enough to let client1 and client2 threads to get blocked on | ||
// _cond_var.wait_for() call | ||
std::this_thread::sleep_for(300ms); | ||
|
||
// interrupt client1 and client2 | ||
{ | ||
std::unique_lock lock{_mutex}; | ||
_cond_var.interrupt(lock); | ||
} | ||
|
||
// wait until client1 and client2 threads get notified about the interruption | ||
// and finished | ||
client1.join(); | ||
client2.join(); | ||
|
||
REQUIRE(client1_is_interrupted == true); | ||
REQUIRE(client2_is_interrupted == true); | ||
} | ||
|
||
TEST_CASE_METHOD( | ||
interruptible_condition_variable_test, | ||
"After being interrupted, all calls to wait() should throw an exception") { | ||
std::unique_lock lock{_mutex}; | ||
_cond_var.interrupt(lock); | ||
|
||
REQUIRE_THROWS_AS(_cond_var.wait_for(lock, [] { return false; }), | ||
interrupted_exception); | ||
} | ||
|
||
TEST_CASE_METHOD( | ||
interruptible_condition_variable_test, | ||
"wait() method should unblock when the condition becomes true") { | ||
auto value_to_wait_for{false}; | ||
|
||
std::thread client{[&] { | ||
std::unique_lock lock{_mutex}; | ||
_cond_var.wait_for(lock, [&] { return value_to_wait_for; }); | ||
}}; | ||
|
||
// wait long enough to let client thread to get blocked on wait_for() method | ||
std::this_thread::sleep_for(300ms); | ||
|
||
// set the wait condition to true and wake up the client | ||
{ | ||
std::unique_lock lock{_mutex}; | ||
value_to_wait_for = true; | ||
_cond_var.notify_all(); | ||
} | ||
|
||
client.join(); | ||
} |
Oops, something went wrong.