diff --git a/include/etl/callback_service.h b/include/etl/callback_service.h index 27876474..e0eb31be 100644 --- a/include/etl/callback_service.h +++ b/include/etl/callback_service.h @@ -61,6 +61,14 @@ namespace etl lookup.fill(&unhandled_callback); } + callback_service(const callback_service&) ETL_DELETE; + callback_service& operator=(const callback_service&) ETL_DELETE; + +#if ETL_USING_CPP11 + callback_service(callback_service&&) ETL_DELETE; + callback_service& operator=(callback_service&&) ETL_DELETE; +#endif + //************************************************************************* /// Registers a callback for the specified id. /// Compile time assert if the id is out of range. diff --git a/include/etl/delegate_service.h b/include/etl/delegate_service.h index 6ca7b40c..13070243 100644 --- a/include/etl/delegate_service.h +++ b/include/etl/delegate_service.h @@ -117,6 +117,14 @@ namespace etl lookup.fill(default_delegate); } + delegate_service(const delegate_service&) ETL_DELETE; + delegate_service& operator=(const delegate_service&) ETL_DELETE; + +#if ETL_USING_CPP11 + delegate_service(delegate_service&&) ETL_DELETE; + delegate_service& operator=(delegate_service&&) ETL_DELETE; +#endif + //************************************************************************* /// Registers a delegate for the specified id. /// Compile time assert if the id is out of range. diff --git a/include/etl/signal.h b/include/etl/signal.h index 3392cff6..b78e7e58 100644 --- a/include/etl/signal.h +++ b/include/etl/signal.h @@ -91,7 +91,8 @@ namespace etl /// ///\tparam TFunction: Callback signature. ///\tparam Size: Maximum number of slots that can be connected to the - /// signal. \tparam TSlot: Function-object type or container type that can + /// signal. + ///\tparam TSlot: Function-object type or container type that can /// be invoked. Default etl::delegate. //*************************************************************************** template > @@ -117,6 +118,66 @@ namespace etl static_assert(sizeof...(slots) <= Size, "Number of slots exceeds capacity"); } + //************************************************************************* + ///\brief Copy constructor. + /// + ///\param other: The signal to copy from. + //************************************************************************* + signal(const signal& other) ETL_NOEXCEPT + : slot_list{} + , slot_list_end{slot_list + other.size()} + { + etl::copy(other.begin(), other.end(), slot_list); + } + + //************************************************************************* + ///\brief Copy assignment operator. + /// + ///\param other: The signal to copy from. + ///\return A reference to this signal. + //************************************************************************* + signal& operator=(const signal& other) ETL_NOEXCEPT + { + if (this != &other) + { + etl::copy(other.begin(), other.end(), slot_list); + slot_list_end = slot_list + other.size(); + } + return *this; + } + + //************************************************************************* + ///\brief Move constructor. + /// The moved-from signal is left empty. + /// + ///\param other: The signal to move from. + //************************************************************************* + signal(signal&& other) ETL_NOEXCEPT + : slot_list{} + , slot_list_end{slot_list + other.size()} + { + etl::move(other.begin(), other.end(), slot_list); + other.slot_list_end = other.slot_list; + } + + //************************************************************************* + ///\brief Move assignment operator. + /// The moved-from signal is left empty. + /// + ///\param other: The signal to move from. + ///\return A reference to this signal. + //************************************************************************* + signal& operator=(signal&& other) ETL_NOEXCEPT + { + if (this != &other) + { + etl::move(other.begin(), other.end(), slot_list); + slot_list_end = slot_list + other.size(); + other.slot_list_end = other.slot_list; + } + return *this; + } + //************************************************************************* ///\brief Connects a slot to the signal. /// Ignores the slot if it has already been connected. diff --git a/test/test_signal.cpp b/test/test_signal.cpp index 69f2f884..78ecc3d4 100644 --- a/test/test_signal.cpp +++ b/test/test_signal.cpp @@ -637,4 +637,105 @@ namespace CHECK_EQUAL(expected_string, ss.str()); } #endif + + //*************************************************************************** + TEST(test_copy_constructor) + { + const auto free_slot = make_free_slot(); + const auto static_slot = make_static_slot(); + + const signal_type original{free_slot, static_slot}; + + // Copy construct + signal_type copy(original); + + // Both should invoke the same slots independently + std::stringstream ss_original; + original(ss_original); + CHECK_EQUAL(std::string("freestatic"), ss_original.str()); + + std::stringstream ss_copy; + copy(ss_copy); + CHECK_EQUAL(std::string("freestatic"), ss_copy.str()); + + // Modifying the copy should not affect the original + const auto lambda_slot = make_lambda_slot(); + copy.connect(lambda_slot); + + CHECK_EQUAL(2U, original.size()); + CHECK_EQUAL(3U, copy.size()); + } + + //*************************************************************************** + TEST(test_copy_assignment) + { + const auto free_slot = make_free_slot(); + const auto static_slot = make_static_slot(); + + const signal_type original{free_slot, static_slot}; + signal_type assigned{make_lambda_slot()}; + + // Copy assign + assigned = original; + + // Both should invoke the same slots independently + std::stringstream ss_original; + original(ss_original); + CHECK_EQUAL(std::string("freestatic"), ss_original.str()); + + std::stringstream ss_assigned; + assigned(ss_assigned); + CHECK_EQUAL(std::string("freestatic"), ss_assigned.str()); + + // Modifying the assigned signal should not affect the original + assigned.disconnect(free_slot); + + CHECK_EQUAL(2U, original.size()); + CHECK_EQUAL(1U, assigned.size()); + } + + //*************************************************************************** + TEST(test_move_constructor) + { + const auto free_slot = make_free_slot(); + const auto static_slot = make_static_slot(); + + signal_type original{free_slot, static_slot}; + + // Move construct + signal_type moved(etl::move(original)); + + // Moved-to signal should have the slots + std::stringstream ss_moved; + moved(ss_moved); + CHECK_EQUAL(std::string("freestatic"), ss_moved.str()); + CHECK_EQUAL(2U, moved.size()); + + // Moved-from signal should be empty + CHECK(original.empty()); + CHECK_EQUAL(0U, original.size()); + } + + //*************************************************************************** + TEST(test_move_assignment) + { + const auto free_slot = make_free_slot(); + const auto static_slot = make_static_slot(); + + signal_type original{free_slot, static_slot}; + signal_type assigned{make_lambda_slot()}; + + // Move assign + assigned = etl::move(original); + + // Moved-to signal should have the original's slots + std::stringstream ss_assigned; + assigned(ss_assigned); + CHECK_EQUAL(std::string("freestatic"), ss_assigned.str()); + CHECK_EQUAL(2U, assigned.size()); + + // Moved-from signal should be empty + CHECK(original.empty()); + CHECK_EQUAL(0U, original.size()); + } } // namespace