From 43bc8d8265b2a50b1019f4a359706eafe5041b76 Mon Sep 17 00:00:00 2001 From: Erki Date: Sun, 14 Nov 2021 01:31:01 +0200 Subject: [PATCH 01/17] Threads: Actors are now composable over threads --- Threads/Inc/threads_actor.hpp | 140 ++++----------------------- Threads/Inc/threads_actor_thread.hpp | 50 ++++++++++ Threads/Inc/threads_iactor.hpp | 68 +++++++++++++ Threads/Src/threads_actor_thread.cpp | 110 +++++++++++++++++++++ Threads/Src/threads_iactor.cpp | 55 +++++++++++ 5 files changed, 300 insertions(+), 123 deletions(-) create mode 100644 Threads/Inc/threads_actor_thread.hpp create mode 100644 Threads/Inc/threads_iactor.hpp create mode 100644 Threads/Src/threads_actor_thread.cpp create mode 100644 Threads/Src/threads_iactor.cpp diff --git a/Threads/Inc/threads_actor.hpp b/Threads/Inc/threads_actor.hpp index 41037a1..fb81899 100644 --- a/Threads/Inc/threads_actor.hpp +++ b/Threads/Inc/threads_actor.hpp @@ -15,15 +15,15 @@ #include #include -#include "threads_primitivethread.hpp" -#include "threads_signal.hpp" -#include "threads_timer.hpp" +#include +#include +#include namespace Threads { template -class Actor +class Actor : public IActor { public: using value_type = std::variant; @@ -31,14 +31,11 @@ public: static_assert(std::is_default_constructible_v, "Ts must be default constructible."); static_assert(std::is_trivially_copyable_v, "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) - : thread_(&Actor::threadHandler_, this, name, priority, stack_size), - msg_queue_(xQueueCreate(queue_size, sizeof(value_type))), signal_(this) - { - assert(msg_queue_); - } + Actor() : IActor(sizeof(value_type)), + signal_(this) + {} - virtual ~Actor() {} + ~Actor() override {} template struct Signal : Signallable @@ -59,17 +56,13 @@ public: void emit(const T& data) override { parent::value_type to_send = data; - xQueueSend(q_->msg_queue_, &to_send, 0); + q_->dispatchEvent(to_send); } BaseType_t emitFromIsr(const T& data) override { parent::value_type to_send = data; - BaseType_t was_awoken = pdFALSE; - - xQueueSendFromISR(q_->msg_queue_, &to_send, &was_awoken); - - return was_awoken; + return q_->dispatchEventFromIsr(to_send); } private: @@ -97,13 +90,12 @@ public: return &signal_; } -protected: - virtual void init() = 0; + void dispatchSignal(const char* data) final + { + dispatchImpl_(data); + } private: - PrimitiveThread thread_; - QueueHandle_t msg_queue_; - struct Visitor_ { using parent = Actor; @@ -121,113 +113,15 @@ private: } }; - void operator()() + void dispatchImpl_(const char* data) { - init(); - - 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*>(d); - (*dd)(); + const value_type* signal_data = reinterpret_cast(data); + std::visit(Visitor_{this}, *signal_data); } Signal signal_; }; -template -class Actor -{ -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*>(d); - (*dd)(); - }, - this, name, priority, stack_size), - msg_queue_(xQueueCreate(queue_size, sizeof(int))), signal_(*this) - { - assert(msg_queue_); - } - - virtual ~Actor() {} - - Signallable* 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(this); - crtp->onSignal(); - } - } - } - - friend struct Signal_; - - struct Signal_ : Signallable - { - using parent = Actor; - 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 diff --git a/Threads/Inc/threads_actor_thread.hpp b/Threads/Inc/threads_actor_thread.hpp new file mode 100644 index 0000000..4929b66 --- /dev/null +++ b/Threads/Inc/threads_actor_thread.hpp @@ -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 +#include + +#include +#include + +#include + +namespace Threads +{ + +class IActor; + +class ActorThread : public Thread +{ +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 actors_; +}; + +}// namespace Threads + + +#endif /* SKULLC_THREADS_ACTOR_THREAD_HPP_ */ diff --git a/Threads/Inc/threads_iactor.hpp b/Threads/Inc/threads_iactor.hpp new file mode 100644 index 0000000..011f448 --- /dev/null +++ b/Threads/Inc/threads_iactor.hpp @@ -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 + +#include + +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 + void dispatchEvent(const T& data) + { + dispatchEventImpl_(&data, sizeof(T)); + } + + template + 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_ */ diff --git a/Threads/Src/threads_actor_thread.cpp b/Threads/Src/threads_actor_thread.cpp new file mode 100644 index 0000000..c68812d --- /dev/null +++ b/Threads/Src/threads_actor_thread.cpp @@ -0,0 +1,110 @@ +/* + * threads_actor_thread.cpp + * + * Created on: Nov 13, 2021 + * Author: erki + */ + + +#include "threads_actor_thread.hpp" + +#include +#include +#include + +#include + +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(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 diff --git a/Threads/Src/threads_iactor.cpp b/Threads/Src/threads_iactor.cpp new file mode 100644 index 0000000..3131010 --- /dev/null +++ b/Threads/Src/threads_iactor.cpp @@ -0,0 +1,55 @@ +/* + * threads_iactor.cpp + * + * Created on: Nov 14, 2021 + * Author: erki + */ + + +#include "threads_iactor.hpp" + +#include + +#include + +#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 From 0d1ea1c1c240967f99f2d8bafd1959806aefebf6 Mon Sep 17 00:00:00 2001 From: Erki Date: Sun, 14 Nov 2021 01:31:12 +0200 Subject: [PATCH 02/17] Peripherals: format ICM file --- Peripherals/Inc/peripherals_imu_icm.hpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Peripherals/Inc/peripherals_imu_icm.hpp b/Peripherals/Inc/peripherals_imu_icm.hpp index 76f71f8..f8afa95 100644 --- a/Peripherals/Inc/peripherals_imu_icm.hpp +++ b/Peripherals/Inc/peripherals_imu_icm.hpp @@ -72,17 +72,17 @@ public: // rate = 1KHz, temp filter = 42 hal::delay(10); - 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, - 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, - new_accel_config); + new_accel_config); -// setGyroscopeScale(scale_gyro_); -// -// setAccelerometerScale(scale_accel_); + // setGyroscopeScale(scale_gyro_); + // + // setAccelerometerScale(scale_accel_); // ACCEL_FCHOICE_B = 0, A_DLPF_CFG = 3 filter=44.8/61.5 rate=1KHz registers.writeRegister(Registers_::ACCEL_CONFIG2 & Registers_::WRITE_MASK, From 88aa3087fe6a3b3b703d635174ae31f3286a8790 Mon Sep 17 00:00:00 2001 From: Erki Date: Sun, 23 Jan 2022 18:33:24 +0200 Subject: [PATCH 03/17] Yup, away we goo --- Jenkinsfile | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 Jenkinsfile diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..2d8eda2 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,22 @@ +pipeline { + agent { + label { + "ubuntu" + } + } + + stages { + stage("build && test") { + steps { + sh 'sudo pip3 install --upgrade conan==1.42.1' + sh 'conan profile new default --detect' + sh 'conan profile update settings.compiler.libcxx=libstdc++11 default' + sh 'mkdir -p build && cd build' + sh 'conan install .. --build=missing' + sh 'cmake .. -G "Ninja" -DCMAKE_BUILD_TYPE=Release -DWITH_TESTS=ON' + sh 'ninja' + sh 'ctest . --output-on-failure' + } + } + } +} From dc9e159377dc52d5a7677706bd36cf796a13ae93 Mon Sep 17 00:00:00 2001 From: Erki Date: Sun, 23 Jan 2022 18:34:37 +0200 Subject: [PATCH 04/17] le woops --- Jenkinsfile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 2d8eda2..d8b2b39 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,8 +1,6 @@ pipeline { agent { - label { - "ubuntu" - } + label 'ubuntu' } stages { From d909651bf1c84696869bbc3460551f9e6d54d5ad Mon Sep 17 00:00:00 2001 From: Erki Date: Sun, 23 Jan 2022 18:46:26 +0200 Subject: [PATCH 05/17] testies --- Jenkinsfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Jenkinsfile b/Jenkinsfile index d8b2b39..f24db61 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -6,6 +6,8 @@ pipeline { stages { stage("build && test") { steps { + echo 'Workspace: ${env.WORKSPACE}' + sh 'ls' sh 'sudo pip3 install --upgrade conan==1.42.1' sh 'conan profile new default --detect' sh 'conan profile update settings.compiler.libcxx=libstdc++11 default' From b8c3e32fd63370cd15b646a3d0ccb20f3dab2321 Mon Sep 17 00:00:00 2001 From: Erki Date: Sun, 23 Jan 2022 18:48:39 +0200 Subject: [PATCH 06/17] yup --- Jenkinsfile | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index f24db61..9792dc8 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -6,16 +6,20 @@ pipeline { stages { stage("build && test") { steps { - echo 'Workspace: ${env.WORKSPACE}' + echo "Workspace: ${env.WORKSPACE}" sh 'ls' sh 'sudo pip3 install --upgrade conan==1.42.1' sh 'conan profile new default --detect' sh 'conan profile update settings.compiler.libcxx=libstdc++11 default' - sh 'mkdir -p build && cd build' - sh 'conan install .. --build=missing' - sh 'cmake .. -G "Ninja" -DCMAKE_BUILD_TYPE=Release -DWITH_TESTS=ON' - sh 'ninja' - sh 'ctest . --output-on-failure' + sh 'mkdir -p build' + + dir("build") { + sh 'ls' + sh 'conan install .. --build=missing' + sh 'cmake .. -G "Ninja" -DCMAKE_BUILD_TYPE=Release -DWITH_TESTS=ON' + sh 'ninja' + sh 'ctest . --output-on-failure' + } } } } From 227af3c9fcd3b00b8ac2f432591ef908deb8ab1b Mon Sep 17 00:00:00 2001 From: Erki Date: Sun, 23 Jan 2022 19:12:47 +0200 Subject: [PATCH 07/17] now with XML --- Jenkinsfile | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 9792dc8..4a79b6c 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -18,9 +18,38 @@ pipeline { sh 'conan install .. --build=missing' sh 'cmake .. -G "Ninja" -DCMAKE_BUILD_TYPE=Release -DWITH_TESTS=ON' sh 'ninja' - sh 'ctest . --output-on-failure' + 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() + } + } } From bb220c9e92ce682573f5e629d523aa980aa850de Mon Sep 17 00:00:00 2001 From: Erki Date: Thu, 16 Jun 2022 23:19:51 +0300 Subject: [PATCH 08/17] Refactor cmake support to be less leaky --- .drone.yml | 1 - CMakeLists.txt | 15 ++++++--------- Jenkinsfile | 6 +----- Messaging/CMakeLists.txt | 11 ++++++++--- Peripherals/CMakeLists.txt | 7 ++++++- Tests/CMakeLists.txt | 18 +++++++++++++++--- Utility/CMakeLists.txt | 11 +++++------ 7 files changed, 41 insertions(+), 28 deletions(-) diff --git a/.drone.yml b/.drone.yml index 0c6f33e..8459a83 100644 --- a/.drone.yml +++ b/.drone.yml @@ -9,7 +9,6 @@ steps: commands: - mkdir -p build - cd build - - conan install .. --build=missing - cmake .. -G "Ninja" -DCMAKE_BUILD_TYPE=Release -DWITH_TESTS=ON - ninja - ctest . --output-on-failure diff --git a/CMakeLists.txt b/CMakeLists.txt index 1f5c83f..b47f745 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,22 +1,19 @@ cmake_minimum_required(VERSION 3.8 FATAL_ERROR) -set(version 0.1.0) +set(SKULLC_VERSION 0.1.0) project(skullc - VERSION ${version} + VERSION ${SKULLC_VERSION} LANGUAGES C 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/) -set(CMAKE_CXX_STANDARD 17) -list(APPEND CMAKE_CXX_FLAGS "-Wall -Wextra") - -option(WITH_TESTS "Enable unit testing." OFF) -option(WITH_HAL "Enable the compiling and deployment of the HAL dependent sections." OFF) +option(SKULLC_WITH_TESTS "Enable unit testing." OFF) +option(SKULLC_WITH_HAL "Enable the compiling and deployment of the HAL dependent sections." OFF) include(skullc-install) @@ -24,7 +21,7 @@ add_subdirectory(Peripherals) add_subdirectory(Utility) add_subdirectory(Messaging) -if(WITH_TESTS) +if(SKULLC_WITH_TESTS) enable_testing() add_subdirectory(Tests) endif() diff --git a/Jenkinsfile b/Jenkinsfile index 4a79b6c..1bb1572 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -7,16 +7,12 @@ pipeline { stage("build && test") { steps { echo "Workspace: ${env.WORKSPACE}" - sh 'ls' - sh 'sudo pip3 install --upgrade conan==1.42.1' - sh 'conan profile new default --detect' - sh 'conan profile update settings.compiler.libcxx=libstdc++11 default' sh 'mkdir -p build' dir("build") { sh 'ls' sh 'conan install .. --build=missing' - sh 'cmake .. -G "Ninja" -DCMAKE_BUILD_TYPE=Release -DWITH_TESTS=ON' + sh 'cmake .. -G "Ninja" -DCMAKE_BUILD_TYPE=Release -DSKULLC_WITH_TESTS=ON' sh 'ninja' sh 'ctest . -T test --output-on-failure --no-compress-output' } diff --git a/Messaging/CMakeLists.txt b/Messaging/CMakeLists.txt index 761c997..08dffc5 100644 --- a/Messaging/CMakeLists.txt +++ b/Messaging/CMakeLists.txt @@ -5,9 +5,14 @@ add_library(messaging INTERFACE) add_library(skullc::messaging ALIAS messaging) target_include_directories(messaging - INTERFACE + INTERFACE $ $ - ) +) -skullc_install_packages(skullc messaging ${version}) +set_target_properties(messaging + PROPERTIES + CXX_STANDARD 17 +) + +skullc_install_packages(skullc messaging ${SKULLC_VERSION}) diff --git a/Peripherals/CMakeLists.txt b/Peripherals/CMakeLists.txt index a143b86..6640782 100644 --- a/Peripherals/CMakeLists.txt +++ b/Peripherals/CMakeLists.txt @@ -10,5 +10,10 @@ target_include_directories(peripherals $ ) +set_target_properties(peripherals + PROPERTIES + CXX_STANDARD 17 +) + ## INSTALL -skullc_install_packages(skullc peripherals ${version}) +skullc_install_packages(skullc peripherals ${SKULLC_VERSION}) diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index cdb718a..215684f 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -1,10 +1,16 @@ 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_LINKER_FLAGS "${CMAKE_LINKER_FLAGS} -fno-omit-frame-pointer -fsanitize=address -fsanitize=undefined -fno-sanitize-recover") endif() @@ -28,6 +34,12 @@ target_link_libraries(tests Catch2::Catch2 ) +set_target_properties(tests + PROPERTIES + CXX_STANDARD 17 +) + +list(APPEND CMAKE_MODULE_PATH ${catch2_SOURCE_DIR}/contrib) include(CTest) include(Catch) catch_discover_tests(tests) \ No newline at end of file diff --git a/Utility/CMakeLists.txt b/Utility/CMakeLists.txt index 34b11ff..2c825f6 100644 --- a/Utility/CMakeLists.txt +++ b/Utility/CMakeLists.txt @@ -1,10 +1,5 @@ cmake_minimum_required(VERSION 3.8 FATAL_ERROR) -#if(WITH_HAL) -# set(additional_sources -# ) -#endif() - add_library(utility STATIC Src/utility_logging.cpp Src/utility_rand.cpp @@ -18,5 +13,9 @@ target_include_directories(utility $ $ ) +set_target_properties(utility + PROPERTIES + CXX_STANDARD 17 +) -skullc_install_packages(skullc utility ${version}) +skullc_install_packages(skullc utility ${SKULLC_VERSION}) From 54fd0e23328d442fe1e18312b2fec0cd4c587bb6 Mon Sep 17 00:00:00 2001 From: Erki Date: Thu, 16 Jun 2022 23:21:48 +0300 Subject: [PATCH 09/17] Fix jenkinsfile by removing unnecessary conan reference --- Jenkinsfile | 1 - 1 file changed, 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 1bb1572..a5e0ff9 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -11,7 +11,6 @@ pipeline { dir("build") { sh 'ls' - sh 'conan install .. --build=missing' sh 'cmake .. -G "Ninja" -DCMAKE_BUILD_TYPE=Release -DSKULLC_WITH_TESTS=ON' sh 'ninja' sh 'ctest . -T test --output-on-failure --no-compress-output' From 9924559fe036f0ae5bb33726085eb8c5c7208bcb Mon Sep 17 00:00:00 2001 From: Erki Date: Thu, 16 Jun 2022 23:24:23 +0300 Subject: [PATCH 10/17] Fix CXX_STANDARD on interface libraries --- Messaging/CMakeLists.txt | 5 ----- Peripherals/CMakeLists.txt | 5 ----- 2 files changed, 10 deletions(-) diff --git a/Messaging/CMakeLists.txt b/Messaging/CMakeLists.txt index 08dffc5..ad8e4e3 100644 --- a/Messaging/CMakeLists.txt +++ b/Messaging/CMakeLists.txt @@ -10,9 +10,4 @@ target_include_directories(messaging $ ) -set_target_properties(messaging - PROPERTIES - CXX_STANDARD 17 -) - skullc_install_packages(skullc messaging ${SKULLC_VERSION}) diff --git a/Peripherals/CMakeLists.txt b/Peripherals/CMakeLists.txt index 6640782..4928c42 100644 --- a/Peripherals/CMakeLists.txt +++ b/Peripherals/CMakeLists.txt @@ -10,10 +10,5 @@ target_include_directories(peripherals $ ) -set_target_properties(peripherals - PROPERTIES - CXX_STANDARD 17 -) - ## INSTALL skullc_install_packages(skullc peripherals ${SKULLC_VERSION}) From e554d30bf6df4d930a489fd55c09504f39053437 Mon Sep 17 00:00:00 2001 From: Erki Date: Sun, 26 Jun 2022 17:53:40 +0300 Subject: [PATCH 11/17] Utility: add the ability to generate static functions from IFunction --- Peripherals/Inc/peripherals_utility.hpp | 4 --- Tests/function.cpp | 47 +++++++++++++++++++++++++ Utility/Inc/utility_function.hpp | 8 +++++ Utility/Inc/utility_tag.hpp | 12 +++++++ 4 files changed, 67 insertions(+), 4 deletions(-) create mode 100644 Utility/Inc/utility_tag.hpp diff --git a/Peripherals/Inc/peripherals_utility.hpp b/Peripherals/Inc/peripherals_utility.hpp index 34b2691..0ab29af 100644 --- a/Peripherals/Inc/peripherals_utility.hpp +++ b/Peripherals/Inc/peripherals_utility.hpp @@ -15,10 +15,6 @@ 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 constexpr const T& clamp(const T& v, const T& lo, const T& hi) { diff --git a/Tests/function.cpp b/Tests/function.cpp index a9dbe19..c7383fc 100644 --- a/Tests/function.cpp +++ b/Tests/function.cpp @@ -5,6 +5,7 @@ #include #include +#include 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); } +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 function(func_to_call); + using signature = void (*)(int, bool); + + signature func_pointer = function.toStaticFunction(); + func_pointer(10, true); + + REQUIRE(int_to_set == 10); + REQUIRE(bool_to_set == true); +} + TEST_CASE("FunctionOwned calls function appropriately.", "[utility],[function]") { struct S @@ -82,3 +103,29 @@ TEST_CASE("FunctionOwned passes arguments appropriately.", "[utility],[function] REQUIRE(subject.int_to_set == 10); 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 function(subject, &S::toCall); + using signature = void (*)(int, bool); + + signature func_pointer = function.toStaticFunction(); + func_pointer(10, true); + + REQUIRE(subject.int_to_set == 10); + REQUIRE(subject.bool_to_set == true); +} diff --git a/Utility/Inc/utility_function.hpp b/Utility/Inc/utility_function.hpp index 4d9f200..e01078c 100644 --- a/Utility/Inc/utility_function.hpp +++ b/Utility/Inc/utility_function.hpp @@ -19,11 +19,19 @@ class IFunction { public: using result_type = R; + using static_signature = R (*)(Args...); virtual ~IFunction() {} virtual result_type operator()(Args... args) = 0; + + template + static_signature toStaticFunction() + { + static decltype(this) h = this; + return +[](Args... args) { (*h)(args...); }; + } }; template diff --git a/Utility/Inc/utility_tag.hpp b/Utility/Inc/utility_tag.hpp new file mode 100644 index 0000000..99eb900 --- /dev/null +++ b/Utility/Inc/utility_tag.hpp @@ -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_ From c0a622c5e43e4f8df8485c97f3e1469667307fff Mon Sep 17 00:00:00 2001 From: Erki Date: Wed, 29 Jun 2022 01:00:45 +0300 Subject: [PATCH 12/17] Utility: add mini-assert library --- Tests/CMakeLists.txt | 6 ++- Tests/assert.cpp | 68 ++++++++++++++++++++++++++++++++++ Tests/assert_ndebug.cpp | 62 +++++++++++++++++++++++++++++++ Utility/CMakeLists.txt | 1 + Utility/Inc/utility_assert.hpp | 33 +++++++++++++++++ Utility/Inc/utility_tag.hpp | 2 +- Utility/Src/utility_assert.cpp | 45 ++++++++++++++++++++++ 7 files changed, 215 insertions(+), 2 deletions(-) create mode 100644 Tests/assert.cpp create mode 100644 Tests/assert_ndebug.cpp create mode 100644 Utility/Inc/utility_assert.hpp create mode 100644 Utility/Src/utility_assert.cpp diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 215684f..117a2ad 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -24,7 +24,11 @@ add_executable(tests rand.cpp fixedpoint.cpp pixelbuffer.cpp - pixelbuffer_effects.cpp function.cpp) + pixelbuffer_effects.cpp + function.cpp + assert_ndebug.cpp + assert.cpp +) target_link_libraries(tests PUBLIC diff --git a/Tests/assert.cpp b/Tests/assert.cpp new file mode 100644 index 0000000..3929583 --- /dev/null +++ b/Tests/assert.cpp @@ -0,0 +1,68 @@ +// +// Created by erki on 29.06.22. +// + +#include + +#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 int) +{ + assert_flag = true; +} + +} + +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); +} diff --git a/Tests/assert_ndebug.cpp b/Tests/assert_ndebug.cpp new file mode 100644 index 0000000..f130c25 --- /dev/null +++ b/Tests/assert_ndebug.cpp @@ -0,0 +1,62 @@ +// +// Created by erki on 29.06.22. +// + +#include + +#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 int) +{ + assert_flag = true; +} + +} + +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); +} diff --git a/Utility/CMakeLists.txt b/Utility/CMakeLists.txt index 2c825f6..1114ce1 100644 --- a/Utility/CMakeLists.txt +++ b/Utility/CMakeLists.txt @@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 3.8 FATAL_ERROR) add_library(utility STATIC Src/utility_logging.cpp Src/utility_rand.cpp + Src/utility_assert.cpp ${additional_sources} ) diff --git a/Utility/Inc/utility_assert.hpp b/Utility/Inc/utility_assert.hpp new file mode 100644 index 0000000..89c1998 --- /dev/null +++ b/Utility/Inc/utility_assert.hpp @@ -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 bool expr, const char* file, const int line); + +} + +#ifndef NDEBUG +# define SKULLC_ASSERT_DEBUG(e) Utility::Assert::Detail::assertImpl(e, __FILE__, __LINE__) +#else +# define SKULLC_ASSERT_DEBUG(e) +#endif + +#define SKULLC_ASSERT_SAFE(e) Utility::Assert::Detail::assertImpl(e, __FILE__, __LINE__) + +namespace Utility::Assert +{ + +using assert_cb = void (*)(const char* file, const int line); + +void setHandler(assert_cb callback); +assert_cb getHandler(); + +} + +#endif // SKULLC_UTILITY_ASSERT_HPP_ diff --git a/Utility/Inc/utility_tag.hpp b/Utility/Inc/utility_tag.hpp index 99eb900..235a769 100644 --- a/Utility/Inc/utility_tag.hpp +++ b/Utility/Inc/utility_tag.hpp @@ -9,4 +9,4 @@ #define SKULLC_CONCAT(x, y) SKULLC_CONCAT_IMPL(x, y) #define SKULLC_TAG struct SKULLC_CONCAT(SkullCTag_, __COUNTER__) -#endif// SKULLC_UTILITY_TAG_HPP_ +#endif // SKULLC_UTILITY_TAG_HPP_ diff --git a/Utility/Src/utility_assert.cpp b/Utility/Src/utility_assert.cpp new file mode 100644 index 0000000..6527a3e --- /dev/null +++ b/Utility/Src/utility_assert.cpp @@ -0,0 +1,45 @@ +// +// Created by erki on 29.06.22. +// + +#include "utility_assert.hpp" + +#include + +namespace +{ + +Utility::Assert::assert_cb INSTALLED_HANDLER = nullptr; + +} + +namespace Utility::Assert +{ + +namespace Detail +{ + +void assertImpl(const bool expr, const char* file, const int line) +{ + if (!expr) + { + if (INSTALLED_HANDLER) + INSTALLED_HANDLER(file, line); + else + std::terminate(); + } +} + +} + +void setHandler(assert_cb callback) +{ + INSTALLED_HANDLER = callback; +} + +assert_cb getHandler() +{ + return INSTALLED_HANDLER; +} + +} From eef2e1318c363ac818959160478b53d04c84dd54 Mon Sep 17 00:00:00 2001 From: Erki Date: Thu, 30 Jun 2022 19:44:50 +0300 Subject: [PATCH 13/17] Make assert library print out assert expressions --- Tests/assert.cpp | 10 +++++----- Tests/assert_ndebug.cpp | 10 +++++----- Utility/Inc/utility_assert.hpp | 14 +++++++------- Utility/Src/utility_assert.cpp | 17 +++++++---------- 4 files changed, 24 insertions(+), 27 deletions(-) diff --git a/Tests/assert.cpp b/Tests/assert.cpp index 3929583..ee606f3 100644 --- a/Tests/assert.cpp +++ b/Tests/assert.cpp @@ -5,14 +5,14 @@ #include #ifdef NDEBUG -# undef NDEBUG -# define NDEBUG_WAS_SET +#undef NDEBUG +#define NDEBUG_WAS_SET #endif #include "utility_assert.hpp" #ifdef NDEBUG_WAS_SET -# define NDEBUG +#define NDEBUG #endif namespace @@ -20,12 +20,12 @@ namespace bool assert_flag = false; -void assertCallback(const char*, const int) +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]") { diff --git a/Tests/assert_ndebug.cpp b/Tests/assert_ndebug.cpp index f130c25..e921a1c 100644 --- a/Tests/assert_ndebug.cpp +++ b/Tests/assert_ndebug.cpp @@ -5,14 +5,14 @@ #include #ifndef NDEBUG -# define NDEBUG -# define NDEBUG_WAS_NOT_DEFINED +#define NDEBUG +#define NDEBUG_WAS_NOT_DEFINED #endif #include "utility_assert.hpp" #ifdef NDEBUG_WAS_NOT_DEFINED -# undef NDEBUG +#undef NDEBUG #endif namespace @@ -20,12 +20,12 @@ namespace bool assert_flag = false; -void assertCallback(const char*, const int) +void assertCallback(const char*, const char*, const int) { assert_flag = true; } -} +}// namespace TEST_CASE("Assert debug with NDEBUG is a null-opt.", "[utility],[assert]") { diff --git a/Utility/Inc/utility_assert.hpp b/Utility/Inc/utility_assert.hpp index 89c1998..a292dc4 100644 --- a/Utility/Inc/utility_assert.hpp +++ b/Utility/Inc/utility_assert.hpp @@ -8,26 +8,26 @@ namespace Utility::Assert::Detail { -void assertImpl(const bool expr, const char* file, const int line); +void assertImpl(const char* expression, const char* file, const int line); } #ifndef NDEBUG -# define SKULLC_ASSERT_DEBUG(e) Utility::Assert::Detail::assertImpl(e, __FILE__, __LINE__) +#define SKULLC_ASSERT_DEBUG(e) (!(e) ? Utility::Assert::Detail::assertImpl(#e, __FILE__, __LINE__) : ((void) 0)) #else -# define SKULLC_ASSERT_DEBUG(e) +#define SKULLC_ASSERT_DEBUG(e) #endif -#define SKULLC_ASSERT_SAFE(e) Utility::Assert::Detail::assertImpl(e, __FILE__, __LINE__) +#define SKULLC_ASSERT_SAFE(e) (!(e) ? Utility::Assert::Detail::assertImpl(#e, __FILE__, __LINE__) : ((void) 0)) namespace Utility::Assert { -using assert_cb = void (*)(const char* file, const int line); +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_ +#endif// SKULLC_UTILITY_ASSERT_HPP_ diff --git a/Utility/Src/utility_assert.cpp b/Utility/Src/utility_assert.cpp index 6527a3e..4f6eb6f 100644 --- a/Utility/Src/utility_assert.cpp +++ b/Utility/Src/utility_assert.cpp @@ -19,18 +19,15 @@ namespace Utility::Assert namespace Detail { -void assertImpl(const bool expr, const char* file, const int line) +void assertImpl(const char* expression, const char* file, const int line) { - if (!expr) - { - if (INSTALLED_HANDLER) - INSTALLED_HANDLER(file, line); - else - std::terminate(); - } + if (INSTALLED_HANDLER) + INSTALLED_HANDLER(expression, file, line); + else + std::terminate(); } -} +}// namespace Detail void setHandler(assert_cb callback) { @@ -42,4 +39,4 @@ assert_cb getHandler() return INSTALLED_HANDLER; } -} +}// namespace Utility::Assert From 0ba9416a57c86feb5dbbac8439e9775742043227 Mon Sep 17 00:00:00 2001 From: Erki Date: Thu, 30 Jun 2022 19:46:56 +0300 Subject: [PATCH 14/17] Add get() functionality to static_pointer --- Utility/Inc/utility_staticpointer.hpp | 14 ++++++++++++++ Utility/Inc/utility_tag.hpp | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/Utility/Inc/utility_staticpointer.hpp b/Utility/Inc/utility_staticpointer.hpp index b8dba5e..0715be6 100644 --- a/Utility/Inc/utility_staticpointer.hpp +++ b/Utility/Inc/utility_staticpointer.hpp @@ -8,8 +8,11 @@ #ifndef SKULLC_UTILITY_STATICPOINTER_HPP_ #define SKULLC_UTILITY_STATICPOINTER_HPP_ +#include #include +#include + namespace Utility { @@ -57,6 +60,17 @@ struct StaticPointer return initialized_; } + value_type* get() + { + SKULLC_ASSERT_DEBUG(initialized_); + return reinterpret_cast(storage); + } + + const value_type* get() const + { + SKULLC_ASSERT_DEBUG(initialized_); + return reinterpret_cast(storage); + } private: bool initialized_ = false; }; diff --git a/Utility/Inc/utility_tag.hpp b/Utility/Inc/utility_tag.hpp index 235a769..99eb900 100644 --- a/Utility/Inc/utility_tag.hpp +++ b/Utility/Inc/utility_tag.hpp @@ -9,4 +9,4 @@ #define SKULLC_CONCAT(x, y) SKULLC_CONCAT_IMPL(x, y) #define SKULLC_TAG struct SKULLC_CONCAT(SkullCTag_, __COUNTER__) -#endif // SKULLC_UTILITY_TAG_HPP_ +#endif// SKULLC_UTILITY_TAG_HPP_ From 718b6705fd47ca1ceb7b8702352ecedf6f7c1c9a Mon Sep 17 00:00:00 2001 From: Erki Date: Fri, 15 Jul 2022 13:54:31 +0300 Subject: [PATCH 15/17] Utility: replace standard library asserts with SKULLC ones. --- Utility/Inc/utility_function.hpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Utility/Inc/utility_function.hpp b/Utility/Inc/utility_function.hpp index e01078c..0d62c67 100644 --- a/Utility/Inc/utility_function.hpp +++ b/Utility/Inc/utility_function.hpp @@ -8,6 +8,8 @@ #ifndef SKULLC_UTILITY_FUNCTION_HPP_ #define SKULLC_UTILITY_FUNCTION_HPP_ +#include + namespace Utility { @@ -49,7 +51,7 @@ public: explicit Function(signature callable) : callable_(callable) { - assert(callable_); + SKULLC_ASSERT_DEBUG(callable_); } ~Function() override @@ -81,7 +83,7 @@ public: explicit FunctionOwned(source& src, signature callable) : src_(&src), callable_(callable) { - assert(callable_); + SKULLC_ASSERT_DEBUG(callable_); } ~FunctionOwned() override From 3aca35788b247974c5a3a7a0f023f6a01bb71c7e Mon Sep 17 00:00:00 2001 From: Erki Date: Fri, 15 Jul 2022 14:15:04 +0300 Subject: [PATCH 16/17] Utility: enum helpers library --- Tests/CMakeLists.txt | 1 + Tests/enum_helpers.cpp | 41 +++++++++++++++++++++++++++ Utility/Inc/utility_enum_helpers.hpp | 20 +++++++++++++ Utility/Inc/utility_staticpointer.hpp | 1 + 4 files changed, 63 insertions(+) create mode 100644 Tests/enum_helpers.cpp create mode 100644 Utility/Inc/utility_enum_helpers.hpp diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 117a2ad..53eedd7 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -28,6 +28,7 @@ add_executable(tests function.cpp assert_ndebug.cpp assert.cpp + enum_helpers.cpp ) target_link_libraries(tests diff --git a/Tests/enum_helpers.cpp b/Tests/enum_helpers.cpp new file mode 100644 index 0000000..1d8df14 --- /dev/null +++ b/Tests/enum_helpers.cpp @@ -0,0 +1,41 @@ +// +// Created by erki on 15.07.22. +// + +#include + +#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); +} diff --git a/Utility/Inc/utility_enum_helpers.hpp b/Utility/Inc/utility_enum_helpers.hpp new file mode 100644 index 0000000..7ee6d8f --- /dev/null +++ b/Utility/Inc/utility_enum_helpers.hpp @@ -0,0 +1,20 @@ +// +// Created by erki on 15.07.22. +// + +#ifndef SKULLC_UTILITY_ENUM_HELPERS_HPP_ +#define SKULLC_UTILITY_ENUM_HELPERS_HPP_ + +#define SKULLC_ENUM_DECLARE_BITFLAG_OPERATORS(E) \ + inline E operator|(const E& lhs, const E& rhs) \ + { \ + using T = std::underlying_type_t; \ + return static_cast(static_cast(lhs) | static_cast(rhs)); \ + } \ + inline E operator&(const E& lhs, const E& rhs) \ + { \ + using T = std::underlying_type_t; \ + return static_cast(static_cast(lhs) & static_cast(rhs)); \ + } + +#endif//SKULLC_UTILITY_ENUM_HELPERS_HPP_ diff --git a/Utility/Inc/utility_staticpointer.hpp b/Utility/Inc/utility_staticpointer.hpp index 0715be6..4556faf 100644 --- a/Utility/Inc/utility_staticpointer.hpp +++ b/Utility/Inc/utility_staticpointer.hpp @@ -71,6 +71,7 @@ struct StaticPointer SKULLC_ASSERT_DEBUG(initialized_); return reinterpret_cast(storage); } + private: bool initialized_ = false; }; From 458fd9e7f2b05376b1a870bf49d92a442eda5c8c Mon Sep 17 00:00:00 2001 From: Erki Date: Fri, 15 Jul 2022 14:17:02 +0300 Subject: [PATCH 17/17] Utility: add missing include to enum helpers --- Utility/Inc/utility_enum_helpers.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Utility/Inc/utility_enum_helpers.hpp b/Utility/Inc/utility_enum_helpers.hpp index 7ee6d8f..62d7e7a 100644 --- a/Utility/Inc/utility_enum_helpers.hpp +++ b/Utility/Inc/utility_enum_helpers.hpp @@ -5,6 +5,8 @@ #ifndef SKULLC_UTILITY_ENUM_HELPERS_HPP_ #define SKULLC_UTILITY_ENUM_HELPERS_HPP_ +#include + #define SKULLC_ENUM_DECLARE_BITFLAG_OPERATORS(E) \ inline E operator|(const E& lhs, const E& rhs) \ { \