From 463bc8ea8019305f6620d96fd21ed1ce0cc1ebc7 Mon Sep 17 00:00:00 2001 From: Allen Winter Date: Sun, 31 Oct 2021 10:43:26 -0400 Subject: [PATCH 01/31] let's call this version 1.1 --- CMakeLists.txt | 2 +- ChangeLog | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f0befa2..14e186b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,7 +31,7 @@ cmake_minimum_required(VERSION 3.12) # for `project(... HOMEPAGE_URL ...)` project(KDBindings DESCRIPTION "Bindings, from the comfort and speed of C++ and without Qt" LANGUAGES CXX - VERSION 1.0.0 + VERSION 1.0.95 HOMEPAGE_URL "https://github.com/KDAB/KDBindings" ) diff --git a/ChangeLog b/ChangeLog index da7c047..152eb52 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,2 +1,5 @@ +* v1.1.0 + - + * v1.0.0 - Initial Release From 2fda7166105405051fde2c76df72a53f46d1c82a Mon Sep 17 00:00:00 2001 From: Allen Winter Date: Mon, 1 Nov 2021 09:30:04 -0400 Subject: [PATCH 02/31] appveyor.yml - start to support linux and mac --- appveyor.yml | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 9342ca6..fd20bf3 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -19,11 +19,9 @@ skip_tags: false # Build worker image image: + - macos - Visual Studio 2019 - -# scripts that are called at very beginning, before repo cloning -init: - - git config --global core.autocrlf input + - Ubuntu #---------------------------------# # build configuration # @@ -31,19 +29,22 @@ init: # build platform, i.e. x86, x64, Any CPU. This setting is optional. platform: - - x64 + - Any CPU # build Configuration, i.e. Debug, Release, etc. configuration: - Release + - Debug + +init: + - cmd: call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat" install: - - call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat" -build_script: - mkdir build - cd build - - cmake -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=%CONFIGURATION% -DKDBindings_TESTS=True -DKDBindings_EXAMPLES=True .. - - nmake + - cmake -G Ninja -DCMAKE_BUILD_TYPE=%CONFIGURATION% -DKDBindings_TESTS=True -DKDBindings_EXAMPLES=True .. + - cmake --build . + - cmake --build . --target install # to disable automatic builds #build: off @@ -53,7 +54,7 @@ build_script: #---------------------------------# test_script: - - nmake test + - ctest --test-dir . # to disable automatic tests #test: off From 6be8d3f5ac51abc74089485816a1dac37e0184ad Mon Sep 17 00:00:00 2001 From: Allen Winter Date: Mon, 1 Nov 2021 09:50:57 -0400 Subject: [PATCH 03/31] appveyor.yml - don't pass -DCMAKE_BUILD_TYPE=%CONFIGURATION% --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index fd20bf3..7841ba1 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -42,7 +42,7 @@ init: install: - mkdir build - cd build - - cmake -G Ninja -DCMAKE_BUILD_TYPE=%CONFIGURATION% -DKDBindings_TESTS=True -DKDBindings_EXAMPLES=True .. + - cmake -G Ninja -DKDBindings_TESTS=True -DKDBindings_EXAMPLES=True .. - cmake --build . - cmake --build . --target install From bbc3fa3b47cf56143d1d32e23f426a3dd8b5d0df Mon Sep 17 00:00:00 2001 From: Allen Winter Date: Mon, 1 Nov 2021 10:48:06 -0400 Subject: [PATCH 04/31] appveyor.yml - experiment with some things --- appveyor.yml | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 7841ba1..d9e3268 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -23,6 +23,10 @@ image: - Visual Studio 2019 - Ubuntu +# scripts that are called at very beginning, before repo cloning +init: + - git config --global core.autocrlf input + #---------------------------------# # build configuration # #---------------------------------# @@ -39,12 +43,15 @@ configuration: init: - cmd: call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat" -install: +build_script: - mkdir build - cd build - - cmake -G Ninja -DKDBindings_TESTS=True -DKDBindings_EXAMPLES=True .. + - cmd: cmake -G Ninja -DCMAKE_BUILD_TYPE=%CONFIGURATION% -DKDBindings_TESTS=True -DKDBindings_EXAMPLES=True .. + - sh: cmake -G Ninja -DCMAKE_BUILD_TYPE=$CONFIGURATION -DKDBindings_TESTS=True -DKDBindings_EXAMPLES=True .. - cmake --build . - - cmake --build . --target install + - cmd: cmake --build . --target install + - sh: sudo cmake --build . --target install + - ctest --test-dir . # to disable automatic builds #build: off @@ -53,11 +60,8 @@ install: # tests configuration # #---------------------------------# -test_script: - - ctest --test-dir . - # to disable automatic tests -#test: off +test: off #---------------------------------# From 9d5ba9c66f7820e369c0cedc4f65ff78c2c155f7 Mon Sep 17 00:00:00 2001 From: Allen Winter Date: Mon, 1 Nov 2021 10:49:52 -0400 Subject: [PATCH 05/31] appveyor.yml - remove adding the path for msvc2019 --- appveyor.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index d9e3268..1dbe50a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -40,9 +40,6 @@ configuration: - Release - Debug -init: - - cmd: call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat" - build_script: - mkdir build - cd build From c631c5cdd761e25b25e6fd86126c36ac1f1583ad Mon Sep 17 00:00:00 2001 From: Allen Winter Date: Mon, 1 Nov 2021 13:01:55 -0400 Subject: [PATCH 06/31] appveyor.yml - attempt to install ninja with brew (on Mac) --- appveyor.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/appveyor.yml b/appveyor.yml index 1dbe50a..83eecd0 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -40,6 +40,9 @@ configuration: - Release - Debug +install: + - sh: if [ "`uname -s`" = "Darwin" ]; then brew install ninja; fi + build_script: - mkdir build - cd build From fa81cc7927d7f118544e99473a4587bf238cc871 Mon Sep 17 00:00:00 2001 From: Allen Winter Date: Mon, 1 Nov 2021 13:13:50 -0400 Subject: [PATCH 07/31] .travis.yml - remove as we build for linux+Mac with AppVeyor --- .travis.yml | 40 ---------------------------------------- 1 file changed, 40 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 3a5b1b0..0000000 --- a/.travis.yml +++ /dev/null @@ -1,40 +0,0 @@ -env: - global: - - secure: "NlWO/NTPlOU6cowOMuPOvjAprXVwIjmpHHf9CoMR71E2c/eBFFKIHj10kXuyFwz2KihHAIExmo9OlGtGniNWobvIrVrabO3dsOSb6UGbPAQkzQiyQLKsDNQAZx3nMuWEKBtMsVRee6rd7/2uGTY4WB5Ot3VhrUYcN1FoRgQQ9gk=" - -branches: - only: - - main - -matrix: - include: - - os: linux - dist: focal - - os: osx - osx_image: xcode11.5 - -language: cpp -compiler: - - gcc - - clang - -script: - - mkdir build - - cd build - - cmake -DCMAKE_BUILD_TYPE=Release -DKDBindings_TESTS=True -KDBindings_EXAMPLES=True .. - - make - - make test - -notifications: - email: - recipients: - - allen.winter@kdab.com - on_success: never - on_failure: always - -dist: bionic -addons: - apt: - update: true - homebrew: - update: true From b5fa29b6bd3f148c8b935dad18bb3951e3d4a9ca Mon Sep 17 00:00:00 2001 From: Allen Winter Date: Thu, 4 Nov 2021 10:11:56 -0400 Subject: [PATCH 08/31] fix KDBindingsConfigVersion.cmake installation --- src/kdbindings/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kdbindings/CMakeLists.txt b/src/kdbindings/CMakeLists.txt index d88a653..928dc7d 100644 --- a/src/kdbindings/CMakeLists.txt +++ b/src/kdbindings/CMakeLists.txt @@ -43,7 +43,7 @@ ecm_setup_version( ${PROJECT_VERSION} VARIABLE_PREFIX KDBINDINGS VERSION_HEADER "${CMAKE_BINARY_DIR}/kdbindings_version.h" - PACKAGE_VERSION_FILE "${CMAKE_BINARY_DIR}/KDBindingsConfigVersion.cmake" + PACKAGE_VERSION_FILE "${PROJECT_BINARY_DIR}/KDBindingsConfigVersion.cmake" COMPATIBILITY AnyNewerVersion ) install(FILES "${CMAKE_BINARY_DIR}/kdbindings_version.h" DESTINATION ${INSTALL_INCLUDE_DIR}/kdbindings) From e37ef6c0bfaac59a41da6798198b510a83023424 Mon Sep 17 00:00:00 2001 From: PPPBerlin Date: Fri, 5 Nov 2021 11:00:35 +0100 Subject: [PATCH 09/31] Update README.md change requested from Tobias --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3396ebd..fce42ae 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ KDBindings ========== -Bindings, from the comfort and speed of C++ and without Qt. +Reactive programming & data binding in C++ From plain C++ you get: From 966bdc327ffec927f063103db33c5ce1a161602e Mon Sep 17 00:00:00 2001 From: Leon Matthes Date: Fri, 5 Nov 2021 11:38:19 +0100 Subject: [PATCH 10/31] Update KDBindings description in docs --- docs/api/footer.html | 2 +- docs/api/mkdocs/mkdocs.yml.cmake | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/api/footer.html b/docs/api/footer.html index ff070de..1d73066 100644 --- a/docs/api/footer.html +++ b/docs/api/footer.html @@ -11,7 +11,7 @@ KDBindings
- Bindings from the comfort and speed of C++
+ Reactive programming & data binding in C++
https://github.com/KDAB/KDBindings/
$generatedby doxygen $doxygenversion
diff --git a/docs/api/mkdocs/mkdocs.yml.cmake b/docs/api/mkdocs/mkdocs.yml.cmake index 6a0de75..b6603d2 100644 --- a/docs/api/mkdocs/mkdocs.yml.cmake +++ b/docs/api/mkdocs/mkdocs.yml.cmake @@ -1,7 +1,7 @@ -site_name: KDBindings - Bindings from the comfort and speed of C++ +site_name: KDBindings - Reactive programming & data binding in C++ site_url: https://docs.kdab.com/kdbindings/${CMAKE_PROJECT_VERSION}/ repo_url: https://github.com/kdab/kdbindings -site_description: KDBindings Documentation - Bindings from the comfort and speed of C++ +site_description: KDBindings Documentation - Reactive programming & data binding in C++ site_author: Klarälvdalens Datakonsult AB (KDAB) theme: From d26b90c6ad1fc0eac1716d1d46831ed09aecc88a Mon Sep 17 00:00:00 2001 From: Waqar Ahmed Date: Wed, 6 Apr 2022 13:43:59 +0500 Subject: [PATCH 11/31] Introduce ScopedConnectionHandle Currently we have to disconnect the slot ourselves when its not needed. This is a bit error prone as we might forget to disconnect a slot in some cases leading to use after frees and invalid reads. This change proposes ScopedConnectionHandle which is a thin wrapper over ConnectionHandle. It automatically disconnects on scope exit. --- src/kdbindings/signal.h | 58 +++++++++++++++++++++++++++++++++++++ tests/signal/tst_signal.cpp | 14 +++++++++ 2 files changed, 72 insertions(+) diff --git a/src/kdbindings/signal.h b/src/kdbindings/signal.h index aeddcab..2c7a280 100644 --- a/src/kdbindings/signal.h +++ b/src/kdbindings/signal.h @@ -191,6 +191,64 @@ class ConnectionHandle } }; +/** + * @brief A ScopedConnectionHandle is a connection handle that will + * automatically disconnect when its scope ends + **/ +class ScopedConnectionHandle +{ +public: + ScopedConnectionHandle() = default; + + ScopedConnectionHandle(ConnectionHandle &&h) + : m_connection(std::move(h)) + { + } + + ScopedConnectionHandle& operator=(ConnectionHandle &&h) + { + m_connection = std::move(h); + return *this; + } + + /** + * @return the real handle that this class is managing + */ + ConnectionHandle& handle() + { + return m_connection; + } + + /** + * @overload + */ + const ConnectionHandle& handle() const + { + return m_connection; + } + + /** + * @brief Disconnect the slot + * @see ConnectionHandle::disconnect + */ + void disconnect() + { + m_connection.disconnect(); + } + + ~ScopedConnectionHandle() + { + m_connection.disconnect(); + } + + // Cannot copy + ScopedConnectionHandle(const ScopedConnectionHandle &) = delete; + ScopedConnectionHandle& operator=(const ScopedConnectionHandle &) = delete; + +private: + ConnectionHandle m_connection; +}; + /** * @brief A Signal provides a mechanism for communication between objects. * diff --git a/tests/signal/tst_signal.cpp b/tests/signal/tst_signal.cpp index 534a7a6..a57bfd1 100644 --- a/tests/signal/tst_signal.cpp +++ b/tests/signal/tst_signal.cpp @@ -479,4 +479,18 @@ TEST_CASE("ConnectionHandle") REQUIRE_FALSE(handle.belongsTo(signal)); REQUIRE(handle.belongsTo(otherSignal)); } + + SUBCASE("scoped connection handle") + { + bool called = false; + Signal<> signal; + { + ScopedConnectionHandle handle = signal.connect([&called]() { called = !called; }); + REQUIRE(handle.handle().isActive()); + signal.emit(); + REQUIRE(called); + } + signal.emit(); + REQUIRE(called); + } } From 78e0bd6f72a59205cabe2ba327a1915a28858cc0 Mon Sep 17 00:00:00 2001 From: Leon Matthes Date: Mon, 11 Apr 2022 10:05:24 +0200 Subject: [PATCH 12/31] Rename ScopedConnectionHandle to ScopedConnection A ScopedConnection is not a ConnectionHandle (in the sense of inheritance), but contains a ConnectionHandle, hopefully the new name makes this a bit clearer. Additional changes: - Convenience access to the ConnectionHandle using operator `->`. - Example 08 for connection management - More tests --- ChangeLog | 2 +- .../08-managing-connections/CMakeLists.txt | 16 ++ examples/08-managing-connections/main.cpp | 56 ++++++ examples/CMakeLists.txt | 1 + src/kdbindings/signal.h | 168 ++++++++++++------ tests/signal/tst_signal.cpp | 48 ++++- 6 files changed, 229 insertions(+), 62 deletions(-) create mode 100644 examples/08-managing-connections/CMakeLists.txt create mode 100644 examples/08-managing-connections/main.cpp diff --git a/ChangeLog b/ChangeLog index 152eb52..1f5bdb7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,5 @@ * v1.1.0 - - + - Feature: Add ScopedConnection for RAII-style connection management (#31) * v1.0.0 - Initial Release diff --git a/examples/08-managing-connections/CMakeLists.txt b/examples/08-managing-connections/CMakeLists.txt new file mode 100644 index 0000000..d25fd86 --- /dev/null +++ b/examples/08-managing-connections/CMakeLists.txt @@ -0,0 +1,16 @@ +# This file is part of KDBindings. +# +# SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company +# Author: Leon Matthes +# +# SPDX-License-Identifier: MIT +# +# Contact KDAB at for commercial licensing options. +# + +project(08-managing-connections VERSION 0.1 LANGUAGES CXX) + +add_executable(${PROJECT_NAME} + main.cpp +) +target_link_libraries(${PROJECT_NAME} KDAB::KDBindings) diff --git a/examples/08-managing-connections/main.cpp b/examples/08-managing-connections/main.cpp new file mode 100644 index 0000000..814f859 --- /dev/null +++ b/examples/08-managing-connections/main.cpp @@ -0,0 +1,56 @@ +/* + This file is part of KDBindings. + + SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company + Author: Leon Matthes + + SPDX-License-Identifier: MIT + + Contact KDAB at for commercial licensing options. +*/ + +#include +#include + +#include +#include + +using namespace KDBindings; + +void displayLabelled(const std::string &label, int value) +{ + std::cout << label << ": " << value << std::endl; +} + +int main() +{ + Signal signal; + + { + // A ScopedConnection will disconnect the connection once it goes out of scope. + // It is especially useful if you're connecting to a member function. + // Storing a ScopedConnection in the object that contains the slot ensures the connection + // is disconnected when the object is destructed. + // This ensures that there are no dangling connections. + ScopedConnection guard = signal.connect(displayLabelled, "Guard is connected"); + + signal.emit(1); + } // The connection is disconnected here + + signal.emit(2); + + ConnectionHandle handle = signal.connect(displayLabelled, "Connection is not blocked"); + + signal.emit(3); + { + // A ConnectionBlocker will block a connection for the duration of its scope. + // This is a good way to avoid endless-recursion, or to suppress updates for a short time. + ConnectionBlocker blocker(handle); // The connection is blocked here + + signal.emit(4); + } // The connection is un-blocked here + + signal.emit(5); + + return 0; +} diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index b3d4c7f..0398be2 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -15,3 +15,4 @@ add_subdirectory(04-simple-property) add_subdirectory(05-property-bindings) add_subdirectory(06-lazy-property-bindings) add_subdirectory(07-advanced-connections) +add_subdirectory(08-managing-connections) diff --git a/src/kdbindings/signal.h b/src/kdbindings/signal.h index 2c7a280..c82a82b 100644 --- a/src/kdbindings/signal.h +++ b/src/kdbindings/signal.h @@ -60,6 +60,9 @@ class SignalImplBase * * It is returned from a Signal when a connection is created and used to * manage the connection by disconnecting, (un)blocking it and checking its state. + * + * To make sure a Connection to an object is disconnected correctly, consider + * storing a ScopedConnection to its ConnectionHandle inside the object. **/ class ConnectionHandle { @@ -191,64 +194,6 @@ class ConnectionHandle } }; -/** - * @brief A ScopedConnectionHandle is a connection handle that will - * automatically disconnect when its scope ends - **/ -class ScopedConnectionHandle -{ -public: - ScopedConnectionHandle() = default; - - ScopedConnectionHandle(ConnectionHandle &&h) - : m_connection(std::move(h)) - { - } - - ScopedConnectionHandle& operator=(ConnectionHandle &&h) - { - m_connection = std::move(h); - return *this; - } - - /** - * @return the real handle that this class is managing - */ - ConnectionHandle& handle() - { - return m_connection; - } - - /** - * @overload - */ - const ConnectionHandle& handle() const - { - return m_connection; - } - - /** - * @brief Disconnect the slot - * @see ConnectionHandle::disconnect - */ - void disconnect() - { - m_connection.disconnect(); - } - - ~ScopedConnectionHandle() - { - m_connection.disconnect(); - } - - // Cannot copy - ScopedConnectionHandle(const ScopedConnectionHandle &) = delete; - ScopedConnectionHandle& operator=(const ScopedConnectionHandle &) = delete; - -private: - ConnectionHandle m_connection; -}; - /** * @brief A Signal provides a mechanism for communication between objects. * @@ -576,6 +521,96 @@ class Signal mutable std::shared_ptr m_impl; }; +/** + * @brief A ScopedConnection is a RAII-style way to make sure a Connection is disconnected. + * + * When the ScopedConnections scope ends, the connection this ScopedConnection guards will be disconnected. + * + * Example: + * - @ref 08-managing-connections/main.cpp + */ +class ScopedConnection +{ +public: + /** + * @brief A ScopedConnection can be default constructed + * + * A default constructed ScopedConnection has no connection to guard. + * Therefore it does nothing when it is destructed, unless a ConnectionHandle is assigned to it. + */ + ScopedConnection() = default; + + /** A ScopedConnection can be move constructed */ + ScopedConnection(ScopedConnection &&) = default; + /** A ScopedConnection can be move assigned */ + ScopedConnection &operator=(ScopedConnection &&) = default; + + /** A ScopedConnection cannot be copied */ + ScopedConnection(const ScopedConnection &) = delete; + /** A ScopedConnection cannot be copied */ + ScopedConnection &operator=(const ScopedConnection &) = delete; + + /** + * A ScopedConnection can be constructed from a ConnectionHandle + */ + ScopedConnection(ConnectionHandle &&h) + : m_connection(std::move(h)) + { + } + + /** + * A ScopedConnection can be assigned from a ConnectionHandle + */ + ScopedConnection &operator=(ConnectionHandle &&h) + { + m_connection = std::move(h); + return *this; + } + + /** + * @return the handle to the connection this instance is managing + */ + ConnectionHandle &handle() + { + return m_connection; + } + + /** + * @overload + */ + const ConnectionHandle &handle() const + { + return m_connection; + } + + /** + * Convenience access to the underlying ConnectionHandle using the `->` operator. + */ + ConnectionHandle *operator->() + { + return &m_connection; + } + + /** + * @overload + */ + const ConnectionHandle *operator->() const + { + return &m_connection; + } + + /** + * When a ConnectionHandle is destructed it disconnects the connection it guards. + */ + ~ScopedConnection() + { + m_connection.disconnect(); + } + +private: + ConnectionHandle m_connection; +}; + /** * @brief A ConnectionBlocker is a convenient RAII-style mechanism for temporarily blocking a connection. * @@ -583,6 +618,9 @@ class Signal * * When it is destructed, it will return the connection to the blocked state it was in * before the ConnectionBlocker was constructed. + * + * Example: + * - @ref 08-managing-connections/main.cpp */ class ConnectionBlocker { @@ -660,4 +698,18 @@ class ConnectionBlocker * ``` */ +/** + * @example 08-managing-connections/main.cpp + * + * An example of how to use a ScopedConnection and ConnectionBlocker to manage + * when a Connection is disconnected or blocked. + * + * Expected output: + * ``` + * Guard is connected: 1 + * Connection is not blocked: 3 + * Connection is not blocked: 5 + * ``` + */ + } // namespace KDBindings diff --git a/tests/signal/tst_signal.cpp b/tests/signal/tst_signal.cpp index a57bfd1..1fb48e2 100644 --- a/tests/signal/tst_signal.cpp +++ b/tests/signal/tst_signal.cpp @@ -27,6 +27,20 @@ static_assert(!std::is_copy_assignable>{}); static_assert(std::is_nothrow_move_constructible>{}); static_assert(std::is_nothrow_move_assignable>{}); +static_assert(std::is_nothrow_destructible{}); +static_assert(std::is_nothrow_default_constructible{}); +static_assert(std::is_copy_constructible{}); +static_assert(std::is_copy_assignable{}); +static_assert(std::is_nothrow_move_constructible{}); +static_assert(std::is_nothrow_move_assignable{}); + +static_assert(std::is_nothrow_destructible{}); +static_assert(std::is_nothrow_default_constructible{}); +static_assert(!std::is_copy_constructible{}); +static_assert(!std::is_copy_assignable{}); +static_assert(std::is_nothrow_move_constructible{}); +static_assert(std::is_nothrow_move_assignable{}); + class Button { public: @@ -479,18 +493,46 @@ TEST_CASE("ConnectionHandle") REQUIRE_FALSE(handle.belongsTo(signal)); REQUIRE(handle.belongsTo(otherSignal)); } +} - SUBCASE("scoped connection handle") +TEST_CASE("ScopedConnection") +{ + SUBCASE("A default constructed ScopedConnection is inactive") + { + ScopedConnection guard; + + REQUIRE_FALSE(guard->isActive()); + } + + SUBCASE("A ScopedConnection disconnects when it goes out of scope") { bool called = false; Signal<> signal; { - ScopedConnectionHandle handle = signal.connect([&called]() { called = !called; }); - REQUIRE(handle.handle().isActive()); + const ScopedConnection guard = signal.connect([&called]() { called = !called; }); + REQUIRE(guard->isActive()); signal.emit(); REQUIRE(called); } signal.emit(); REQUIRE(called); } + + SUBCASE("A ScopedConnection can be moved") + { + bool called = false; + Signal<> signal; + ScopedConnection into; + REQUIRE_FALSE(into->isActive()); + { + ScopedConnection guard = signal.connect([&called]() { called = true; }); + REQUIRE(guard->isActive()); + into = std::move(guard); + REQUIRE_FALSE(guard->isActive()); + } + REQUIRE(into->isActive()); + + signal.emit(); + REQUIRE(called); + } } From 07db5916b8608cfc8b8616b7c5756989aacdb6c6 Mon Sep 17 00:00:00 2001 From: Sergio Martins Date: Mon, 13 Jun 2022 18:19:29 +0100 Subject: [PATCH 13/31] Add a basic dev preset Makes it easier to use modern IDEs and my scripts too --- .gitignore | 1 + CMakePresets.json | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 CMakePresets.json diff --git a/.gitignore b/.gitignore index ff27c7d..366f060 100644 --- a/.gitignore +++ b/.gitignore @@ -79,6 +79,7 @@ imgui.ini .vscode/* build/* +build-* serenity_metatype.* output.json diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 0000000..2081aeb --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,17 @@ +{ + "version": 2, + "configurePresets": [ + { + "name": "dev", + "displayName": "dev", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build-dev", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug", + "CMAKE_EXPORT_COMPILE_COMMANDS" : "ON", + "KDBindings_TESTS" : "ON", + "KDBindings_EXAMPLES" : "ON" + } + } + ] +} From c7b82077dfef5151f577951abc2fbd9b89446bd6 Mon Sep 17 00:00:00 2001 From: Sergio Martins Date: Mon, 13 Jun 2022 18:30:58 +0100 Subject: [PATCH 14/31] Fix ScopedConnection not disconnecting old signals when assigned RAII classes release their resources when assigned. --- src/kdbindings/signal.h | 1 + tests/signal/tst_signal.cpp | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/src/kdbindings/signal.h b/src/kdbindings/signal.h index c82a82b..63ad8ac 100644 --- a/src/kdbindings/signal.h +++ b/src/kdbindings/signal.h @@ -563,6 +563,7 @@ class ScopedConnection */ ScopedConnection &operator=(ConnectionHandle &&h) { + m_connection.disconnect(); m_connection = std::move(h); return *this; } diff --git a/tests/signal/tst_signal.cpp b/tests/signal/tst_signal.cpp index 1fb48e2..d038b72 100644 --- a/tests/signal/tst_signal.cpp +++ b/tests/signal/tst_signal.cpp @@ -518,6 +518,19 @@ TEST_CASE("ScopedConnection") REQUIRE(called); } + SUBCASE("A ScopedConnection disconnects when assigned") + { + int numCalled = 0; + Signal<> signal; + ScopedConnection guard = signal.connect([&numCalled]() { numCalled++; }); + signal.emit(); + CHECK_EQ(numCalled, 1); + + guard = signal.connect([&numCalled]() { numCalled++; }); + signal.emit(); + CHECK_EQ(numCalled, 2); + } + SUBCASE("A ScopedConnection can be moved") { bool called = false; From f18431c9b4dc7b71b2138994a59374e27b49548f Mon Sep 17 00:00:00 2001 From: Leon Matthes Date: Wed, 6 Jul 2022 10:28:41 +0200 Subject: [PATCH 15/31] Fix ScopedConnection not disconnecting when move assigned Similar issue as #34 --- src/kdbindings/signal.h | 14 +++++++++----- tests/signal/tst_signal.cpp | 25 +++++++++++++++++++++++-- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/src/kdbindings/signal.h b/src/kdbindings/signal.h index 63ad8ac..c141ee2 100644 --- a/src/kdbindings/signal.h +++ b/src/kdbindings/signal.h @@ -542,14 +542,20 @@ class ScopedConnection /** A ScopedConnection can be move constructed */ ScopedConnection(ScopedConnection &&) = default; - /** A ScopedConnection can be move assigned */ - ScopedConnection &operator=(ScopedConnection &&) = default; /** A ScopedConnection cannot be copied */ ScopedConnection(const ScopedConnection &) = delete; /** A ScopedConnection cannot be copied */ ScopedConnection &operator=(const ScopedConnection &) = delete; + /** A ScopedConnection can be move assigned */ + ScopedConnection &operator=(ScopedConnection &&other) + { + m_connection.disconnect(); + m_connection = std::move(other.m_connection); + return *this; + } + /** * A ScopedConnection can be constructed from a ConnectionHandle */ @@ -563,9 +569,7 @@ class ScopedConnection */ ScopedConnection &operator=(ConnectionHandle &&h) { - m_connection.disconnect(); - m_connection = std::move(h); - return *this; + return *this = ScopedConnection(std::move(h)); } /** diff --git a/tests/signal/tst_signal.cpp b/tests/signal/tst_signal.cpp index d038b72..f4279ac 100644 --- a/tests/signal/tst_signal.cpp +++ b/tests/signal/tst_signal.cpp @@ -39,7 +39,7 @@ static_assert(std::is_nothrow_default_constructible{}); static_assert(!std::is_copy_constructible{}); static_assert(!std::is_copy_assignable{}); static_assert(std::is_nothrow_move_constructible{}); -static_assert(std::is_nothrow_move_assignable{}); +static_assert(!std::is_nothrow_move_assignable{}); class Button { @@ -518,7 +518,7 @@ TEST_CASE("ScopedConnection") REQUIRE(called); } - SUBCASE("A ScopedConnection disconnects when assigned") + SUBCASE("A ScopedConnection disconnects when assigned a new ConnectionHandle") { int numCalled = 0; Signal<> signal; @@ -531,6 +531,27 @@ TEST_CASE("ScopedConnection") CHECK_EQ(numCalled, 2); } + SUBCASE("A ScopedConnection disconnects when move assigned") + { + int numCalled = 0; + Signal<> signal; + { + ScopedConnection guard1 = signal.connect([&numCalled]() { numCalled++; }); + ScopedConnection guard2 = signal.connect([&numCalled]() { numCalled++; }); + + // This should drop the old connection of guard1 + guard1 = std::move(guard2); + CHECK(!guard2->isActive()); + CHECK(guard1->isActive()); + + signal.emit(); + CHECK_EQ(numCalled, 1); + } + // all connections should now be dropped + signal.emit(); + CHECK_EQ(numCalled, 1); + } + SUBCASE("A ScopedConnection can be moved") { bool called = false; From 7d263aeb3b92eb1f4c3fd23a5b9545243cf31435 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Thu, 14 Jul 2022 11:05:17 +0100 Subject: [PATCH 16/31] Don't define docs target when option is disabled Otherwise projects using KDBindings via fetchcontent will be unable to declare their own docs target due to a name clash. --- CMakeLists.txt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a07cfe9..2cd49e9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,10 +94,6 @@ endif() if(${PROJECT_NAME}_DOCS) add_subdirectory(docs) # needs to go last, in case there are build source files -else() - add_custom_target(docs - COMMAND ${CMAKE_COMMAND} -E echo "Sorry, there is no docs target since KDBindings_DOCS=OFF." - "Re-run cmake with the -DKDBindings_DOCS=ON option if you want to generate the documentation.") endif() if(${PROJECT_NAME}_IS_ROOT_PROJECT) From bb0fe09cfdd08d78f507ff681bcaffa8dd269578 Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Thu, 16 Feb 2023 16:05:13 +0100 Subject: [PATCH 17/31] Make KDBINDINGS_DECLARE_FUNCTION callable outside of within KDBindings namespace --- src/kdbindings/node_functions.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/kdbindings/node_functions.h b/src/kdbindings/node_functions.h index afdd463..e625129 100644 --- a/src/kdbindings/node_functions.h +++ b/src/kdbindings/node_functions.h @@ -53,9 +53,9 @@ struct any_bindables : std::integral_constant< */ #define KDBINDINGS_DECLARE_FUNCTION(NAME, FUNC) \ template \ - inline auto NAME(Ts &&...args)->std::enable_if_t::value, KDBindings::Private::Node>> \ + inline auto NAME(Ts &&...args)->std::enable_if_t<::KDBindings::Private::any_bindables::value, ::KDBindings::Private::Node<::KDBindings::Private::operator_node_result_t>> \ { \ - return Private::makeNode(FUNC, std::forward(args)...); \ + return ::KDBindings::Private::makeNode(FUNC, std::forward(args)...); \ } /** From 847b2f9dca537e9176b3bae8a06ad9aa3c24f1c5 Mon Sep 17 00:00:00 2001 From: Tobias Koenig Date: Fri, 31 Mar 2023 08:16:33 +0200 Subject: [PATCH 18/31] Fix compilation on Windows Rename 'interface' parameter to 'nodeInterface' to avoid compilation errors on Windows, where 'interface' is a predefined type in some system header. --- src/kdbindings/node.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/kdbindings/node.h b/src/kdbindings/node.h index 7d12224..ddccffc 100644 --- a/src/kdbindings/node.h +++ b/src/kdbindings/node.h @@ -100,8 +100,8 @@ template class Node { public: - Node(std::unique_ptr> &&interface) - : m_interface(std::move(interface)) + Node(std::unique_ptr> &&nodeInterface) + : m_interface(std::move(nodeInterface)) { } From 46d3004d874d239bf0f923592a00c2eff8cfe38a Mon Sep 17 00:00:00 2001 From: Allen Winter Date: Sat, 1 Apr 2023 07:25:17 -0400 Subject: [PATCH 19/31] update copyright year --- .reuse/dep5 | 4 ++-- CMakeLists.txt | 2 +- README.md | 2 +- cmake/KDBindingsConfig.cmake.in | 2 +- docs/CMakeLists.txt | 2 +- docs/api/CMakeLists.txt | 2 +- docs/api/footer.html | 2 +- docs/api/mkdocs/mkdocs.yml.cmake | 2 +- examples/01-simple-connection/CMakeLists.txt | 2 +- examples/01-simple-connection/main.cpp | 2 +- examples/02-signal-member/CMakeLists.txt | 2 +- examples/02-signal-member/main.cpp | 2 +- examples/03-member-arguments/CMakeLists.txt | 2 +- examples/03-member-arguments/main.cpp | 2 +- examples/04-simple-property/CMakeLists.txt | 2 +- examples/04-simple-property/main.cpp | 2 +- examples/05-property-bindings/CMakeLists.txt | 2 +- examples/05-property-bindings/main.cpp | 2 +- examples/06-lazy-property-bindings/CMakeLists.txt | 2 +- examples/06-lazy-property-bindings/main.cpp | 2 +- examples/07-advanced-connections/CMakeLists.txt | 2 +- examples/07-advanced-connections/main.cpp | 2 +- examples/08-managing-connections/CMakeLists.txt | 2 +- examples/08-managing-connections/main.cpp | 2 +- examples/CMakeLists.txt | 2 +- src/kdbindings/CMakeLists.txt | 2 +- src/kdbindings/binding.h | 2 +- src/kdbindings/binding_evaluator.h | 2 +- src/kdbindings/make_node.h | 2 +- src/kdbindings/node.h | 2 +- src/kdbindings/node_functions.h | 2 +- src/kdbindings/node_operators.h | 2 +- src/kdbindings/property.h | 2 +- src/kdbindings/property_updater.h | 2 +- src/kdbindings/signal.h | 2 +- src/kdbindings/utils.h | 2 +- tests/CMakeLists.txt | 2 +- tests/binding/CMakeLists.txt | 2 +- tests/binding/tst_binding.cpp | 2 +- tests/node/CMakeLists.txt | 2 +- tests/node/tst_node.cpp | 2 +- tests/property/CMakeLists.txt | 2 +- tests/property/tst_property.cpp | 2 +- tests/signal/CMakeLists.txt | 2 +- tests/signal/tst_signal.cpp | 2 +- tests/utils/CMakeLists.txt | 2 +- tests/utils/tst_gen_index_array.cpp | 2 +- tests/utils/tst_get_arity.cpp | 2 +- tests/utils/tst_utils_main.cpp | 2 +- 49 files changed, 50 insertions(+), 50 deletions(-) diff --git a/.reuse/dep5 b/.reuse/dep5 index 90f49e6..319a087 100644 --- a/.reuse/dep5 +++ b/.reuse/dep5 @@ -4,12 +4,12 @@ Upstream-Contact: Source: https://www.github.com/KDAB/KDBindings Files: *.json *.html *.md docs/api/Doxyfile.cmake docs/api/mkdocs/mkdocs.yml docs/api/mkdocs/docs/stylesheets/kdab.css -Copyright: 2020-2022 Klarälvdalens Datakonsult AB, a KDAB Group company +Copyright: 2020-2023 Klarälvdalens Datakonsult AB, a KDAB Group company License: MIT #artwork Files: docs/api/*.png docs/api/mkdocs/docs/assets/*.svg -Copyright: 2001-2022 Klarälvdalens Datakonsult AB, a KDAB Group company +Copyright: 2001-2023 Klarälvdalens Datakonsult AB, a KDAB Group company License: MIT #3rdparty cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 2cd49e9..b17b3a8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ # This file is part of KDBindings. # -# SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company +# SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company # Author: Sean Harmer # # SPDX-License-Identifier: MIT diff --git a/README.md b/README.md index fce42ae..63de4c9 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ Stay up-to-date with KDAB product announcements: Licensing ========= -KDBindings is (C) 2020-2021, Klarälvdalens Datakonsult AB, and is available under the +KDBindings is (C) 2020-2023, Klarälvdalens Datakonsult AB, and is available under the terms of the [MIT](https://github.com/KDAB/KDBindings/blob/main/LICENSES/MIT.txt) license. Contact KDAB at if you need different licensing options. diff --git a/cmake/KDBindingsConfig.cmake.in b/cmake/KDBindingsConfig.cmake.in index ae4f1cd..1e73d6c 100644 --- a/cmake/KDBindingsConfig.cmake.in +++ b/cmake/KDBindingsConfig.cmake.in @@ -1,6 +1,6 @@ # This file is part of KDBindings. # -# SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company +# SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company # Author: Juan Casafranca # # SPDX-License-Identifier: MIT diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index 67c59c2..f42e3eb 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -1,6 +1,6 @@ # This file is part of KDBindings. # -# SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company +# SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company # Author: Allen Winter # # SPDX-License-Identifier: MIT diff --git a/docs/api/CMakeLists.txt b/docs/api/CMakeLists.txt index 1dbd815..8f4cd98 100644 --- a/docs/api/CMakeLists.txt +++ b/docs/api/CMakeLists.txt @@ -1,6 +1,6 @@ # This file is part of KDBindings. # -# SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company +# SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company # Author: Allen Winter # # SPDX-License-Identifier: MIT diff --git a/docs/api/footer.html b/docs/api/footer.html index 1d73066..dc8e8aa 100644 --- a/docs/api/footer.html +++ b/docs/api/footer.html @@ -1,7 +1,7 @@
- © 2020-2021 Klarälvdalens Datakonsult AB (KDAB) + © 2020-2023 Klarälvdalens Datakonsult AB (KDAB)
"The Qt, C++ and OpenGL Experts"
https://www.kdab.com/ diff --git a/docs/api/mkdocs/mkdocs.yml.cmake b/docs/api/mkdocs/mkdocs.yml.cmake index d62cbe8..74033b0 100644 --- a/docs/api/mkdocs/mkdocs.yml.cmake +++ b/docs/api/mkdocs/mkdocs.yml.cmake @@ -18,7 +18,7 @@ theme: text: 'Open Sans' favicon: assets/assets_logo_tree.svg logo: assets/transparentWhiteKDAB.svg -copyright: "Copyright © 2020-2022 Klarälvdalens Datakonsult AB (KDAB)
The Qt, C++ and OpenGL Experts
https://www.kdab.com/" +copyright: "Copyright © 2020-2023 Klarälvdalens Datakonsult AB (KDAB)
The Qt, C++ and OpenGL Experts
https://www.kdab.com/" extra: # Disabling the generator notice is currently a # Insiders only feature. diff --git a/examples/01-simple-connection/CMakeLists.txt b/examples/01-simple-connection/CMakeLists.txt index e055d7f..3fd6c5e 100644 --- a/examples/01-simple-connection/CMakeLists.txt +++ b/examples/01-simple-connection/CMakeLists.txt @@ -1,6 +1,6 @@ # This file is part of KDBindings. # -# SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company +# SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company # Author: Sean Harmer # # SPDX-License-Identifier: MIT diff --git a/examples/01-simple-connection/main.cpp b/examples/01-simple-connection/main.cpp index c433e5c..2b3d329 100644 --- a/examples/01-simple-connection/main.cpp +++ b/examples/01-simple-connection/main.cpp @@ -1,7 +1,7 @@ /* This file is part of KDBindings. - SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company + SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company Author: Sean Harmer SPDX-License-Identifier: MIT diff --git a/examples/02-signal-member/CMakeLists.txt b/examples/02-signal-member/CMakeLists.txt index 55dc59f..aa9873e 100644 --- a/examples/02-signal-member/CMakeLists.txt +++ b/examples/02-signal-member/CMakeLists.txt @@ -1,6 +1,6 @@ # This file is part of KDBindings. # -# SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company +# SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company # Author: Sean Harmer # # SPDX-License-Identifier: MIT diff --git a/examples/02-signal-member/main.cpp b/examples/02-signal-member/main.cpp index eb6ba67..b816cdc 100644 --- a/examples/02-signal-member/main.cpp +++ b/examples/02-signal-member/main.cpp @@ -1,7 +1,7 @@ /* This file is part of KDBindings. - SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company + SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company Author: Sean Harmer SPDX-License-Identifier: MIT diff --git a/examples/03-member-arguments/CMakeLists.txt b/examples/03-member-arguments/CMakeLists.txt index 71c8772..612ce31 100644 --- a/examples/03-member-arguments/CMakeLists.txt +++ b/examples/03-member-arguments/CMakeLists.txt @@ -1,6 +1,6 @@ # This file is part of KDBindings. # -# SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company +# SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company # Author: Sean Harmer # # SPDX-License-Identifier: MIT diff --git a/examples/03-member-arguments/main.cpp b/examples/03-member-arguments/main.cpp index 56f87e8..847199f 100644 --- a/examples/03-member-arguments/main.cpp +++ b/examples/03-member-arguments/main.cpp @@ -1,7 +1,7 @@ /* This file is part of KDBindings. - SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company + SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company Author: Sean Harmer SPDX-License-Identifier: MIT diff --git a/examples/04-simple-property/CMakeLists.txt b/examples/04-simple-property/CMakeLists.txt index 6dccbdd..a205e48 100644 --- a/examples/04-simple-property/CMakeLists.txt +++ b/examples/04-simple-property/CMakeLists.txt @@ -1,6 +1,6 @@ # This file is part of KDBindings. # -# SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company +# SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company # Author: Sean Harmer # # SPDX-License-Identifier: MIT diff --git a/examples/04-simple-property/main.cpp b/examples/04-simple-property/main.cpp index ef58ffd..8f89519 100644 --- a/examples/04-simple-property/main.cpp +++ b/examples/04-simple-property/main.cpp @@ -1,7 +1,7 @@ /* This file is part of KDBindings. - SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company + SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company Author: Sean Harmer SPDX-License-Identifier: MIT diff --git a/examples/05-property-bindings/CMakeLists.txt b/examples/05-property-bindings/CMakeLists.txt index b90cc32..832fed9 100644 --- a/examples/05-property-bindings/CMakeLists.txt +++ b/examples/05-property-bindings/CMakeLists.txt @@ -1,6 +1,6 @@ # This file is part of KDBindings. # -# SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company +# SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company # Author: Sean Harmer # # SPDX-License-Identifier: MIT diff --git a/examples/05-property-bindings/main.cpp b/examples/05-property-bindings/main.cpp index 217a3eb..1e863b5 100644 --- a/examples/05-property-bindings/main.cpp +++ b/examples/05-property-bindings/main.cpp @@ -1,7 +1,7 @@ /* This file is part of KDBindings. - SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company + SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company Author: Sean Harmer SPDX-License-Identifier: MIT diff --git a/examples/06-lazy-property-bindings/CMakeLists.txt b/examples/06-lazy-property-bindings/CMakeLists.txt index 95353a4..66b887f 100644 --- a/examples/06-lazy-property-bindings/CMakeLists.txt +++ b/examples/06-lazy-property-bindings/CMakeLists.txt @@ -1,6 +1,6 @@ # This file is part of KDBindings. # -# SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company +# SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company # Author: Sean Harmer # # SPDX-License-Identifier: MIT diff --git a/examples/06-lazy-property-bindings/main.cpp b/examples/06-lazy-property-bindings/main.cpp index c4c70e7..980e286 100644 --- a/examples/06-lazy-property-bindings/main.cpp +++ b/examples/06-lazy-property-bindings/main.cpp @@ -1,7 +1,7 @@ /* This file is part of KDBindings. - SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company + SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company Author: Sean Harmer SPDX-License-Identifier: MIT diff --git a/examples/07-advanced-connections/CMakeLists.txt b/examples/07-advanced-connections/CMakeLists.txt index 89f6495..53849b5 100644 --- a/examples/07-advanced-connections/CMakeLists.txt +++ b/examples/07-advanced-connections/CMakeLists.txt @@ -1,6 +1,6 @@ # This file is part of KDBindings. # -# SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company +# SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company # Author: Leon Matthes # # SPDX-License-Identifier: MIT diff --git a/examples/07-advanced-connections/main.cpp b/examples/07-advanced-connections/main.cpp index 82e0dc5..71f1463 100644 --- a/examples/07-advanced-connections/main.cpp +++ b/examples/07-advanced-connections/main.cpp @@ -1,7 +1,7 @@ /* This file is part of KDBindings. - SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company + SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company Author: Leon Matthes SPDX-License-Identifier: MIT diff --git a/examples/08-managing-connections/CMakeLists.txt b/examples/08-managing-connections/CMakeLists.txt index d25fd86..0bc9b3c 100644 --- a/examples/08-managing-connections/CMakeLists.txt +++ b/examples/08-managing-connections/CMakeLists.txt @@ -1,6 +1,6 @@ # This file is part of KDBindings. # -# SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company +# SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company # Author: Leon Matthes # # SPDX-License-Identifier: MIT diff --git a/examples/08-managing-connections/main.cpp b/examples/08-managing-connections/main.cpp index 814f859..8048ddb 100644 --- a/examples/08-managing-connections/main.cpp +++ b/examples/08-managing-connections/main.cpp @@ -1,7 +1,7 @@ /* This file is part of KDBindings. - SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company + SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company Author: Leon Matthes SPDX-License-Identifier: MIT diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 0398be2..60aa9b2 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,6 +1,6 @@ # This file is part of KDBindings. # -# SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company +# SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company # Author: Sean Harmer # # SPDX-License-Identifier: MIT diff --git a/src/kdbindings/CMakeLists.txt b/src/kdbindings/CMakeLists.txt index 10cb6cb..83c2080 100644 --- a/src/kdbindings/CMakeLists.txt +++ b/src/kdbindings/CMakeLists.txt @@ -1,6 +1,6 @@ # This file is part of KDBindings. # -# SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company +# SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company # Author: Sean Harmer # # SPDX-License-Identifier: MIT diff --git a/src/kdbindings/binding.h b/src/kdbindings/binding.h index ae8a037..e99eabc 100644 --- a/src/kdbindings/binding.h +++ b/src/kdbindings/binding.h @@ -1,7 +1,7 @@ /* This file is part of KDBindings. - SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company + SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company Author: Sean Harmer SPDX-License-Identifier: MIT diff --git a/src/kdbindings/binding_evaluator.h b/src/kdbindings/binding_evaluator.h index e73a5c4..fdcf328 100644 --- a/src/kdbindings/binding_evaluator.h +++ b/src/kdbindings/binding_evaluator.h @@ -1,7 +1,7 @@ /* This file is part of KDBindings. - SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company + SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company Author: Sean Harmer SPDX-License-Identifier: MIT diff --git a/src/kdbindings/make_node.h b/src/kdbindings/make_node.h index f897b33..e8053ee 100644 --- a/src/kdbindings/make_node.h +++ b/src/kdbindings/make_node.h @@ -1,7 +1,7 @@ /* This file is part of KDBindings. - SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company + SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company Author: Sean Harmer SPDX-License-Identifier: MIT diff --git a/src/kdbindings/node.h b/src/kdbindings/node.h index ddccffc..f17fcd7 100644 --- a/src/kdbindings/node.h +++ b/src/kdbindings/node.h @@ -1,7 +1,7 @@ /* This file is part of KDBindings. - SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company + SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company Author: Sean Harmer SPDX-License-Identifier: MIT diff --git a/src/kdbindings/node_functions.h b/src/kdbindings/node_functions.h index e625129..a8bcfdd 100644 --- a/src/kdbindings/node_functions.h +++ b/src/kdbindings/node_functions.h @@ -1,7 +1,7 @@ /* This file is part of KDBindings. - SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company + SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company Author: Sean Harmer SPDX-License-Identifier: MIT diff --git a/src/kdbindings/node_operators.h b/src/kdbindings/node_operators.h index 7bd3fc9..e79ae68 100644 --- a/src/kdbindings/node_operators.h +++ b/src/kdbindings/node_operators.h @@ -1,7 +1,7 @@ /* This file is part of KDBindings. - SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company + SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company Author: Sean Harmer SPDX-License-Identifier: MIT diff --git a/src/kdbindings/property.h b/src/kdbindings/property.h index a707c18..682adf4 100644 --- a/src/kdbindings/property.h +++ b/src/kdbindings/property.h @@ -1,7 +1,7 @@ /* This file is part of KDBindings. - SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company + SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company Author: Sean Harmer SPDX-License-Identifier: MIT diff --git a/src/kdbindings/property_updater.h b/src/kdbindings/property_updater.h index bef2632..8aeb014 100644 --- a/src/kdbindings/property_updater.h +++ b/src/kdbindings/property_updater.h @@ -1,7 +1,7 @@ /* This file is part of KDBindings. - SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company + SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company Author: Sean Harmer SPDX-License-Identifier: MIT diff --git a/src/kdbindings/signal.h b/src/kdbindings/signal.h index c141ee2..87d0a7c 100644 --- a/src/kdbindings/signal.h +++ b/src/kdbindings/signal.h @@ -1,7 +1,7 @@ /* This file is part of KDBindings. - SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company + SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company Author: Sean Harmer SPDX-License-Identifier: MIT diff --git a/src/kdbindings/utils.h b/src/kdbindings/utils.h index f9ef864..f6c5b07 100644 --- a/src/kdbindings/utils.h +++ b/src/kdbindings/utils.h @@ -1,7 +1,7 @@ /* This file is part of KDBindings. - SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company + SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company Author: Leon Matthes SPDX-License-Identifier: MIT diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 5e5d085..f63cc00 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,6 +1,6 @@ # This file is part of KDBindings. # -# SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company +# SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company # Author: Sean Harmer # # SPDX-License-Identifier: MIT diff --git a/tests/binding/CMakeLists.txt b/tests/binding/CMakeLists.txt index 6e09654..34982f3 100644 --- a/tests/binding/CMakeLists.txt +++ b/tests/binding/CMakeLists.txt @@ -1,6 +1,6 @@ # This file is part of KDBindings. # -# SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company +# SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company # Author: Sean Harmer # # SPDX-License-Identifier: MIT diff --git a/tests/binding/tst_binding.cpp b/tests/binding/tst_binding.cpp index ec49ea7..8f6bc8c 100644 --- a/tests/binding/tst_binding.cpp +++ b/tests/binding/tst_binding.cpp @@ -1,7 +1,7 @@ /* This file is part of KDBindings. - SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company + SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company Author: Sean Harmer SPDX-License-Identifier: MIT diff --git a/tests/node/CMakeLists.txt b/tests/node/CMakeLists.txt index 12ac88c..76d831a 100644 --- a/tests/node/CMakeLists.txt +++ b/tests/node/CMakeLists.txt @@ -1,6 +1,6 @@ # This file is part of KDBindings. # -# SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company +# SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company # Author: Sean Harmer # # SPDX-License-Identifier: MIT diff --git a/tests/node/tst_node.cpp b/tests/node/tst_node.cpp index 0cca955..58c45c8 100644 --- a/tests/node/tst_node.cpp +++ b/tests/node/tst_node.cpp @@ -1,7 +1,7 @@ /* This file is part of KDBindings. - SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company + SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company Author: Sean Harmer SPDX-License-Identifier: MIT diff --git a/tests/property/CMakeLists.txt b/tests/property/CMakeLists.txt index 2ef2995..6a103e1 100644 --- a/tests/property/CMakeLists.txt +++ b/tests/property/CMakeLists.txt @@ -1,6 +1,6 @@ # This file is part of KDBindings. # -# SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company +# SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company # Author: Sean Harmer # # SPDX-License-Identifier: MIT diff --git a/tests/property/tst_property.cpp b/tests/property/tst_property.cpp index b277445..3bf31be 100644 --- a/tests/property/tst_property.cpp +++ b/tests/property/tst_property.cpp @@ -1,7 +1,7 @@ /* This file is part of KDBindings. - SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company + SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company Author: Sean Harmer SPDX-License-Identifier: MIT diff --git a/tests/signal/CMakeLists.txt b/tests/signal/CMakeLists.txt index 92d6171..3c4061d 100644 --- a/tests/signal/CMakeLists.txt +++ b/tests/signal/CMakeLists.txt @@ -1,6 +1,6 @@ # This file is part of KDBindings. # -# SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company +# SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company # Author: Sean Harmer # # SPDX-License-Identifier: MIT diff --git a/tests/signal/tst_signal.cpp b/tests/signal/tst_signal.cpp index f4279ac..683b6c8 100644 --- a/tests/signal/tst_signal.cpp +++ b/tests/signal/tst_signal.cpp @@ -1,7 +1,7 @@ /* This file is part of KDBindings. - SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company + SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company Author: Sean Harmer SPDX-License-Identifier: MIT diff --git a/tests/utils/CMakeLists.txt b/tests/utils/CMakeLists.txt index 66e71e2..796561c 100644 --- a/tests/utils/CMakeLists.txt +++ b/tests/utils/CMakeLists.txt @@ -1,6 +1,6 @@ # This file is part of KDBindings. # -# SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company +# SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company # Author: Leon Matthes # # SPDX-License-Identifier: MIT diff --git a/tests/utils/tst_gen_index_array.cpp b/tests/utils/tst_gen_index_array.cpp index 4f570c4..4f9ea8b 100644 --- a/tests/utils/tst_gen_index_array.cpp +++ b/tests/utils/tst_gen_index_array.cpp @@ -1,7 +1,7 @@ /* This file is part of KDBindings. - SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company + SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company Author: Leon Matthes SPDX-License-Identifier: MIT diff --git a/tests/utils/tst_get_arity.cpp b/tests/utils/tst_get_arity.cpp index 21ce4fc..9768063 100644 --- a/tests/utils/tst_get_arity.cpp +++ b/tests/utils/tst_get_arity.cpp @@ -1,7 +1,7 @@ /* This file is part of KDBindings. - SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company + SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company Author: Leon Matthes SPDX-License-Identifier: MIT diff --git a/tests/utils/tst_utils_main.cpp b/tests/utils/tst_utils_main.cpp index 6ec5251..d7aaf79 100644 --- a/tests/utils/tst_utils_main.cpp +++ b/tests/utils/tst_utils_main.cpp @@ -1,7 +1,7 @@ /* This file is part of KDBindings. - SPDX-FileCopyrightText: 2021-2022 Klarälvdalens Datakonsult AB, a KDAB Group company + SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company Author: Leon Matthes SPDX-License-Identifier: MIT From 6f0231ce026c202366c4fba1be3c76d4df49ef52 Mon Sep 17 00:00:00 2001 From: Daniel Nicoletti Date: Thu, 21 Sep 2023 21:54:23 -0300 Subject: [PATCH 20/31] Add GitHub Actions --- .github/workflows/build.yml | 58 +++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..f8646fc --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,58 @@ +# SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group company +# +# SPDX-License-Identifier: MIT + +name: CI + +on: [push, pull_request] + +jobs: + build: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: true + matrix: + os: + - ubuntu-22.04 + #- ubuntu-20.04 + - windows-2022 + #- windows-2019 + - macos-12 + #- macos-11 + build_type: + - Debug + - Release + + steps: + - name: Checkout sources + uses: actions/checkout@v4 + + - name: Create build directory + run: mkdir build + + - name: Install ninja-build tool + uses: turtlesec-no/get-ninja@main + + - name: Make sure MSVC is found when Ninja generator is in use + uses: ilammy/msvc-dev-cmd@v1 + + - name: Configure project + run: > + cmake -S . -B ./build -G Ninja + -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} + -DKDBindings_TESTS=${{ matrix.build_type == 'Debug' }} + -DKDBindings_EXAMPLES=${{ matrix.build_type == 'Debug' }} + -DKDBindings_DOCS=${{ matrix.build_type == 'Debug' && runner.os == 'Linux' }} + + - name: Build Project + run: cmake --build ./build + + - name: Run tests + if: ${{ matrix.build_type == 'Debug' }} + run: ctest --test-dir ./build -C ${{ matrix.build_type }} --output-on-failure + + - name: Read tests log when it fails + uses: andstor/file-reader-action@v1 + if: ${{ failure() && matrix.build_type == 'Debug' }} + with: + path: "./build/Testing/Temporary/LastTest.log" From 86d6bd56597013dcae645e902e4bdac69eccf64d Mon Sep 17 00:00:00 2001 From: Leon Matthes Date: Mon, 8 Jan 2024 13:34:36 +0100 Subject: [PATCH 21/31] Deferred connection evaluation (#48) * Deferred connection evaluation * handle the evaluator object lifetime and added tests * update connection_evaluator.h * test and documentation update * implementing dequeueSlotInvocation on disconnect and update the documentations * Update connection_evaluator.h * Adding the connection_handle file * change the deferred slot signature and manage connectionHandle correctly * deque on deconstruct and nits * Refactor & Fix up disconnections on deconstruct * Remove some duplicate checks * Incorporate feedback from @MiKom - Add license header to connection_evaluator.h - Use slotInvocation instead of Connection in the ConnectionEvaluator - Add warnings that deferred connections are experimental - Improved documentation for deferred connections --------- Co-authored-by: Shivam Kunwar Co-authored-by: Shivam <75530356+phyBrackets@users.noreply.github.com> --- src/kdbindings/CMakeLists.txt | 2 + src/kdbindings/connection_evaluator.h | 96 +++++++++ src/kdbindings/connection_handle.h | 209 ++++++++++++++++++ src/kdbindings/genindex_array.h | 7 +- src/kdbindings/signal.h | 297 ++++++++++---------------- tests/signal/tst_signal.cpp | 166 ++++++++++++++ 6 files changed, 597 insertions(+), 180 deletions(-) create mode 100644 src/kdbindings/connection_evaluator.h create mode 100644 src/kdbindings/connection_handle.h diff --git a/src/kdbindings/CMakeLists.txt b/src/kdbindings/CMakeLists.txt index 83c2080..8a99730 100644 --- a/src/kdbindings/CMakeLists.txt +++ b/src/kdbindings/CMakeLists.txt @@ -18,6 +18,8 @@ set(HEADERS property.h property_updater.h signal.h + connection_evaluator.h + connection_handle.h utils.h ) diff --git a/src/kdbindings/connection_evaluator.h b/src/kdbindings/connection_evaluator.h new file mode 100644 index 0000000..184644e --- /dev/null +++ b/src/kdbindings/connection_evaluator.h @@ -0,0 +1,96 @@ +/* + This file is part of KDBindings. + + SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group company + Author: Shivam Kunwar + + SPDX-License-Identifier: MIT + + Contact KDAB at for commercial licensing options. +*/ +#pragma once + +#include +#include + +#include + +namespace KDBindings { + +/** + * @brief Manages and evaluates deferred Signal connections. + * + * @warning Deferred connections are experimental and may be removed or changed in the future. + * + * The ConnectionEvaluator class is responsible for managing and evaluating connections + * to Signals. It provides mechanisms to delay and control the evaluation of connections. + * It therefore allows controlling when and on which thread slots connected to a Signal are executed. + * + * @see Signal::connectDeferred() + */ +class ConnectionEvaluator +{ + +public: + /** ConnectionEvaluators are default constructible */ + ConnectionEvaluator() = default; + + /** Connectionevaluators are not copyable */ + // As it is designed to manage connections, + // and copying it could lead to unexpected behavior, including duplication of connections and issues + // related to connection lifetimes. Therefore, it is intentionally made non-copyable. + ConnectionEvaluator(const ConnectionEvaluator &) noexcept = delete; + + ConnectionEvaluator &operator=(const ConnectionEvaluator &) noexcept = delete; + + /** ConnectionEvaluators are not moveable */ + // As they are captures by-reference + // by the Signal, so moving them would lead to a dangling reference. + ConnectionEvaluator(ConnectionEvaluator &&other) noexcept = delete; + + ConnectionEvaluator &operator=(ConnectionEvaluator &&other) noexcept = delete; + + /** + * @brief Evaluate the deferred connections. + * + * This function is responsible for evaluating and executing deferred connections. + * This function is thread safe. + */ + void evaluateDeferredConnections() + { + std::lock_guard lock(m_slotInvocationMutex); + + for (auto &pair : m_deferredSlotInvocations) { + pair.second(); + } + m_deferredSlotInvocations.clear(); + } + +private: + template + friend class Signal; + + void enqueueSlotInvocation(const ConnectionHandle &handle, const std::function &slotInvocation) + { + std::lock_guard lock(m_slotInvocationMutex); + m_deferredSlotInvocations.push_back({ handle, std::move(slotInvocation) }); + } + + void dequeueSlotInvocation(const ConnectionHandle &handle) + { + std::lock_guard lock(m_slotInvocationMutex); + + auto handleMatches = [&handle](const auto &invocationPair) { + return invocationPair.first == handle; + }; + + // Remove all invocations that match the handle + m_deferredSlotInvocations.erase( + std::remove_if(m_deferredSlotInvocations.begin(), m_deferredSlotInvocations.end(), handleMatches), + m_deferredSlotInvocations.end()); + } + + std::vector>> m_deferredSlotInvocations; + std::mutex m_slotInvocationMutex; +}; +} // namespace KDBindings diff --git a/src/kdbindings/connection_handle.h b/src/kdbindings/connection_handle.h new file mode 100644 index 0000000..247c9d5 --- /dev/null +++ b/src/kdbindings/connection_handle.h @@ -0,0 +1,209 @@ +/* + This file is part of KDBindings. + + SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company + Author: Sean Harmer + + SPDX-License-Identifier: MIT + + Contact KDAB at for commercial licensing options. +*/ + +#include +#include +#include + +namespace KDBindings { + +template +class Signal; + +class ConnectionHandle; + +namespace Private { +// +// This class defines a virtual interface, that the Signal this ConnectionHandle refers +// to must implement. +// It allows ConnectionHandle to refer to this non-template class, which then dispatches +// to the template implementation using virtual function calls. +// It allows ConnectionHandle to be a non-template class. +class SignalImplBase : public std::enable_shared_from_this +{ +public: + SignalImplBase() = default; + + virtual ~SignalImplBase() = default; + + virtual void disconnect(const ConnectionHandle &handle) = 0; + virtual bool blockConnection(const GenerationalIndex &id, bool blocked) = 0; + virtual bool isConnectionActive(const GenerationalIndex &id) const = 0; + virtual bool isConnectionBlocked(const GenerationalIndex &id) const = 0; +}; + +} // namespace Private + +/** + * @brief A ConnectionHandle represents the connection of a Signal + * to a slot (i.e. a function that is called when the Signal is emitted). + * + * It is returned from a Signal when a connection is created and used to + * manage the connection by disconnecting, (un)blocking it and checking its state. + **/ +class ConnectionHandle +{ +public: + /** + * A ConnectionHandle can be default constructed. + * In this case the ConnectionHandle will not reference any active connection (i.e. isActive() will return false), + * and not belong to any Signal. + **/ + ConnectionHandle() = default; + + /** + * A ConnectionHandle can be copied. + **/ + ConnectionHandle(const ConnectionHandle &) = default; + ConnectionHandle &operator=(const ConnectionHandle &) = default; + + /** + * A ConnectionHandle can be moved. + **/ + ConnectionHandle(ConnectionHandle &&) = default; + ConnectionHandle &operator=(ConnectionHandle &&) = default; + + /** + * Disconnect the slot. + * + * When this function is called, the function that was passed to Signal::connect + * to create this ConnectionHandle will no longer be called when the Signal is emitted. + * + * If the ConnectionHandle is not active or the connection has already been disconnected, + * nothing happens. + * + * After this call, the ConnectionHandle will be inactive (i.e. isActive() returns false) + * and will no longer belong to any Signal (i.e. belongsTo returns false). + **/ + void disconnect() + { + if (auto shared_impl = checkedLock()) { + shared_impl->disconnect(*this); + } + + // ConnectionHandle is no longer active; + m_signalImpl.reset(); + } + + /** + * Check whether the connection of this ConnectionHandle is active. + * + * @return true if the ConnectionHandle refers to an active Signal + * and the connection was not disconnected previously, false otherwise. + **/ + bool isActive() const + { + return static_cast(checkedLock()); + } + + /** + * Sets the block state of the connection. + * If a connection is blocked, emitting the Signal will no longer call this + * connections slot, until the connection is unblocked. + * + * Behaves the same as calling Signal::blockConnection with this + * ConnectionHandle as argument. + * + * To temporarily block a connection, consider using an instance of ConnectionBlocker, + * which offers a RAII-style implementation that makes sure the connection is always + * returned to its original state. + * + * @param blocked The new blocked state of the connection. + * @return whether the connection was previously blocked. + * @throw std::out_of_range Throws if the connection is not active (i.e. isActive() returns false). + **/ + bool block(bool blocked) + { + if (auto shared_impl = checkedLock()) { + return shared_impl->blockConnection(*m_id, blocked); + } + throw std::out_of_range("Cannot block a non-active connection!"); + } + + /** + * Checks whether the connection is currently blocked. + * + * To change the blocked state of a connection, call ConnectionHandle::block. + * + * @return whether the connection is currently blocked. + **/ + bool isBlocked() const + { + if (auto shared_impl = checkedLock()) { + return shared_impl->isConnectionBlocked(*m_id); + } + throw std::out_of_range("Cannot check whether a non-active connection is blocked!"); + } + + /** + * Check whether this ConnectionHandle belongs to the given Signal. + * + * @return true if this ConnectionHandle refers to a connection within the given Signal + **/ + template + bool belongsTo(const Signal &signal) const + { + auto shared_impl = m_signalImpl.lock(); + return shared_impl && shared_impl == std::static_pointer_cast(signal.m_impl); + } + + // Define an operator== function to compare ConnectionHandle objects. + bool operator==(const ConnectionHandle &other) const + { + auto thisSignalImpl = m_signalImpl.lock(); + auto otherSignalImpl = other.m_signalImpl.lock(); + + // If both signalImpl pointers are valid, compare them along with the IDs. + if (thisSignalImpl && otherSignalImpl) { + return (thisSignalImpl == otherSignalImpl) && (m_id == other.m_id); + } + + // If neither instance has an ID, and both signalImpl pointers are invalid, consider them equal. + if (!m_id.has_value() && !other.m_id.has_value() && !thisSignalImpl && !otherSignalImpl) { + return true; + } + + // In all other cases, they are not equal. + return false; + } + +private: + template + friend class Signal; + + std::weak_ptr m_signalImpl; + std::optional m_id; + + // private, so it is only available from Signal + ConnectionHandle(std::weak_ptr signalImpl, std::optional id) + : m_signalImpl{ std::move(signalImpl) }, m_id{ std::move(id) } + { + } + void setId(const Private::GenerationalIndex &id) + { + m_id = id; + } + + // Checks that the weak_ptr can be locked and that the connection is + // still active + std::shared_ptr checkedLock() const + { + if (m_id.has_value()) { + auto shared_impl = m_signalImpl.lock(); + if (shared_impl && shared_impl->isConnectionActive(*m_id)) { + return shared_impl; + } + } + return nullptr; + } +}; + +} // namespace KDBindings diff --git a/src/kdbindings/genindex_array.h b/src/kdbindings/genindex_array.h index ab5cddf..4da17d8 100644 --- a/src/kdbindings/genindex_array.h +++ b/src/kdbindings/genindex_array.h @@ -36,6 +36,11 @@ namespace Private { struct GenerationalIndex { uint32_t index = 0; uint32_t generation = 0; + + bool operator==(const GenerationalIndex &rhs) const + { + return index == rhs.index && generation == rhs.generation; + } }; class GenerationalIndexAllocator @@ -202,6 +207,6 @@ class GenerationalIndexArray } }; -} //namespace Private +} // namespace Private } // namespace KDBindings diff --git a/src/kdbindings/signal.h b/src/kdbindings/signal.h index 87d0a7c..44e0121 100644 --- a/src/kdbindings/signal.h +++ b/src/kdbindings/signal.h @@ -12,13 +12,12 @@ #pragma once #include -#include #include -#include #include #include #include +#include #include #include @@ -29,171 +28,6 @@ */ namespace KDBindings { -template -class Signal; - -namespace Private { -// -// This class defines a virtual interface, that the Signal this ConnectionHandle refers -// to must implement. -// It allows ConnectionHandle to refer to this non-template class, which then dispatches -// to the template implementation using virtual function calls. -// It allows ConnectionHandle to be a non-template class. -class SignalImplBase -{ -public: - SignalImplBase() = default; - - virtual ~SignalImplBase() = default; - - virtual void disconnect(const GenerationalIndex &id) = 0; - virtual bool blockConnection(const GenerationalIndex &id, bool blocked) = 0; - virtual bool isConnectionActive(const GenerationalIndex &id) const = 0; - virtual bool isConnectionBlocked(const GenerationalIndex &id) const = 0; -}; - -} // namespace Private - -/** - * @brief A ConnectionHandle represents the connection of a Signal - * to a slot (i.e. a function that is called when the Signal is emitted). - * - * It is returned from a Signal when a connection is created and used to - * manage the connection by disconnecting, (un)blocking it and checking its state. - * - * To make sure a Connection to an object is disconnected correctly, consider - * storing a ScopedConnection to its ConnectionHandle inside the object. - **/ -class ConnectionHandle -{ -public: - /** - * A ConnectionHandle can be default constructed. - * In this case the ConnectionHandle will not reference any active connection (i.e. isActive() will return false), - * and not belong to any Signal. - **/ - ConnectionHandle() = default; - - /** - * A ConnectionHandle can be copied. - **/ - ConnectionHandle(const ConnectionHandle &) = default; - ConnectionHandle &operator=(const ConnectionHandle &) = default; - - /** - * A ConnectionHandle can be moved. - **/ - ConnectionHandle(ConnectionHandle &&) = default; - ConnectionHandle &operator=(ConnectionHandle &&) = default; - - /** - * Disconnect the slot. - * - * When this function is called, the function that was passed to Signal::connect - * to create this ConnectionHandle will no longer be called when the Signal is emitted. - * - * If the ConnectionHandle is not active or the connection has already been disconnected, - * nothing happens. - * - * After this call, the ConnectionHandle will be inactive (i.e. isActive() returns false) - * and will no longer belong to any Signal (i.e. belongsTo returns false). - **/ - void disconnect() - { - if (auto shared_impl = checkedLock()) { - shared_impl->disconnect(m_id); - } - // ConnectionHandle is no longer active; - m_signalImpl.reset(); - } - - /** - * Check whether the connection of this ConnectionHandle is active. - * - * @return true if the ConnectionHandle refers to an active Signal - * and the connection was not disconnected previously, false otherwise. - **/ - bool isActive() const - { - return static_cast(checkedLock()); - } - - /** - * Sets the block state of the connection. - * If a connection is blocked, emitting the Signal will no longer call this - * connections slot, until the connection is unblocked. - * - * Behaves the same as calling Signal::blockConnection with this - * ConnectionHandle as argument. - * - * To temporarily block a connection, consider using an instance of ConnectionBlocker, - * which offers a RAII-style implementation that makes sure the connection is always - * returned to its original state. - * - * @param blocked The new blocked state of the connection. - * @return whether the connection was previously blocked. - * @throw std::out_of_range Throws if the connection is not active (i.e. isActive() returns false). - **/ - bool block(bool blocked) - { - if (auto shared_impl = checkedLock()) { - return shared_impl->blockConnection(m_id, blocked); - } - throw std::out_of_range("Cannot block a non-active connection!"); - } - - /** - * Checks whether the connection is currently blocked. - * - * To change the blocked state of a connection, call ConnectionHandle::block. - * - * @return whether the connection is currently blocked. - **/ - bool isBlocked() const - { - if (auto shared_impl = checkedLock()) { - return shared_impl->isConnectionBlocked(m_id); - } - throw std::out_of_range("Cannot check whether a non-active connection is blocked!"); - } - - /** - * Check whether this ConnectionHandle belongs to the given Signal. - * - * @return true if this ConnectionHandle refers to a connection within the given Signal - **/ - template - bool belongsTo(const Signal &signal) const - { - auto shared_impl = m_signalImpl.lock(); - return shared_impl && shared_impl == std::static_pointer_cast(signal.m_impl); - } - -private: - template - friend class Signal; - - std::weak_ptr m_signalImpl; - Private::GenerationalIndex m_id; - - // private, so it is only available from Signal - ConnectionHandle(std::weak_ptr signalImpl, Private::GenerationalIndex id) - : m_signalImpl{ std::move(signalImpl) }, m_id{ std::move(id) } - { - } - - // Checks that the weak_ptr can be locked and that the connection is - // still active - std::shared_ptr checkedLock() const - { - auto shared_impl = m_signalImpl.lock(); - if (shared_impl && shared_impl->isConnectionActive(m_id)) { - return shared_impl; - } - return nullptr; - } -}; - /** * @brief A Signal provides a mechanism for communication between objects. * @@ -207,6 +41,14 @@ class ConnectionHandle * * The Args type parameter pack describe which value types the Signal will emit. * + * Deferred Connection: + * + * KDBindings::Signal supports deferred connections, enabling the decoupling of signal + * emission from the execution of connected slots. With deferred connections, you can + * connect slots to the Signal that are not immediately executed when the signal is emitted. + * Instead, you can evaluate these deferred connections at a later time, allowing for + * asynchronous or delayed execution of connected slots. + * * Examples: * - @ref 01-simple-connection/main.cpp * - @ref 02-signal-member/main.cpp @@ -242,18 +84,72 @@ class Signal // value can be used to disconnect the function again. Private::GenerationalIndex connect(std::function const &slot) { - return m_connections.insert({ slot }); + Connection newConnection; + newConnection.slot = slot; + return m_connections.insert(std::move(newConnection)); + } + + // Establish a deferred connection between signal and slot, where ConnectionEvaluator object + // is used to queue all the connection to evaluate later. The returned + // value can be used to disconnect the slot later. + Private::GenerationalIndex connectDeferred(const std::shared_ptr &evaluator, std::function const &slot) + { + auto weakEvaluator = std::weak_ptr(evaluator); + + auto deferredSlot = [weakEvaluator = std::move(weakEvaluator), slot](const ConnectionHandle &handle, Args... args) { + if (auto evaluatorPtr = weakEvaluator.lock()) { + auto lambda = [slot, args...]() { + slot(args...); + }; + evaluatorPtr->enqueueSlotInvocation(handle, lambda); + } else { + throw std::runtime_error("ConnectionEvaluator is no longer alive"); + } + }; + + Connection newConnection; + newConnection.m_connectionEvaluator = evaluator; + newConnection.slotDeferred = deferredSlot; + + return m_connections.insert(std::move(newConnection)); } // Disconnects a previously connected function - void disconnect(const Private::GenerationalIndex &id) override + void disconnect(const ConnectionHandle &handle) override { - m_connections.erase(id); + // If the connection evaluator is still valid, remove any queued up slot invocations + // associated with the given handle to prevent them from being evaluated in the future. + auto idOpt = handle.m_id; // Retrieve the connection associated with this id + + // Proceed only if the id is valid + if (idOpt.has_value()) { + auto id = idOpt.value(); + + // Retrieve the connection associated with this id + auto connection = m_connections.get(id); + if (connection && connection->slotDeferred) { + if (auto evaluatorPtr = connection->m_connectionEvaluator.lock()) { + evaluatorPtr->dequeueSlotInvocation(handle); + } + } + + m_connections.erase(id); + } } // Disconnects all previously connected functions void disconnectAll() { + const auto numEntries = m_connections.entriesSize(); + + const auto sharedThis = shared_from_this(); + for (auto i = decltype(numEntries){ 0 }; i < numEntries; ++i) { + const auto indexOpt = m_connections.indexAtEntry(i); + if (sharedThis && indexOpt) { + disconnect(ConnectionHandle(sharedThis, *indexOpt)); + } + } + m_connections.clear(); } @@ -284,9 +180,9 @@ class Signal } } - // Calls all connected functions - void emit(Args... p) const + void emit(Args... p) { + const auto numEntries = m_connections.entriesSize(); // This loop can tolerate signal handles being disconnected inside a slot, @@ -297,17 +193,29 @@ class Signal if (index) { const auto con = m_connections.get(*index); - if (!con->blocked) - con->slot(p...); + if (!con->blocked) { + if (con->slotDeferred) { + if (auto sharedThis = shared_from_this(); sharedThis) { + ConnectionHandle handle(sharedThis, *index); + con->slotDeferred(handle, p...); + } + } else if (con->slot) { + con->slot(p...); + } + } } } } private: + friend class Signal; struct Connection { std::function slot; + std::function slotDeferred; + std::weak_ptr m_connectionEvaluator; bool blocked{ false }; }; + mutable Private::GenerationalIndexArray m_connections; }; @@ -352,6 +260,33 @@ class Signal return ConnectionHandle{ m_impl, m_impl->connect(slot) }; } + /** + * @brief Establishes a deferred connection between the provided evaluator and slot. + * + * @warning Deferred connections are experimental and may be removed or changed in the future. + * + * This function allows connecting an evaluator and a slot such that the slot's execution + * is deferred until the conditions evaluated by the `evaluator` are met. + * + * First argument to the function is reference to a shared pointer to the ConnectionEvaluator responsible for determining + * when the slot should be executed. + * + * @return An instance of ConnectionHandle, that can be used to disconnect + * or temporarily block the connection. + * + * @note + * The Signal class itself is not thread-safe. While the ConnectionEvaluator is inherently + * thread-safe, ensure that any concurrent access to this Signal is protected externally to maintain thread safety. + */ + ConnectionHandle connectDeferred(const std::shared_ptr &evaluator, std::function const &slot) + { + ensureImpl(); + + ConnectionHandle handle(m_impl, {}); + handle.setId(m_impl->connectDeferred(evaluator, slot)); + return handle; + } + /** * A template overload of Signal::connect that makes it easier to connect arbitrary functions to this * Signal. @@ -404,8 +339,8 @@ class Signal */ void disconnect(const ConnectionHandle &handle) { - if (m_impl && handle.belongsTo(*this)) { - m_impl->disconnect(handle.m_id); + if (m_impl && handle.belongsTo(*this) && handle.m_id.has_value()) { + m_impl->disconnect(handle); // TODO check if Impl is now empty and reset } else { throw std::out_of_range("Provided ConnectionHandle does not match any connection\nLikely the connection was deleted before!"); @@ -449,8 +384,8 @@ class Signal */ bool blockConnection(const ConnectionHandle &handle, bool blocked) { - if (m_impl && handle.belongsTo(*this)) { - return m_impl->blockConnection(handle.m_id, blocked); + if (m_impl && handle.belongsTo(*this) && handle.m_id.has_value()) { + return m_impl->blockConnection(*handle.m_id, blocked); } else { throw std::out_of_range("Provided ConnectionHandle does not match any connection\nLikely the connection was deleted before!"); } @@ -472,7 +407,11 @@ class Signal throw std::out_of_range("Provided ConnectionHandle does not match any connection\nLikely the connection was deleted before!"); } - return m_impl->isConnectionBlocked(handle.m_id); + if (handle.m_id.has_value()) { + return m_impl->isConnectionBlocked(*handle.m_id); + } else { + return false; + } } /** diff --git a/tests/signal/tst_signal.cpp b/tests/signal/tst_signal.cpp index 683b6c8..67cf4e9 100644 --- a/tests/signal/tst_signal.cpp +++ b/tests/signal/tst_signal.cpp @@ -11,9 +11,11 @@ #include "kdbindings/utils.h" #include +#include #include #include +#include #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN #include @@ -91,6 +93,170 @@ TEST_CASE("Signal connections") REQUIRE(lambdaCalled == true); } + SUBCASE("Disconnect Deferred Connection") + { + Signal signal1; + Signal signal2; + int val = 4; + auto evaluator = std::make_shared(); + + auto connection1 = signal1.connectDeferred(evaluator, [&val](int value) { + val += value; + }); + + auto connection2 = signal2.connectDeferred(evaluator, [&val](int value1, int value2) { + val += value1; + val += value2; + }); + + REQUIRE(connection1.isActive()); + + signal1.emit(4); + REQUIRE(val == 4); // val not changing immediately after emit + + signal2.emit(3, 2); + REQUIRE(val == 4); // val not changing immediately after emit + + connection1.disconnect(); + REQUIRE(!connection1.isActive()); + + REQUIRE(connection2.isActive()); + + evaluator->evaluateDeferredConnections(); // It doesn't evaluate any slots of signal1 as it ConnectionHandle gets disconnected before the evaluation of the deferred connections. + REQUIRE(val == 9); + } + + SUBCASE("Multiple Signals with Evaluator") + { + Signal signal1; + Signal signal2; + int val = 4; + auto evaluator = std::make_shared(); + + std::thread thread1([&] { + signal1.connectDeferred(evaluator, [&val](int value) { + val += value; + }); + }); + + std::thread thread2([&] { + signal2.connectDeferred(evaluator, [&val](int value) { + val += value; + }); + }); + + thread1.join(); + thread2.join(); + + signal1.emit(2); + signal2.emit(3); + REQUIRE(val == 4); // val not changing immediately after emit + + evaluator->evaluateDeferredConnections(); + + REQUIRE(val == 9); + } + + SUBCASE("Emit Multiple Signals with Evaluator") + { + Signal signal1; + Signal signal2; + int val1 = 4; + int val2 = 4; + auto evaluator = std::make_shared(); + + signal1.connectDeferred(evaluator, [&val1](int value) { + val1 += value; + }); + + signal2.connectDeferred(evaluator, [&val2](int value) { + val2 += value; + }); + + std::thread thread1([&] { + signal1.emit(2); + }); + + std::thread thread2([&] { + signal2.emit(3); + }); + + thread1.join(); + thread2.join(); + + REQUIRE(val1 == 4); + REQUIRE(val2 == 4); + + evaluator->evaluateDeferredConnections(); + + REQUIRE(val1 == 6); + REQUIRE(val2 == 7); + } + + SUBCASE("Deferred Connect, Emit, Disconnect, and Evaluate") + { + Signal signal; + int val = 4; + auto evaluator = std::make_shared(); + + auto connection = signal.connectDeferred(evaluator, [&val](int value) { + val += value; + }); + + REQUIRE(connection.isActive()); + + signal.emit(2); + REQUIRE(val == 4); + + connection.disconnect(); + evaluator->evaluateDeferredConnections(); // It doesn't evaluate the slot as the signal gets disconnected before it's evaluation of the deferred connections. + + REQUIRE(val == 4); + } + + SUBCASE("Double Evaluate Deferred Connections") + { + Signal signal; + int val = 4; + auto evaluator = std::make_shared(); + + signal.connectDeferred(evaluator, [&val](int value) { + val += value; + }); + + signal.emit(2); + REQUIRE(val == 4); + + evaluator->evaluateDeferredConnections(); + evaluator->evaluateDeferredConnections(); + + REQUIRE(val == 6); + } + + SUBCASE("Disconnect deferred connection from deleted signal") + { + auto signal = new Signal<>(); + auto anotherSignal = Signal<>(); + auto evaluator = std::make_shared(); + bool called = false; + bool anotherCalled = false; + + auto handle = signal->connectDeferred(evaluator, [&called]() { called = true; }); + anotherSignal.connectDeferred(evaluator, [&anotherCalled]() { anotherCalled = true; }); + + signal->emit(); + anotherSignal.emit(); + delete signal; + + REQUIRE(!called); + REQUIRE(!anotherCalled); + evaluator->evaluateDeferredConnections(); + REQUIRE(!called); + // Make sure the other signal still works, even after deconstructing another + // signal that was connected to the same evaluator. + REQUIRE(anotherCalled); + } + SUBCASE("A signal with arguments can be connected to a lambda and invoked with l-value args") { Signal signal; From 691c74ba4dd0b7509b7e8798be578ed1f3f9c98d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mi=C5=82osz=20Kosobucki?= Date: Mon, 8 Jan 2024 13:52:51 +0100 Subject: [PATCH 22/31] Avoid error in presence of Windows min/max macros In theory we could relegate the responsibility of defining NOMINMAX to the users of KDBindings but as it's such a tiny change I rather carry it here and avoid the problem altogheter. --- src/kdbindings/genindex_array.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/kdbindings/genindex_array.h b/src/kdbindings/genindex_array.h index 4da17d8..27a54dc 100644 --- a/src/kdbindings/genindex_array.h +++ b/src/kdbindings/genindex_array.h @@ -66,7 +66,8 @@ class GenerationalIndexAllocator return { index, m_entries[index].generation }; } else { // check that we are still within the bounds of uint32_t - if (m_entries.size() + 1 >= std::numeric_limits::max()) { + // (parentheses added to avoid Windows min/max macros) + if (m_entries.size() + 1 >= (std::numeric_limits::max)()) { throw std::length_error(std::string("Maximum number of values inside GenerationalIndexArray reached: ") + std::to_string(m_entries.size())); } From 1304f46f6a7f40cf4e36ba771394fc1174f2ed17 Mon Sep 17 00:00:00 2001 From: Leon Matthes Date: Wed, 10 Jan 2024 16:30:06 +0100 Subject: [PATCH 23/31] Fix CI: Link to Pthread library explicitly --- tests/signal/CMakeLists.txt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/signal/CMakeLists.txt b/tests/signal/CMakeLists.txt index 3c4061d..f33d741 100644 --- a/tests/signal/CMakeLists.txt +++ b/tests/signal/CMakeLists.txt @@ -13,6 +13,12 @@ project(test-signal VERSION 0.1 LANGUAGES CXX) add_executable(${PROJECT_NAME} tst_signal.cpp ) -target_link_libraries(${PROJECT_NAME} KDAB::KDBindings) +# For some reason, CMake with gcc doesn't automatically include the pthread library +# when using std::thread. This is a workaround for that. +# IMHO, this is ridiculous, std::thread is part of the standard library, it should just work +# when I use C++, but it is what it is. +# See: https://cmake.cmake.narkive.com/wWDhK9RQ/undefined-reference-to-pthread-create +find_package (Threads) +target_link_libraries(${PROJECT_NAME} KDAB::KDBindings ${CMAKE_THREAD_LIBS_INIT}) add_test(${PROJECT_NAME} ${PROJECT_NAME}) From 62de0121860f6b37e023d15305b8c26a2afb5e9e Mon Sep 17 00:00:00 2001 From: Leon Matthes Date: Wed, 10 Jan 2024 10:36:08 +0100 Subject: [PATCH 24/31] Fix CI staticcheck warnings - 2 instances of use-after-move - Missing #pragma once - Also move ScopedConnection into connection_handle.h --- src/kdbindings/connection_handle.h | 97 ++++++++++++++++++++++++++++++ src/kdbindings/signal.h | 95 ----------------------------- tests/signal/tst_signal.cpp | 16 ++++- 3 files changed, 111 insertions(+), 97 deletions(-) diff --git a/src/kdbindings/connection_handle.h b/src/kdbindings/connection_handle.h index 247c9d5..a0a1811 100644 --- a/src/kdbindings/connection_handle.h +++ b/src/kdbindings/connection_handle.h @@ -9,6 +9,8 @@ Contact KDAB at for commercial licensing options. */ +#pragma once + #include #include #include @@ -206,4 +208,99 @@ class ConnectionHandle } }; +/** + * @brief A ScopedConnection is a RAII-style way to make sure a Connection is disconnected. + * + * When the ScopedConnections scope ends, the connection this ScopedConnection guards will be disconnected. + * + * Example: + * - @ref 08-managing-connections/main.cpp + */ +class ScopedConnection +{ +public: + /** + * @brief A ScopedConnection can be default constructed + * + * A default constructed ScopedConnection has no connection to guard. + * Therefore it does nothing when it is destructed, unless a ConnectionHandle is assigned to it. + */ + ScopedConnection() = default; + + /** A ScopedConnection can be move constructed */ + ScopedConnection(ScopedConnection &&) = default; + + /** A ScopedConnection cannot be copied */ + ScopedConnection(const ScopedConnection &) = delete; + /** A ScopedConnection cannot be copied */ + ScopedConnection &operator=(const ScopedConnection &) = delete; + + /** A ScopedConnection can be move assigned */ + ScopedConnection &operator=(ScopedConnection &&other) + { + m_connection.disconnect(); + m_connection = std::move(other.m_connection); + return *this; + } + + /** + * A ScopedConnection can be constructed from a ConnectionHandle + */ + ScopedConnection(ConnectionHandle &&h) + : m_connection(std::move(h)) + { + } + + /** + * A ScopedConnection can be assigned from a ConnectionHandle + */ + ScopedConnection &operator=(ConnectionHandle &&h) + { + return *this = ScopedConnection(std::move(h)); + } + + /** + * @return the handle to the connection this instance is managing + */ + ConnectionHandle &handle() + { + return m_connection; + } + + /** + * @overload + */ + const ConnectionHandle &handle() const + { + return m_connection; + } + + /** + * Convenience access to the underlying ConnectionHandle using the `->` operator. + */ + ConnectionHandle *operator->() + { + return &m_connection; + } + + /** + * @overload + */ + const ConnectionHandle *operator->() const + { + return &m_connection; + } + + /** + * When a ConnectionHandle is destructed it disconnects the connection it guards. + */ + ~ScopedConnection() + { + m_connection.disconnect(); + } + +private: + ConnectionHandle m_connection; +}; + } // namespace KDBindings diff --git a/src/kdbindings/signal.h b/src/kdbindings/signal.h index 44e0121..2350c31 100644 --- a/src/kdbindings/signal.h +++ b/src/kdbindings/signal.h @@ -460,101 +460,6 @@ class Signal mutable std::shared_ptr m_impl; }; -/** - * @brief A ScopedConnection is a RAII-style way to make sure a Connection is disconnected. - * - * When the ScopedConnections scope ends, the connection this ScopedConnection guards will be disconnected. - * - * Example: - * - @ref 08-managing-connections/main.cpp - */ -class ScopedConnection -{ -public: - /** - * @brief A ScopedConnection can be default constructed - * - * A default constructed ScopedConnection has no connection to guard. - * Therefore it does nothing when it is destructed, unless a ConnectionHandle is assigned to it. - */ - ScopedConnection() = default; - - /** A ScopedConnection can be move constructed */ - ScopedConnection(ScopedConnection &&) = default; - - /** A ScopedConnection cannot be copied */ - ScopedConnection(const ScopedConnection &) = delete; - /** A ScopedConnection cannot be copied */ - ScopedConnection &operator=(const ScopedConnection &) = delete; - - /** A ScopedConnection can be move assigned */ - ScopedConnection &operator=(ScopedConnection &&other) - { - m_connection.disconnect(); - m_connection = std::move(other.m_connection); - return *this; - } - - /** - * A ScopedConnection can be constructed from a ConnectionHandle - */ - ScopedConnection(ConnectionHandle &&h) - : m_connection(std::move(h)) - { - } - - /** - * A ScopedConnection can be assigned from a ConnectionHandle - */ - ScopedConnection &operator=(ConnectionHandle &&h) - { - return *this = ScopedConnection(std::move(h)); - } - - /** - * @return the handle to the connection this instance is managing - */ - ConnectionHandle &handle() - { - return m_connection; - } - - /** - * @overload - */ - const ConnectionHandle &handle() const - { - return m_connection; - } - - /** - * Convenience access to the underlying ConnectionHandle using the `->` operator. - */ - ConnectionHandle *operator->() - { - return &m_connection; - } - - /** - * @overload - */ - const ConnectionHandle *operator->() const - { - return &m_connection; - } - - /** - * When a ConnectionHandle is destructed it disconnects the connection it guards. - */ - ~ScopedConnection() - { - m_connection.disconnect(); - } - -private: - ConnectionHandle m_connection; -}; - /** * @brief A ConnectionBlocker is a convenient RAII-style mechanism for temporarily blocking a connection. * diff --git a/tests/signal/tst_signal.cpp b/tests/signal/tst_signal.cpp index 67cf4e9..e05c6d6 100644 --- a/tests/signal/tst_signal.cpp +++ b/tests/signal/tst_signal.cpp @@ -707,7 +707,14 @@ TEST_CASE("ScopedConnection") // This should drop the old connection of guard1 guard1 = std::move(guard2); - CHECK(!guard2->isActive()); + // Ideally we'd like to assert here that: + // CHECK(!guard2->isActive()); + // However, this is not possible, as a moved-from ScopedConnection is + // undefined (as is any C++ object for that matter). + // But because we assert that `guard1` is still active after the scope + // ends and that numCalled is only 1 after the emit, we can be sure that + // `guard2` was moved from and didn't disconnect. + CHECK(guard1->isActive()); signal.emit(); @@ -728,7 +735,12 @@ TEST_CASE("ScopedConnection") ScopedConnection guard = signal.connect([&called]() { called = true; }); REQUIRE(guard->isActive()); into = std::move(guard); - REQUIRE_FALSE(guard->isActive()); + // Ideally we'd like to assert here that: + // REQUIRE_FALSE(guard->isActive()); + // However, this is not possible, as a moved-from ScopedConnection is + // undefined (as is any C++ object for that matter). + // But because we assert that `into` is still active after the scope + // ends, we can be sure that `guard` was moved from and didn't disconnect. } REQUIRE(into->isActive()); From b6f1c1b73b3bac66ce3c5c097185490c8bd35e42 Mon Sep 17 00:00:00 2001 From: Leon Matthes Date: Fri, 12 Jan 2024 17:56:09 +0100 Subject: [PATCH 25/31] Standardize project to KDAB copyright policy Follow-up for the new files added in main since 1.0. --- examples/08-managing-connections/CMakeLists.txt | 2 +- examples/08-managing-connections/main.cpp | 4 ++-- src/kdbindings/connection_handle.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/08-managing-connections/CMakeLists.txt b/examples/08-managing-connections/CMakeLists.txt index 0bc9b3c..b3fdb89 100644 --- a/examples/08-managing-connections/CMakeLists.txt +++ b/examples/08-managing-connections/CMakeLists.txt @@ -1,6 +1,6 @@ # This file is part of KDBindings. # -# SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company +# SPDX-FileCopyrightText: 2021 Klarälvdalens Datakonsult AB, a KDAB Group company # Author: Leon Matthes # # SPDX-License-Identifier: MIT diff --git a/examples/08-managing-connections/main.cpp b/examples/08-managing-connections/main.cpp index 8048ddb..330e057 100644 --- a/examples/08-managing-connections/main.cpp +++ b/examples/08-managing-connections/main.cpp @@ -1,7 +1,7 @@ /* This file is part of KDBindings. - SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company + SPDX-FileCopyrightText: 2021 Klarälvdalens Datakonsult AB, a KDAB Group company Author: Leon Matthes SPDX-License-Identifier: MIT @@ -39,7 +39,7 @@ int main() signal.emit(2); - ConnectionHandle handle = signal.connect(displayLabelled, "Connection is not blocked"); + ConnectionHandle handle = signal.connect(displayLabelled, "Connection is not blocked"); signal.emit(3); { diff --git a/src/kdbindings/connection_handle.h b/src/kdbindings/connection_handle.h index a0a1811..81eb447 100644 --- a/src/kdbindings/connection_handle.h +++ b/src/kdbindings/connection_handle.h @@ -1,7 +1,7 @@ /* This file is part of KDBindings. - SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company + SPDX-FileCopyrightText: 2021 Klarälvdalens Datakonsult AB, a KDAB Group company Author: Sean Harmer SPDX-License-Identifier: MIT From 219eba4d0bf3cac36239671951dc00d815bd60a8 Mon Sep 17 00:00:00 2001 From: Leon Matthes Date: Wed, 17 Jan 2024 09:37:08 +0100 Subject: [PATCH 26/31] Fix Threads linking issue under Windows Only gcc needs the Threads library linked and it can't be correctly linked under windows, so add a check that we're compiling with gcc. --- tests/signal/CMakeLists.txt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/signal/CMakeLists.txt b/tests/signal/CMakeLists.txt index 26d0296..39141a9 100644 --- a/tests/signal/CMakeLists.txt +++ b/tests/signal/CMakeLists.txt @@ -13,12 +13,17 @@ project(test-signal VERSION 0.1 LANGUAGES CXX) add_executable(${PROJECT_NAME} tst_signal.cpp ) + +target_link_libraries(${PROJECT_NAME} KDAB::KDBindings) + # For some reason, CMake with gcc doesn't automatically include the pthread library # when using std::thread. This is a workaround for that. # IMHO, this is ridiculous, std::thread is part of the standard library, it should just work # when I use C++, but it is what it is. # See: https://cmake.cmake.narkive.com/wWDhK9RQ/undefined-reference-to-pthread-create -find_package (Threads) -target_link_libraries(${PROJECT_NAME} KDAB::KDBindings ${CMAKE_THREAD_LIBS_INIT}) +if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + find_package (Threads) + target_link_libraries(${PROJECT_NAME} ${CMAKE_THREAD_LIBS_INIT}) +endif() add_test(${PROJECT_NAME} ${PROJECT_NAME}) From 12d987be008a83a41f38b0912e9c343b45a14ad3 Mon Sep 17 00:00:00 2001 From: Leon Matthes Date: Wed, 17 Jan 2024 14:50:41 +0100 Subject: [PATCH 27/31] CI: Use presets for testing Only test Release mode, which reduces number of runners needed. --- .github/workflows/build.yml | 17 ++++------------- CMakePresets.json | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 13 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f8646fc..7496bb1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,9 +19,6 @@ jobs: #- windows-2019 - macos-12 #- macos-11 - build_type: - - Debug - - Release steps: - name: Checkout sources @@ -37,22 +34,16 @@ jobs: uses: ilammy/msvc-dev-cmd@v1 - name: Configure project - run: > - cmake -S . -B ./build -G Ninja - -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} - -DKDBindings_TESTS=${{ matrix.build_type == 'Debug' }} - -DKDBindings_EXAMPLES=${{ matrix.build_type == 'Debug' }} - -DKDBindings_DOCS=${{ matrix.build_type == 'Debug' && runner.os == 'Linux' }} + run: cmake --preset=ci - name: Build Project - run: cmake --build ./build + run: cmake --build --preset=ci - name: Run tests - if: ${{ matrix.build_type == 'Debug' }} - run: ctest --test-dir ./build -C ${{ matrix.build_type }} --output-on-failure + run: ctest --preset=ci - name: Read tests log when it fails uses: andstor/file-reader-action@v1 - if: ${{ failure() && matrix.build_type == 'Debug' }} + if: ${{ failure() }} with: path: "./build/Testing/Temporary/LastTest.log" diff --git a/CMakePresets.json b/CMakePresets.json index 2081aeb..a4759ac 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -12,6 +12,43 @@ "KDBindings_TESTS" : "ON", "KDBindings_EXAMPLES" : "ON" } + }, + { + "name": "ci", + "displayName": "ci", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build-ci", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release", + "CMAKE_EXPORT_COMPILE_COMMANDS" : "ON", + "KDBindings_TESTS" : "ON", + "KDBindings_EXAMPLES" : "ON", + "KDBindings_DOCS" : "ON" + } + } + ], + "buildPresets": [ + { + "name": "ci", + "configurePreset": "ci" + }, + { + "name": "dev", + "configurePreset": "dev" + } + ], + "testPresets": [ + { + "name": "ci", + "configurePreset": "ci", + "output": {"outputOnFailure": true}, + "execution": {"noTestsAction": "error", "stopOnFailure": true} + }, + { + "name": "dev", + "configurePreset": "dev", + "output": {"outputOnFailure": true}, + "execution": {"noTestsAction": "error", "stopOnFailure": false} } ] } From bb66ec5a9851e47925eb2c0539507f1867e020b7 Mon Sep 17 00:00:00 2001 From: Daniel Nicoletti Date: Wed, 17 Jan 2024 10:44:48 -0300 Subject: [PATCH 28/31] CI: Add static checks --- .github/workflows/static_checks.yml | 57 +++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 .github/workflows/static_checks.yml diff --git a/.github/workflows/static_checks.yml b/.github/workflows/static_checks.yml new file mode 100644 index 0000000..633295b --- /dev/null +++ b/.github/workflows/static_checks.yml @@ -0,0 +1,57 @@ +# SPDX-FileCopyrightText: 2024 Klarälvdalens Datakonsult AB, a KDAB Group company +# +# SPDX-License-Identifier: MIT + +name: CI Static Checks + +on: + push: + branches: + - main + pull_request: + branches: + - main + +jobs: + build: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: + - ubuntu-latest + + config: + - name: clang-tidy + cmake_arg: '-DCMAKE_CXX_CLANG_TIDY=clang-tidy' + + - name: clazy + cmake_arg: '-DCMAKE_CXX_COMPILER=clazy' + apt_pgks: + - clazy + + steps: + - name: Install ninja-build tool + uses: turtlesec-no/get-ninja@main + + - name: Install dependencies on Ubuntu (${{ join(matrix.config.apt_pgks, ' ') }}) + if: ${{ runner.os == 'Linux' && matrix.config.apt_pgks }} + run: | + sudo apt update -qq + echo ${{ join(matrix.config.apt_pgks, ' ') }} | xargs sudo apt install -y + + - uses: actions/checkout@v4 + + - name: Fetch Git submodules + run: git submodule update --init --recursive + + - name: Configure project + run: > + cmake -S . -B ./build -G Ninja ${{ matrix.config.cmake_arg }} + --warn-uninitialized -Werror=dev + -DCMAKE_BUILD_TYPE=Debug + -DKDBindings_TESTS=True + + - name: Build Project + id: ctest + run: cmake --build ./build From 102336a2df55604d56243a752990978c2c71b2c9 Mon Sep 17 00:00:00 2001 From: Daniel Nicoletti Date: Wed, 17 Jan 2024 11:00:51 -0300 Subject: [PATCH 29/31] CI: Avoid duplicated CI jobs Specifying the push/pull_request branch avoids duplicated CI Jobs. --- .github/workflows/build.yml | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7496bb1..e587b25 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -4,7 +4,13 @@ name: CI -on: [push, pull_request] +on: + push: + branches: + - main + pull_request: + branches: + - main jobs: build: @@ -13,25 +19,20 @@ jobs: fail-fast: true matrix: os: - - ubuntu-22.04 - #- ubuntu-20.04 - - windows-2022 - #- windows-2019 - - macos-12 - #- macos-11 + - ubuntu-latest + - windows-latest + - macos-latest steps: - name: Checkout sources uses: actions/checkout@v4 - - name: Create build directory - run: mkdir build - - name: Install ninja-build tool uses: turtlesec-no/get-ninja@main - name: Make sure MSVC is found when Ninja generator is in use uses: ilammy/msvc-dev-cmd@v1 + if: ${{ runner.os == 'Windows' }} - name: Configure project run: cmake --preset=ci From 94bb1e8a09006e0c52e3b5ced02d10bc857abc18 Mon Sep 17 00:00:00 2001 From: Leon Matthes Date: Wed, 17 Jan 2024 17:02:54 +0100 Subject: [PATCH 30/31] Add CMake presets for static checks --- .github/workflows/static_checks.yml | 10 ++----- CMakePresets.json | 45 +++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/.github/workflows/static_checks.yml b/.github/workflows/static_checks.yml index 633295b..94e4f86 100644 --- a/.github/workflows/static_checks.yml +++ b/.github/workflows/static_checks.yml @@ -23,10 +23,8 @@ jobs: config: - name: clang-tidy - cmake_arg: '-DCMAKE_CXX_CLANG_TIDY=clang-tidy' - name: clazy - cmake_arg: '-DCMAKE_CXX_COMPILER=clazy' apt_pgks: - clazy @@ -46,12 +44,8 @@ jobs: run: git submodule update --init --recursive - name: Configure project - run: > - cmake -S . -B ./build -G Ninja ${{ matrix.config.cmake_arg }} - --warn-uninitialized -Werror=dev - -DCMAKE_BUILD_TYPE=Debug - -DKDBindings_TESTS=True + run: cmake --preset=${{ matrix.config.name }} - name: Build Project id: ctest - run: cmake --build ./build + run: cmake --build --preset=${{ matrix.config.name }} diff --git a/CMakePresets.json b/CMakePresets.json index a4759ac..e8cfa14 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -25,7 +25,44 @@ "KDBindings_EXAMPLES" : "ON", "KDBindings_DOCS" : "ON" } + }, + { + "name": "clazy", + "displayName": "clazy", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build-clazy", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug", + "CMAKE_CXX_COMPILER" : "clazy", + "KDBindings_TESTS" : "ON", + "KDBindings_EXAMPLES" : "ON" + }, + "warnings": { + "uninitialized": true + }, + "errors": { + "dev": true + } + }, + { + "name": "clang-tidy", + "displayName": "clang-tidy", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build-clang-tidy", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug", + "CMAKE_CXX_CLANG_TIDY" : "clang-tidy", + "KDBindings_TESTS" : "ON", + "KDBindings_EXAMPLES" : "ON" + }, + "warnings": { + "uninitialized": true + }, + "errors": { + "dev": true + } } + ], "buildPresets": [ { @@ -35,6 +72,14 @@ { "name": "dev", "configurePreset": "dev" + }, + { + "name": "clazy", + "configurePreset": "clazy" + }, + { + "name": "clang-tidy", + "configurePreset": "clang-tidy" } ], "testPresets": [ From 1a03c8182acaf96c02f680b971b2a6e969e68992 Mon Sep 17 00:00:00 2001 From: Daniel Nicoletti Date: Wed, 17 Jan 2024 13:14:02 -0300 Subject: [PATCH 31/31] Remove appveyor.yml --- appveyor.yml | 85 ---------------------------------------------------- 1 file changed, 85 deletions(-) delete mode 100644 appveyor.yml diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index 75d23e2..0000000 --- a/appveyor.yml +++ /dev/null @@ -1,85 +0,0 @@ -#---------------------------------# -# general configuration # -#---------------------------------# - -# version format -version: 1.0.{build}-{branch} - -# branches to build -branches: - except: - - gh-pages - -# Do not build on tags (GitHub and BitBucket) -skip_tags: false - -#---------------------------------# -# environment configuration # -#---------------------------------# - -# Build worker image -image: - - Ubuntu - - macos - - Visual Studio 2019 - -# scripts that are called at very beginning, before repo cloning -init: - - git config --global core.autocrlf input - -#---------------------------------# -# build configuration # -#---------------------------------# - -# build platform, i.e. x86, x64, Any CPU. This setting is optional. -platform: - - x64 - -# build Configuration, i.e. Debug, Release, etc. -configuration: - - Release - - Debug - -install: - - sh: if [ "`uname -s`" = "Darwin" ]; then brew install ninja; fi - -before_build: - - cmd: call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat" - -build_script: - - mkdir build - - cd build - - cmd: cmake -G Ninja -DCMAKE_BUILD_TYPE=%CONFIGURATION% -DKDBindings_TESTS=True -DKDBindings_EXAMPLES=True .. - - sh: cmake -G Ninja -DCMAKE_BUILD_TYPE=$CONFIGURATION -DKDBindings_TESTS=True -DKDBindings_EXAMPLES=True .. - - cmake --build . - - cmd: cmake --build . --target install - - sh: sudo cmake --build . --target install - - ctest --test-dir . - -# to disable automatic builds -#build: off - -#---------------------------------# -# tests configuration # -#---------------------------------# - -# to disable automatic tests -test: off - - -#---------------------------------# -# deployment configuration # -#---------------------------------# - -deploy: off - -#---------------------------------# -# notifications # -#---------------------------------# -notifications: - # Email - - provider: Email - to: - - allen.winter@kdab.com - on_build_success: false - on_build_failure: true