Merge branch 'master' into other/mousetrap_fixes_v2
# Conflicts: # Peripherals/Inc/peripherals_imu_icm.hpp
This commit is contained in:
commit
d65e0b9ad9
@ -9,7 +9,6 @@ steps:
|
|||||||
commands:
|
commands:
|
||||||
- mkdir -p build
|
- mkdir -p build
|
||||||
- cd build
|
- cd build
|
||||||
- conan install .. --build=missing
|
|
||||||
- cmake .. -G "Ninja" -DCMAKE_BUILD_TYPE=Release -DWITH_TESTS=ON
|
- cmake .. -G "Ninja" -DCMAKE_BUILD_TYPE=Release -DWITH_TESTS=ON
|
||||||
- ninja
|
- ninja
|
||||||
- ctest . --output-on-failure
|
- ctest . --output-on-failure
|
||||||
|
|||||||
@ -1,22 +1,19 @@
|
|||||||
cmake_minimum_required(VERSION 3.8 FATAL_ERROR)
|
cmake_minimum_required(VERSION 3.8 FATAL_ERROR)
|
||||||
|
|
||||||
set(version 0.1.0)
|
set(SKULLC_VERSION 0.1.0)
|
||||||
|
|
||||||
project(skullc
|
project(skullc
|
||||||
VERSION ${version}
|
VERSION ${SKULLC_VERSION}
|
||||||
LANGUAGES
|
LANGUAGES
|
||||||
C
|
C
|
||||||
CXX
|
CXX
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR})
|
#list(APPEND CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR})
|
||||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/)
|
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
option(SKULLC_WITH_TESTS "Enable unit testing." OFF)
|
||||||
list(APPEND CMAKE_CXX_FLAGS "-Wall -Wextra")
|
option(SKULLC_WITH_HAL "Enable the compiling and deployment of the HAL dependent sections." OFF)
|
||||||
|
|
||||||
option(WITH_TESTS "Enable unit testing." OFF)
|
|
||||||
option(WITH_HAL "Enable the compiling and deployment of the HAL dependent sections." OFF)
|
|
||||||
|
|
||||||
include(skullc-install)
|
include(skullc-install)
|
||||||
|
|
||||||
@ -24,7 +21,7 @@ add_subdirectory(Peripherals)
|
|||||||
add_subdirectory(Utility)
|
add_subdirectory(Utility)
|
||||||
add_subdirectory(Messaging)
|
add_subdirectory(Messaging)
|
||||||
|
|
||||||
if(WITH_TESTS)
|
if(SKULLC_WITH_TESTS)
|
||||||
enable_testing()
|
enable_testing()
|
||||||
add_subdirectory(Tests)
|
add_subdirectory(Tests)
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
50
Jenkinsfile
vendored
Normal file
50
Jenkinsfile
vendored
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
pipeline {
|
||||||
|
agent {
|
||||||
|
label 'ubuntu'
|
||||||
|
}
|
||||||
|
|
||||||
|
stages {
|
||||||
|
stage("build && test") {
|
||||||
|
steps {
|
||||||
|
echo "Workspace: ${env.WORKSPACE}"
|
||||||
|
sh 'mkdir -p build'
|
||||||
|
|
||||||
|
dir("build") {
|
||||||
|
sh 'ls'
|
||||||
|
sh 'cmake .. -G "Ninja" -DCMAKE_BUILD_TYPE=Release -DSKULLC_WITH_TESTS=ON'
|
||||||
|
sh 'ninja'
|
||||||
|
sh 'ctest . -T test --output-on-failure --no-compress-output'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
post {
|
||||||
|
always {
|
||||||
|
archiveArtifacts (
|
||||||
|
artifacts: 'build/Testing/**/*.xml',
|
||||||
|
fingerprint: true
|
||||||
|
)
|
||||||
|
|
||||||
|
// Process the CTest xml output with the xUnit plugin
|
||||||
|
xunit (
|
||||||
|
testTimeMargin: '3000',
|
||||||
|
thresholdMode: 1,
|
||||||
|
thresholds: [
|
||||||
|
skipped(failureThreshold: '0'),
|
||||||
|
failed(failureThreshold: '0')
|
||||||
|
],
|
||||||
|
tools: [CTest(
|
||||||
|
pattern: 'build/Testing/**/*.xml',
|
||||||
|
deleteOutputFiles: true,
|
||||||
|
failIfNotNew: false,
|
||||||
|
skipNoTestFiles: true,
|
||||||
|
stopProcessingIfError: true
|
||||||
|
)]
|
||||||
|
)
|
||||||
|
|
||||||
|
// Clear the source and build dirs before next run
|
||||||
|
deleteDir()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,9 +5,9 @@ add_library(messaging INTERFACE)
|
|||||||
add_library(skullc::messaging ALIAS messaging)
|
add_library(skullc::messaging ALIAS messaging)
|
||||||
|
|
||||||
target_include_directories(messaging
|
target_include_directories(messaging
|
||||||
INTERFACE
|
INTERFACE
|
||||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/Inc>
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/Inc>
|
||||||
$<INSTALL_INTERFACE:include>
|
$<INSTALL_INTERFACE:include>
|
||||||
)
|
)
|
||||||
|
|
||||||
skullc_install_packages(skullc messaging ${version})
|
skullc_install_packages(skullc messaging ${SKULLC_VERSION})
|
||||||
|
|||||||
@ -11,4 +11,4 @@ target_include_directories(peripherals
|
|||||||
)
|
)
|
||||||
|
|
||||||
## INSTALL
|
## INSTALL
|
||||||
skullc_install_packages(skullc peripherals ${version})
|
skullc_install_packages(skullc peripherals ${SKULLC_VERSION})
|
||||||
|
|||||||
@ -74,11 +74,12 @@ public:
|
|||||||
|
|
||||||
const std::uint8_t new_gyro_conf = (std::uint32_t(scale_gyro_) << 3);
|
const std::uint8_t new_gyro_conf = (std::uint32_t(scale_gyro_) << 3);
|
||||||
registers.writeRegister(Registers_::GYRO_CONFIG & Registers_::WRITE_MASK,
|
registers.writeRegister(Registers_::GYRO_CONFIG & Registers_::WRITE_MASK,
|
||||||
new_gyro_conf);
|
new_gyro_conf);
|
||||||
|
|
||||||
const std::uint8_t new_accel_config = (std::uint32_t(scale_accel_) << 3);
|
const std::uint8_t new_accel_config = (std::uint32_t(scale_accel_) << 3);
|
||||||
registers.writeRegister(Registers_::ACCEL_CONFIG & Registers_::WRITE_MASK,
|
registers.writeRegister(Registers_::ACCEL_CONFIG & Registers_::WRITE_MASK,
|
||||||
new_accel_config);
|
new_accel_config);
|
||||||
|
|
||||||
|
|
||||||
// ACCEL_FCHOICE_B = 0, A_DLPF_CFG = 3 filter=44.8/61.5 rate=1KHz
|
// ACCEL_FCHOICE_B = 0, A_DLPF_CFG = 3 filter=44.8/61.5 rate=1KHz
|
||||||
registers.writeRegister(Registers_::ACCEL_CONFIG2 & Registers_::WRITE_MASK,
|
registers.writeRegister(Registers_::ACCEL_CONFIG2 & Registers_::WRITE_MASK,
|
||||||
|
|||||||
@ -15,10 +15,6 @@
|
|||||||
namespace Peripherals
|
namespace Peripherals
|
||||||
{
|
{
|
||||||
|
|
||||||
#define SKULLC_CONCAT_IMPL(x, y) x##y
|
|
||||||
#define SKULLC_CONCAT(x, y) SKULLC_CONCAT_IMPL(x, y)
|
|
||||||
#define SKULLC_TAG struct SKULLC_CONCAT(SkullCTag_, __COUNTER__)
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr const T& clamp(const T& v, const T& lo, const T& hi)
|
constexpr const T& clamp(const T& v, const T& lo, const T& hi)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,10 +1,16 @@
|
|||||||
cmake_minimum_required(VERSION 3.8 FATAL_ERROR)
|
cmake_minimum_required(VERSION 3.8 FATAL_ERROR)
|
||||||
|
|
||||||
option(TESTS_WITH_SANITIZERS "Enable sanitizers for tests." ON)
|
option(SKULLC_TESTS_WITH_SANITIZERS "Enable sanitizers for tests." ON)
|
||||||
|
|
||||||
find_package(Catch2 REQUIRED)
|
include(FetchContent)
|
||||||
|
|
||||||
if(TESTS_WITH_SANITIZERS)
|
FetchContent_Declare(Catch2
|
||||||
|
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
|
||||||
|
GIT_TAG v2.13.8
|
||||||
|
)
|
||||||
|
FetchContent_MakeAvailable(Catch2)
|
||||||
|
|
||||||
|
if(SKULLC_TESTS_WITH_SANITIZERS)
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-omit-frame-pointer -fsanitize=address -fsanitize=undefined -fno-sanitize-recover")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-omit-frame-pointer -fsanitize=address -fsanitize=undefined -fno-sanitize-recover")
|
||||||
set(CMAKE_LINKER_FLAGS "${CMAKE_LINKER_FLAGS} -fno-omit-frame-pointer -fsanitize=address -fsanitize=undefined -fno-sanitize-recover")
|
set(CMAKE_LINKER_FLAGS "${CMAKE_LINKER_FLAGS} -fno-omit-frame-pointer -fsanitize=address -fsanitize=undefined -fno-sanitize-recover")
|
||||||
endif()
|
endif()
|
||||||
@ -18,7 +24,12 @@ add_executable(tests
|
|||||||
rand.cpp
|
rand.cpp
|
||||||
fixedpoint.cpp
|
fixedpoint.cpp
|
||||||
pixelbuffer.cpp
|
pixelbuffer.cpp
|
||||||
pixelbuffer_effects.cpp function.cpp)
|
pixelbuffer_effects.cpp
|
||||||
|
function.cpp
|
||||||
|
assert_ndebug.cpp
|
||||||
|
assert.cpp
|
||||||
|
enum_helpers.cpp
|
||||||
|
)
|
||||||
|
|
||||||
target_link_libraries(tests
|
target_link_libraries(tests
|
||||||
PUBLIC
|
PUBLIC
|
||||||
@ -28,6 +39,12 @@ target_link_libraries(tests
|
|||||||
Catch2::Catch2
|
Catch2::Catch2
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set_target_properties(tests
|
||||||
|
PROPERTIES
|
||||||
|
CXX_STANDARD 17
|
||||||
|
)
|
||||||
|
|
||||||
|
list(APPEND CMAKE_MODULE_PATH ${catch2_SOURCE_DIR}/contrib)
|
||||||
include(CTest)
|
include(CTest)
|
||||||
include(Catch)
|
include(Catch)
|
||||||
catch_discover_tests(tests)
|
catch_discover_tests(tests)
|
||||||
68
Tests/assert.cpp
Normal file
68
Tests/assert.cpp
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
//
|
||||||
|
// Created by erki on 29.06.22.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
|
#ifdef NDEBUG
|
||||||
|
#undef NDEBUG
|
||||||
|
#define NDEBUG_WAS_SET
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "utility_assert.hpp"
|
||||||
|
|
||||||
|
#ifdef NDEBUG_WAS_SET
|
||||||
|
#define NDEBUG
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
bool assert_flag = false;
|
||||||
|
|
||||||
|
void assertCallback(const char*, const char*, const int)
|
||||||
|
{
|
||||||
|
assert_flag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}// namespace
|
||||||
|
|
||||||
|
TEST_CASE("Assert debug without NDEBUG gets triggered if check is false.", "[utility],[assert]")
|
||||||
|
{
|
||||||
|
assert_flag = false;
|
||||||
|
Utility::Assert::setHandler(assertCallback);
|
||||||
|
|
||||||
|
SKULLC_ASSERT_DEBUG(false);
|
||||||
|
|
||||||
|
CHECK(assert_flag == true);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Assert debug without NDEBUG doesn't get triggered if check is true.", "[utility],[assert]")
|
||||||
|
{
|
||||||
|
assert_flag = false;
|
||||||
|
Utility::Assert::setHandler(assertCallback);
|
||||||
|
|
||||||
|
SKULLC_ASSERT_DEBUG(true);
|
||||||
|
|
||||||
|
CHECK(assert_flag == false);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Assert safe without NDEBUG gets triggered if check is false.", "[utility],[assert]")
|
||||||
|
{
|
||||||
|
assert_flag = false;
|
||||||
|
Utility::Assert::setHandler(assertCallback);
|
||||||
|
|
||||||
|
SKULLC_ASSERT_SAFE(false);
|
||||||
|
|
||||||
|
CHECK(assert_flag == true);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Assert safe without NDEBUG doesn't get triggered if check is true.", "[utility],[assert]")
|
||||||
|
{
|
||||||
|
assert_flag = false;
|
||||||
|
Utility::Assert::setHandler(assertCallback);
|
||||||
|
|
||||||
|
SKULLC_ASSERT_SAFE(true);
|
||||||
|
|
||||||
|
CHECK(assert_flag == false);
|
||||||
|
}
|
||||||
62
Tests/assert_ndebug.cpp
Normal file
62
Tests/assert_ndebug.cpp
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
//
|
||||||
|
// Created by erki on 29.06.22.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
#define NDEBUG
|
||||||
|
#define NDEBUG_WAS_NOT_DEFINED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "utility_assert.hpp"
|
||||||
|
|
||||||
|
#ifdef NDEBUG_WAS_NOT_DEFINED
|
||||||
|
#undef NDEBUG
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
bool assert_flag = false;
|
||||||
|
|
||||||
|
void assertCallback(const char*, const char*, const int)
|
||||||
|
{
|
||||||
|
assert_flag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}// namespace
|
||||||
|
|
||||||
|
TEST_CASE("Assert debug with NDEBUG is a null-opt.", "[utility],[assert]")
|
||||||
|
{
|
||||||
|
assert_flag = false;
|
||||||
|
Utility::Assert::setHandler(assertCallback);
|
||||||
|
|
||||||
|
int check_number = 0;
|
||||||
|
SKULLC_ASSERT_DEBUG(check_number++ == 0);
|
||||||
|
|
||||||
|
CHECK(check_number == 0);
|
||||||
|
CHECK(assert_flag == false);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Assert safe with NDEBUG gets triggered if check is false.", "[utility],[assert]")
|
||||||
|
{
|
||||||
|
assert_flag = false;
|
||||||
|
Utility::Assert::setHandler(assertCallback);
|
||||||
|
|
||||||
|
int check_number = 0;
|
||||||
|
SKULLC_ASSERT_SAFE(check_number++ == 1);
|
||||||
|
|
||||||
|
CHECK(check_number == 1);
|
||||||
|
CHECK(assert_flag == true);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Assert safe with NDEBUG doesn't get triggered if check is true.", "[utility],[assert]")
|
||||||
|
{
|
||||||
|
assert_flag = false;
|
||||||
|
Utility::Assert::setHandler(assertCallback);
|
||||||
|
|
||||||
|
SKULLC_ASSERT_SAFE(true);
|
||||||
|
|
||||||
|
CHECK(assert_flag == false);
|
||||||
|
}
|
||||||
41
Tests/enum_helpers.cpp
Normal file
41
Tests/enum_helpers.cpp
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
//
|
||||||
|
// Created by erki on 15.07.22.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
|
#include "utility_enum_helpers.hpp"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
enum class TestEnum : unsigned
|
||||||
|
{
|
||||||
|
FLAG_0 = 1,
|
||||||
|
FLAG_1 = 2,
|
||||||
|
FLAG_2 = 4
|
||||||
|
};
|
||||||
|
|
||||||
|
SKULLC_ENUM_DECLARE_BITFLAG_OPERATORS(TestEnum)
|
||||||
|
|
||||||
|
}// namespace
|
||||||
|
|
||||||
|
TEST_CASE("OR operator works as expected.", "[utility],[enum_helpers]")
|
||||||
|
{
|
||||||
|
const TestEnum a = TestEnum::FLAG_0;
|
||||||
|
const TestEnum b = TestEnum::FLAG_1;
|
||||||
|
|
||||||
|
const TestEnum sum = a | b;
|
||||||
|
CHECK(unsigned(sum) == 3u);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("AND operator works as expected.", "[utility],[enum_helpers]")
|
||||||
|
{
|
||||||
|
const TestEnum a = TestEnum::FLAG_0 | TestEnum::FLAG_1;
|
||||||
|
|
||||||
|
const TestEnum masked_1 = a & TestEnum::FLAG_0;
|
||||||
|
CHECK(masked_1 == TestEnum::FLAG_0);
|
||||||
|
|
||||||
|
const TestEnum masked_2 = a & TestEnum::FLAG_2;
|
||||||
|
CHECK(masked_2 != TestEnum::FLAG_2);
|
||||||
|
}
|
||||||
@ -5,6 +5,7 @@
|
|||||||
#include <catch2/catch.hpp>
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
#include <utility_function.hpp>
|
#include <utility_function.hpp>
|
||||||
|
#include <utility_tag.hpp>
|
||||||
|
|
||||||
TEST_CASE("Function calls function appropriately.", "[utility],[function]")
|
TEST_CASE("Function calls function appropriately.", "[utility],[function]")
|
||||||
{
|
{
|
||||||
@ -38,6 +39,26 @@ TEST_CASE("Function passes arguments appropriately.", "[utility],[function]")
|
|||||||
REQUIRE(bool_to_set == true);
|
REQUIRE(bool_to_set == true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Function works with toStaticFunction.", "[utility],[function]")
|
||||||
|
{
|
||||||
|
static int int_to_set = 0;
|
||||||
|
static bool bool_to_set = false;
|
||||||
|
|
||||||
|
auto func_to_call = [](const int i, const bool b) {
|
||||||
|
int_to_set = i;
|
||||||
|
bool_to_set = b;
|
||||||
|
};
|
||||||
|
|
||||||
|
Utility::Function<void(int, bool)> function(func_to_call);
|
||||||
|
using signature = void (*)(int, bool);
|
||||||
|
|
||||||
|
signature func_pointer = function.toStaticFunction<SKULLC_TAG>();
|
||||||
|
func_pointer(10, true);
|
||||||
|
|
||||||
|
REQUIRE(int_to_set == 10);
|
||||||
|
REQUIRE(bool_to_set == true);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("FunctionOwned calls function appropriately.", "[utility],[function]")
|
TEST_CASE("FunctionOwned calls function appropriately.", "[utility],[function]")
|
||||||
{
|
{
|
||||||
struct S
|
struct S
|
||||||
@ -82,3 +103,29 @@ TEST_CASE("FunctionOwned passes arguments appropriately.", "[utility],[function]
|
|||||||
REQUIRE(subject.int_to_set == 10);
|
REQUIRE(subject.int_to_set == 10);
|
||||||
REQUIRE(subject.bool_to_set == false);
|
REQUIRE(subject.bool_to_set == false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("FunctionOwned works with toStaticFunction.", "[utility],[function]")
|
||||||
|
{
|
||||||
|
struct S
|
||||||
|
{
|
||||||
|
int int_to_set = 0;
|
||||||
|
bool bool_to_set = true;
|
||||||
|
|
||||||
|
void toCall(const int i, const bool b)
|
||||||
|
{
|
||||||
|
int_to_set = i;
|
||||||
|
bool_to_set = b;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
S subject;
|
||||||
|
|
||||||
|
Utility::FunctionOwned<S, void(int, bool)> function(subject, &S::toCall);
|
||||||
|
using signature = void (*)(int, bool);
|
||||||
|
|
||||||
|
signature func_pointer = function.toStaticFunction<SKULLC_TAG>();
|
||||||
|
func_pointer(10, true);
|
||||||
|
|
||||||
|
REQUIRE(subject.int_to_set == 10);
|
||||||
|
REQUIRE(subject.bool_to_set == true);
|
||||||
|
}
|
||||||
|
|||||||
@ -15,15 +15,15 @@
|
|||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
|
||||||
#include "threads_primitivethread.hpp"
|
#include <threads_actor_thread.hpp>
|
||||||
#include "threads_signal.hpp"
|
#include <threads_iactor.hpp>
|
||||||
#include "threads_timer.hpp"
|
#include <threads_signal.hpp>
|
||||||
|
|
||||||
namespace Threads
|
namespace Threads
|
||||||
{
|
{
|
||||||
|
|
||||||
template<typename CRTP, typename... Ts>
|
template<typename CRTP, typename... Ts>
|
||||||
class Actor
|
class Actor : public IActor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using value_type = std::variant<Ts...>;
|
using value_type = std::variant<Ts...>;
|
||||||
@ -31,14 +31,11 @@ public:
|
|||||||
static_assert(std::is_default_constructible_v<value_type>, "Ts must be default constructible.");
|
static_assert(std::is_default_constructible_v<value_type>, "Ts must be default constructible.");
|
||||||
static_assert(std::is_trivially_copyable_v<value_type>, "Ts must be trivially copyable.");
|
static_assert(std::is_trivially_copyable_v<value_type>, "Ts must be trivially copyable.");
|
||||||
|
|
||||||
Actor(const std::uint32_t queue_size, const char* name, const osPriority_t priority, const std::uint32_t stack_size)
|
Actor() : IActor(sizeof(value_type)),
|
||||||
: thread_(&Actor<CRTP, Ts...>::threadHandler_, this, name, priority, stack_size),
|
signal_(this)
|
||||||
msg_queue_(xQueueCreate(queue_size, sizeof(value_type))), signal_(this)
|
{}
|
||||||
{
|
|
||||||
assert(msg_queue_);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~Actor() {}
|
~Actor() override {}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct Signal : Signallable<T>
|
struct Signal : Signallable<T>
|
||||||
@ -59,17 +56,13 @@ public:
|
|||||||
void emit(const T& data) override
|
void emit(const T& data) override
|
||||||
{
|
{
|
||||||
parent::value_type to_send = data;
|
parent::value_type to_send = data;
|
||||||
xQueueSend(q_->msg_queue_, &to_send, 0);
|
q_->dispatchEvent(to_send);
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseType_t emitFromIsr(const T& data) override
|
BaseType_t emitFromIsr(const T& data) override
|
||||||
{
|
{
|
||||||
parent::value_type to_send = data;
|
parent::value_type to_send = data;
|
||||||
BaseType_t was_awoken = pdFALSE;
|
return q_->dispatchEventFromIsr(to_send);
|
||||||
|
|
||||||
xQueueSendFromISR(q_->msg_queue_, &to_send, &was_awoken);
|
|
||||||
|
|
||||||
return was_awoken;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -97,13 +90,12 @@ public:
|
|||||||
return &signal_;
|
return &signal_;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
void dispatchSignal(const char* data) final
|
||||||
virtual void init() = 0;
|
{
|
||||||
|
dispatchImpl_(data);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PrimitiveThread thread_;
|
|
||||||
QueueHandle_t msg_queue_;
|
|
||||||
|
|
||||||
struct Visitor_
|
struct Visitor_
|
||||||
{
|
{
|
||||||
using parent = Actor<CRTP, Ts...>;
|
using parent = Actor<CRTP, Ts...>;
|
||||||
@ -121,113 +113,15 @@ private:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void operator()()
|
void dispatchImpl_(const char* data)
|
||||||
{
|
{
|
||||||
init();
|
const value_type* signal_data = reinterpret_cast<const value_type*>(data);
|
||||||
|
std::visit(Visitor_{this}, *signal_data);
|
||||||
value_type data{};
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
const BaseType_t got = xQueueReceive(msg_queue_, &data, portMAX_DELAY);
|
|
||||||
|
|
||||||
if (got == pdTRUE)
|
|
||||||
{
|
|
||||||
std::visit(Visitor_{this}, data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void threadHandler_(void* d)
|
|
||||||
{
|
|
||||||
auto* dd = static_cast<Actor<CRTP, Ts...>*>(d);
|
|
||||||
(*dd)();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Signal<value_type> signal_;
|
Signal<value_type> signal_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename CRTP>
|
|
||||||
class Actor<CRTP, void>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using value_type = void;
|
|
||||||
|
|
||||||
Actor(const std::uint32_t queue_size, const char* name, const osPriority_t priority, const std::uint32_t stack_size)
|
|
||||||
: thread_([](void* d) {
|
|
||||||
auto* dd = static_cast<Actor<CRTP, value_type>*>(d);
|
|
||||||
(*dd)();
|
|
||||||
},
|
|
||||||
this, name, priority, stack_size),
|
|
||||||
msg_queue_(xQueueCreate(queue_size, sizeof(int))), signal_(*this)
|
|
||||||
{
|
|
||||||
assert(msg_queue_);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~Actor() {}
|
|
||||||
|
|
||||||
Signallable<value_type>* getSignal()
|
|
||||||
{
|
|
||||||
return &signal_;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void init() = 0;
|
|
||||||
|
|
||||||
private:
|
|
||||||
PrimitiveThread thread_;
|
|
||||||
QueueHandle_t msg_queue_;
|
|
||||||
|
|
||||||
void operator()()
|
|
||||||
{
|
|
||||||
init();
|
|
||||||
|
|
||||||
int data;
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
const BaseType_t got = xQueueReceive(msg_queue_, &data, portMAX_DELAY);
|
|
||||||
|
|
||||||
if (got == pdTRUE)
|
|
||||||
{
|
|
||||||
auto* crtp = static_cast<CRTP*>(this);
|
|
||||||
crtp->onSignal();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
friend struct Signal_;
|
|
||||||
|
|
||||||
struct Signal_ : Signallable<value_type>
|
|
||||||
{
|
|
||||||
using parent = Actor<CRTP, void>;
|
|
||||||
parent& q;
|
|
||||||
|
|
||||||
explicit Signal_(parent& q)
|
|
||||||
: q(q)
|
|
||||||
{}
|
|
||||||
|
|
||||||
void emit() override
|
|
||||||
{
|
|
||||||
const int data = 0;
|
|
||||||
|
|
||||||
xQueueSend(q.msg_queue_, &data, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
BaseType_t emitFromIsr() override
|
|
||||||
{
|
|
||||||
const int data = 0;
|
|
||||||
|
|
||||||
BaseType_t was_awoken = pdFALSE;
|
|
||||||
xQueueSendFromISR(q.msg_queue_, &data, &was_awoken);
|
|
||||||
|
|
||||||
return was_awoken;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Signal_ signal_;
|
|
||||||
};
|
|
||||||
|
|
||||||
}// namespace Threads
|
}// namespace Threads
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
50
Threads/Inc/threads_actor_thread.hpp
Normal file
50
Threads/Inc/threads_actor_thread.hpp
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* threads_actor_thread.hpp
|
||||||
|
*
|
||||||
|
* Created on: Nov 13, 2021
|
||||||
|
* Author: erki
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SKULLC_THREADS_ACTOR_THREAD_HPP_
|
||||||
|
#define SKULLC_THREADS_ACTOR_THREAD_HPP_
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include <freertos_os2.h>
|
||||||
|
#include <queue.h>
|
||||||
|
|
||||||
|
#include <threads_thread.hpp>
|
||||||
|
|
||||||
|
namespace Threads
|
||||||
|
{
|
||||||
|
|
||||||
|
class IActor;
|
||||||
|
|
||||||
|
class ActorThread : public Thread<ActorThread>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ActorThread(const std::size_t queue_length, const char* name, const osPriority_t priority, const std::uint32_t stack_size);
|
||||||
|
|
||||||
|
void operator()();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void init_();
|
||||||
|
void doMessageLoop_();
|
||||||
|
|
||||||
|
friend class IActor;
|
||||||
|
std::size_t acceptActor_(IActor* actor);
|
||||||
|
|
||||||
|
std::size_t queue_length_;
|
||||||
|
std::size_t queue_item_length_ = 0;
|
||||||
|
|
||||||
|
QueueHandle_t queue_ = nullptr;
|
||||||
|
char* rx_buffer_ = nullptr;
|
||||||
|
char* tx_buffer_ = nullptr;
|
||||||
|
std::array<IActor*, 32> actors_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}// namespace Threads
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* SKULLC_THREADS_ACTOR_THREAD_HPP_ */
|
||||||
68
Threads/Inc/threads_iactor.hpp
Normal file
68
Threads/Inc/threads_iactor.hpp
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* threads_iactor.hpp
|
||||||
|
*
|
||||||
|
* Created on: Nov 14, 2021
|
||||||
|
* Author: erki
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SKULLC_THREADS_IACTOR_HPP_
|
||||||
|
#define SKULLC_THREADS_IACTOR_HPP_
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include <freertos_os2.h>
|
||||||
|
|
||||||
|
namespace Threads
|
||||||
|
{
|
||||||
|
|
||||||
|
class ActorThread;
|
||||||
|
|
||||||
|
class IActor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
IActor(const std::size_t signal_size)
|
||||||
|
: signal_size_(signal_size)
|
||||||
|
{}
|
||||||
|
|
||||||
|
virtual ~IActor() {}
|
||||||
|
|
||||||
|
virtual void init() = 0;
|
||||||
|
virtual void dispatchSignal(const char* data) = 0;
|
||||||
|
|
||||||
|
void moveToThread(ActorThread* thread);
|
||||||
|
|
||||||
|
std::size_t actorIndex() const
|
||||||
|
{
|
||||||
|
return actor_index_;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t signalSize() const
|
||||||
|
{
|
||||||
|
return signal_size_;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
template<typename T>
|
||||||
|
void dispatchEvent(const T& data)
|
||||||
|
{
|
||||||
|
dispatchEventImpl_(&data, sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
BaseType_t dispatchEventFromIsr(const T& data)
|
||||||
|
{
|
||||||
|
return dispatchEventFromIsrImpl_(&data, sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ActorThread* parent_thread_ = nullptr;
|
||||||
|
std::size_t actor_index_ = 0;
|
||||||
|
std::size_t signal_size_;
|
||||||
|
|
||||||
|
void dispatchEventImpl_(const void* data, const std::size_t data_size);
|
||||||
|
BaseType_t dispatchEventFromIsrImpl_(const void* data, const std::size_t data_size);
|
||||||
|
};
|
||||||
|
|
||||||
|
}// namespace Threads
|
||||||
|
|
||||||
|
#endif /* SKULLC_THREADS_IACTOR_HPP_ */
|
||||||
110
Threads/Src/threads_actor_thread.cpp
Normal file
110
Threads/Src/threads_actor_thread.cpp
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
* threads_actor_thread.cpp
|
||||||
|
*
|
||||||
|
* Created on: Nov 13, 2021
|
||||||
|
* Author: erki
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "threads_actor_thread.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include <threads_iactor.hpp>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
struct SignalMessage
|
||||||
|
{
|
||||||
|
std::size_t actor_index;
|
||||||
|
const char* data;
|
||||||
|
|
||||||
|
static SignalMessage fromData(char* data)
|
||||||
|
{
|
||||||
|
SignalMessage message;
|
||||||
|
std::memcpy(&message.actor_index, data, sizeof(message.actor_index));
|
||||||
|
message.data = data + sizeof(message.actor_index);
|
||||||
|
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}// namespace
|
||||||
|
|
||||||
|
namespace Threads
|
||||||
|
{
|
||||||
|
|
||||||
|
ActorThread::ActorThread(const std::size_t queue_length, const char* name, const osPriority_t priority, const std::uint32_t stack_size)
|
||||||
|
: Thread<ActorThread>(name, priority, stack_size), queue_length_(queue_length), queue_(nullptr)
|
||||||
|
{
|
||||||
|
actors_.fill(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActorThread::operator()()
|
||||||
|
{
|
||||||
|
init_();
|
||||||
|
|
||||||
|
osThreadYield();
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
doMessageLoop_();
|
||||||
|
|
||||||
|
osThreadYield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActorThread::init_()
|
||||||
|
{
|
||||||
|
for (IActor* actor : actors_)
|
||||||
|
{
|
||||||
|
if (actor != nullptr)
|
||||||
|
{
|
||||||
|
queue_item_length_ = std::max(queue_item_length_, actor->signalSize());
|
||||||
|
|
||||||
|
actor->init();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
queue_ = xQueueCreate(queue_length_, queue_item_length_ + sizeof(std::size_t));
|
||||||
|
assert(queue_ != nullptr);
|
||||||
|
|
||||||
|
rx_buffer_ = new char[queue_item_length_ + sizeof(std::size_t)];
|
||||||
|
tx_buffer_ = new char[queue_item_length_ + sizeof(std::size_t)];
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActorThread::doMessageLoop_()
|
||||||
|
{
|
||||||
|
const BaseType_t has_data = xQueueReceive(queue_, rx_buffer_, portMAX_DELAY);
|
||||||
|
|
||||||
|
if (has_data == pdTRUE)
|
||||||
|
{
|
||||||
|
const SignalMessage message = SignalMessage::fromData(rx_buffer_);
|
||||||
|
assert(message.actor_index <= actors_.size());
|
||||||
|
|
||||||
|
IActor* actor = actors_[message.actor_index];
|
||||||
|
assert(actor != nullptr);
|
||||||
|
|
||||||
|
actor->dispatchSignal(message.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t ActorThread::acceptActor_(IActor* actor)
|
||||||
|
{
|
||||||
|
for (auto it = actors_.begin(); it != actors_.end(); ++it)
|
||||||
|
{
|
||||||
|
if (*it == nullptr)
|
||||||
|
{
|
||||||
|
*it = actor;
|
||||||
|
return std::distance(actors_.begin(), it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(false);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}// namespace Threads
|
||||||
55
Threads/Src/threads_iactor.cpp
Normal file
55
Threads/Src/threads_iactor.cpp
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* threads_iactor.cpp
|
||||||
|
*
|
||||||
|
* Created on: Nov 14, 2021
|
||||||
|
* Author: erki
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "threads_iactor.hpp"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include <queue.h>
|
||||||
|
|
||||||
|
#include "threads_actor_thread.hpp"
|
||||||
|
|
||||||
|
namespace Threads
|
||||||
|
{
|
||||||
|
|
||||||
|
void IActor::moveToThread(ActorThread* thread)
|
||||||
|
{
|
||||||
|
actor_index_ = thread->acceptActor_(this);
|
||||||
|
parent_thread_ = thread;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IActor::dispatchEventImpl_(const void* data, const std::size_t data_size)
|
||||||
|
{
|
||||||
|
taskENTER_CRITICAL();
|
||||||
|
|
||||||
|
std::memcpy(parent_thread_->tx_buffer_, &actor_index_, sizeof(std::size_t));
|
||||||
|
char* data_dest = parent_thread_->tx_buffer_ + sizeof(std::size_t);
|
||||||
|
std::memcpy(data_dest, data, data_size);
|
||||||
|
|
||||||
|
xQueueSend(parent_thread_->queue_, parent_thread_->tx_buffer_, 0);
|
||||||
|
|
||||||
|
taskEXIT_CRITICAL();
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseType_t IActor::dispatchEventFromIsrImpl_(const void* data, const std::size_t data_size)
|
||||||
|
{
|
||||||
|
const auto isr_data = taskENTER_CRITICAL_FROM_ISR();
|
||||||
|
|
||||||
|
std::memcpy(parent_thread_->tx_buffer_, &actor_index_, sizeof(std::size_t));
|
||||||
|
char* data_dest = parent_thread_->tx_buffer_ + sizeof(std::size_t);
|
||||||
|
std::memcpy(data_dest, data, data_size);
|
||||||
|
|
||||||
|
BaseType_t task_awoken = pdFALSE;
|
||||||
|
xQueueSendFromISR(parent_thread_->queue_, parent_thread_->tx_buffer_, &task_awoken);
|
||||||
|
|
||||||
|
taskEXIT_CRITICAL_FROM_ISR(isr_data);
|
||||||
|
|
||||||
|
return task_awoken;
|
||||||
|
}
|
||||||
|
|
||||||
|
}// namespace Threads
|
||||||
@ -1,13 +1,9 @@
|
|||||||
cmake_minimum_required(VERSION 3.8 FATAL_ERROR)
|
cmake_minimum_required(VERSION 3.8 FATAL_ERROR)
|
||||||
|
|
||||||
#if(WITH_HAL)
|
|
||||||
# set(additional_sources
|
|
||||||
# )
|
|
||||||
#endif()
|
|
||||||
|
|
||||||
add_library(utility STATIC
|
add_library(utility STATIC
|
||||||
Src/utility_logging.cpp
|
Src/utility_logging.cpp
|
||||||
Src/utility_rand.cpp
|
Src/utility_rand.cpp
|
||||||
|
Src/utility_assert.cpp
|
||||||
${additional_sources}
|
${additional_sources}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -18,5 +14,9 @@ target_include_directories(utility
|
|||||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/Inc>
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/Inc>
|
||||||
$<INSTALL_INTERFACE:include>
|
$<INSTALL_INTERFACE:include>
|
||||||
)
|
)
|
||||||
|
set_target_properties(utility
|
||||||
|
PROPERTIES
|
||||||
|
CXX_STANDARD 17
|
||||||
|
)
|
||||||
|
|
||||||
skullc_install_packages(skullc utility ${version})
|
skullc_install_packages(skullc utility ${SKULLC_VERSION})
|
||||||
|
|||||||
33
Utility/Inc/utility_assert.hpp
Normal file
33
Utility/Inc/utility_assert.hpp
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
//
|
||||||
|
// Created by erki on 29.06.22.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef SKULLC_UTILITY_ASSERT_HPP_
|
||||||
|
#define SKULLC_UTILITY_ASSERT_HPP_
|
||||||
|
|
||||||
|
namespace Utility::Assert::Detail
|
||||||
|
{
|
||||||
|
|
||||||
|
void assertImpl(const char* expression, const char* file, const int line);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
#define SKULLC_ASSERT_DEBUG(e) (!(e) ? Utility::Assert::Detail::assertImpl(#e, __FILE__, __LINE__) : ((void) 0))
|
||||||
|
#else
|
||||||
|
#define SKULLC_ASSERT_DEBUG(e)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SKULLC_ASSERT_SAFE(e) (!(e) ? Utility::Assert::Detail::assertImpl(#e, __FILE__, __LINE__) : ((void) 0))
|
||||||
|
|
||||||
|
namespace Utility::Assert
|
||||||
|
{
|
||||||
|
|
||||||
|
using assert_cb = void (*)(const char* expression, const char* file, const int line);
|
||||||
|
|
||||||
|
void setHandler(assert_cb callback);
|
||||||
|
assert_cb getHandler();
|
||||||
|
|
||||||
|
}// namespace Utility::Assert
|
||||||
|
|
||||||
|
#endif// SKULLC_UTILITY_ASSERT_HPP_
|
||||||
22
Utility/Inc/utility_enum_helpers.hpp
Normal file
22
Utility/Inc/utility_enum_helpers.hpp
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
//
|
||||||
|
// Created by erki on 15.07.22.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef SKULLC_UTILITY_ENUM_HELPERS_HPP_
|
||||||
|
#define SKULLC_UTILITY_ENUM_HELPERS_HPP_
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#define SKULLC_ENUM_DECLARE_BITFLAG_OPERATORS(E) \
|
||||||
|
inline E operator|(const E& lhs, const E& rhs) \
|
||||||
|
{ \
|
||||||
|
using T = std::underlying_type_t<E>; \
|
||||||
|
return static_cast<E>(static_cast<T>(lhs) | static_cast<T>(rhs)); \
|
||||||
|
} \
|
||||||
|
inline E operator&(const E& lhs, const E& rhs) \
|
||||||
|
{ \
|
||||||
|
using T = std::underlying_type_t<E>; \
|
||||||
|
return static_cast<E>(static_cast<T>(lhs) & static_cast<T>(rhs)); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif//SKULLC_UTILITY_ENUM_HELPERS_HPP_
|
||||||
@ -8,6 +8,8 @@
|
|||||||
#ifndef SKULLC_UTILITY_FUNCTION_HPP_
|
#ifndef SKULLC_UTILITY_FUNCTION_HPP_
|
||||||
#define SKULLC_UTILITY_FUNCTION_HPP_
|
#define SKULLC_UTILITY_FUNCTION_HPP_
|
||||||
|
|
||||||
|
#include <utility_assert.hpp>
|
||||||
|
|
||||||
namespace Utility
|
namespace Utility
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -19,11 +21,19 @@ class IFunction<R(Args...)>
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using result_type = R;
|
using result_type = R;
|
||||||
|
using static_signature = R (*)(Args...);
|
||||||
|
|
||||||
virtual ~IFunction()
|
virtual ~IFunction()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
virtual result_type operator()(Args... args) = 0;
|
virtual result_type operator()(Args... args) = 0;
|
||||||
|
|
||||||
|
template<typename Tag>
|
||||||
|
static_signature toStaticFunction()
|
||||||
|
{
|
||||||
|
static decltype(this) h = this;
|
||||||
|
return +[](Args... args) { (*h)(args...); };
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class>
|
template<class>
|
||||||
@ -41,7 +51,7 @@ public:
|
|||||||
explicit Function(signature callable)
|
explicit Function(signature callable)
|
||||||
: callable_(callable)
|
: callable_(callable)
|
||||||
{
|
{
|
||||||
assert(callable_);
|
SKULLC_ASSERT_DEBUG(callable_);
|
||||||
}
|
}
|
||||||
|
|
||||||
~Function() override
|
~Function() override
|
||||||
@ -73,7 +83,7 @@ public:
|
|||||||
explicit FunctionOwned(source& src, signature callable)
|
explicit FunctionOwned(source& src, signature callable)
|
||||||
: src_(&src), callable_(callable)
|
: src_(&src), callable_(callable)
|
||||||
{
|
{
|
||||||
assert(callable_);
|
SKULLC_ASSERT_DEBUG(callable_);
|
||||||
}
|
}
|
||||||
|
|
||||||
~FunctionOwned() override
|
~FunctionOwned() override
|
||||||
|
|||||||
@ -8,8 +8,11 @@
|
|||||||
#ifndef SKULLC_UTILITY_STATICPOINTER_HPP_
|
#ifndef SKULLC_UTILITY_STATICPOINTER_HPP_
|
||||||
#define SKULLC_UTILITY_STATICPOINTER_HPP_
|
#define SKULLC_UTILITY_STATICPOINTER_HPP_
|
||||||
|
|
||||||
|
#include <new>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#include <utility_assert.hpp>
|
||||||
|
|
||||||
namespace Utility
|
namespace Utility
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -57,6 +60,18 @@ struct StaticPointer
|
|||||||
return initialized_;
|
return initialized_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
value_type* get()
|
||||||
|
{
|
||||||
|
SKULLC_ASSERT_DEBUG(initialized_);
|
||||||
|
return reinterpret_cast<value_type*>(storage);
|
||||||
|
}
|
||||||
|
|
||||||
|
const value_type* get() const
|
||||||
|
{
|
||||||
|
SKULLC_ASSERT_DEBUG(initialized_);
|
||||||
|
return reinterpret_cast<const value_type*>(storage);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool initialized_ = false;
|
bool initialized_ = false;
|
||||||
};
|
};
|
||||||
|
|||||||
12
Utility/Inc/utility_tag.hpp
Normal file
12
Utility/Inc/utility_tag.hpp
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
//
|
||||||
|
// Created by erki on 26.06.22.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef SKULLC_UTILITY_TAG_HPP_
|
||||||
|
#define SKULLC_UTILITY_TAG_HPP_
|
||||||
|
|
||||||
|
#define SKULLC_CONCAT_IMPL(x, y) x##y
|
||||||
|
#define SKULLC_CONCAT(x, y) SKULLC_CONCAT_IMPL(x, y)
|
||||||
|
#define SKULLC_TAG struct SKULLC_CONCAT(SkullCTag_, __COUNTER__)
|
||||||
|
|
||||||
|
#endif// SKULLC_UTILITY_TAG_HPP_
|
||||||
42
Utility/Src/utility_assert.cpp
Normal file
42
Utility/Src/utility_assert.cpp
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
//
|
||||||
|
// Created by erki on 29.06.22.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "utility_assert.hpp"
|
||||||
|
|
||||||
|
#include <exception>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
Utility::Assert::assert_cb INSTALLED_HANDLER = nullptr;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Utility::Assert
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace Detail
|
||||||
|
{
|
||||||
|
|
||||||
|
void assertImpl(const char* expression, const char* file, const int line)
|
||||||
|
{
|
||||||
|
if (INSTALLED_HANDLER)
|
||||||
|
INSTALLED_HANDLER(expression, file, line);
|
||||||
|
else
|
||||||
|
std::terminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
}// namespace Detail
|
||||||
|
|
||||||
|
void setHandler(assert_cb callback)
|
||||||
|
{
|
||||||
|
INSTALLED_HANDLER = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_cb getHandler()
|
||||||
|
{
|
||||||
|
return INSTALLED_HANDLER;
|
||||||
|
}
|
||||||
|
|
||||||
|
}// namespace Utility::Assert
|
||||||
Loading…
x
Reference in New Issue
Block a user