Rebased on development

This commit is contained in:
John Wellbelove 2025-09-20 11:25:09 +01:00
parent 1da478fa60
commit 62b5a4a6ae
8 changed files with 1076 additions and 0 deletions

1
.gitignore vendored
View File

@ -410,3 +410,4 @@ examples/UniquePtrWithPool/CMakeCache.txt
examples/UniquePtrWithPool/UniquePtrWithPool
test/vs2022/Debug Clang C++20 - Optimised -O2
include/etl/header_file_list.txt
temp

View File

@ -108,4 +108,5 @@ SOFTWARE.
#define ETL_SPAN_FILE_ID "75"
#define ETL_ALGORITHM_FILE_ID "76"
#define ETL_NOT_NULL_FILE_ID "77"
#define ETL_SIGNAL_FILE_ID "78"
#endif

380
include/etl/signal.h Normal file
View File

@ -0,0 +1,380 @@
///\file
/******************************************************************************
The MIT License(MIT)
Embedded Template Library.
https://github.com/ETLCPP/etl
https://www.etlcpp.com
Copyright(c) 2025 John Wellbelove, Mark Kitson
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files(the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions :
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#ifndef ETL_SIGNAL_INCLUDED
#define ETL_SIGNAL_INCLUDED
#include <cstddef>
#include "platform.h"
#if ETL_NOT_USING_CPP11
#error NOT SUPPORTED FOR C++03 OR BELOW
#endif
#if ETL_USING_CPP11
#include "exception.h"
#include "error_handler.h"
#include "delegate.h"
#include "algorithm.h"
#include "iterator.h"
#include "type_traits.h"
#include "initializer_list.h"
#include "span.h"
#include "file_error_numbers.h"
//*****************************************************************************
///\defgroup signal signal
/// Container that handles storing and calling callbacks.
///\ingroup containers
//*****************************************************************************
namespace etl
{
//***************************************************************************
///\ingroup signal
/// The base class for signal exceptions.
//***************************************************************************
class signal_exception : public exception
{
public:
signal_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
: exception{reason_, file_name_, line_number_}
{
}
};
//***************************************************************************
///\ingroup signal
/// Signal full exception.
//***************************************************************************
class signal_full : public signal_exception
{
public:
signal_full(string_type file_name_, numeric_type line_number_)
: signal_exception{ETL_ERROR_TEXT("signal:full", ETL_SIGNAL_FILE_ID"A"), file_name_, line_number_}
{
}
};
//***************************************************************************
///\ingroup signal
///
///\brief A lightweight signal class designed for efficient memory usage and
/// ability to store in ROM.
///
///\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 be invoked. Default etl::delegate<TFunction>.
//***************************************************************************
template <typename TFunction, size_t Size, typename TSlot = etl::delegate<TFunction>>
class signal
{
public:
using slot_type = TSlot;
using size_type = size_t;
using span_type = etl::span<const slot_type>;
//*************************************************************************
///\brief Construct the signal from a variadic list of slots.
///
///\param slots: Variadic list of slots.
//*************************************************************************
template <typename... TSlots>
ETL_CONSTEXPR14 explicit signal(TSlots&&... slots) ETL_NOEXCEPT
: slot_list{etl::forward<TSlots>(slots)...}
, slot_list_end{slot_list + sizeof...(slots)}
{
static_assert((etl::are_all_same<slot_type, etl::decay_t<TSlots>...>::value), "All slots must be slot_type");
static_assert(sizeof...(slots) <= Size, "Number of slots exceeds capacity");
}
//*************************************************************************
///\brief Connects a slot to the signal.
/// Ignores the slot if it has already been connected.
///
///\param slot: The slot to connect.
///\return <b>false</b> if not all slots could be connected.
//*************************************************************************
bool connect(const slot_type& slot) ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS)
{
if (!connected(slot))
{
ETL_ASSERT_OR_RETURN_VALUE(!full(), ETL_ERROR(signal_full), false);
append_slot(slot);
}
return true;
}
#if ETL_HAS_INITIALIZER_LIST && ETL_USING_CPP17
//*************************************************************************
///\brief Connects slots to the signal.
/// Ignores the slots if it has already been connected.
///
///\param slots: std::initializer_list of slots to connect.
///\return <b>false</b> if not all slots could be connected.
//*************************************************************************
bool connect(std::initializer_list<const slot_type> slots) ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS)
{
for (const slot_type& slot : slots)
{
if (!connected(slot))
{
ETL_ASSERT_OR_RETURN_VALUE(!full(), ETL_ERROR(signal_full), false);
append_slot(slot);
}
}
return true;
}
#endif
//*************************************************************************
///\brief Connects slots to the signal.
/// Ignores the slots if it has already been connected.
///
///\param slots: etl::span of slots to connect.
///\return <b>false</b> if not all slots could be connected.
//*************************************************************************
bool connect(const span_type slots) ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS)
{
for (const slot_type& slot : slots)
{
if (!connected(slot))
{
ETL_ASSERT_OR_RETURN_VALUE(!full(), ETL_ERROR(signal_full), false);
append_slot(slot);
}
}
return true;
}
//*************************************************************************
///\brief Disconnects a slot from the signal.
///
///\param slot: To disconnect.
//*************************************************************************
void disconnect(const slot_type& slot) ETL_NOEXCEPT
{
const auto end_itr = end();
const auto itr = etl::find(begin(), end_itr, slot);
if (itr != end_itr)
{
// Shifts all elements after 'itr' one position to the left.
etl::copy(etl::next(itr), end_itr, itr);
slot_list_end = etl::prev(slot_list_end);
}
}
#if ETL_HAS_INITIALIZER_LIST && ETL_USING_CPP17
//*************************************************************************
///\brief Disconnects multiple slots from the signal.
///
///\param slot: std::intializer_list of slots to disconnect.
//*************************************************************************
void disconnect(std::initializer_list<const slot_type> slots) ETL_NOEXCEPT
{
for (const slot_type& slot : slots)
{
disconnect(slot);
}
}
#endif
//*************************************************************************
///\brief Disconnects multiple slots from the signal.
///
///\param slot: etl::span of slots to disconnect.
//*************************************************************************
void disconnect(const span_type slots) ETL_NOEXCEPT
{
for (const slot_type& slot : slots)
{
disconnect(slot);
}
}
//*************************************************************************
///\brief Disconnects all slots from the signal.
//*************************************************************************
void disconnect_all() ETL_NOEXCEPT
{
slot_list_end = begin();
}
//*************************************************************************
///\brief Checks if a slot is connected to the signal.
///
///\param slot: To check.
///\return <b>true</b> if the slot is connected.
//*************************************************************************
ETL_CONSTEXPR14 bool connected(const slot_type& slot) const ETL_NOEXCEPT
{
return etl::any_of(begin(), end(), [&slot](const slot_type& s) { return s == slot; });
}
//*************************************************************************
///\return <b>true</b> if the signal has no slots connected.
//*************************************************************************
ETL_CONSTEXPR14 bool empty() const ETL_NOEXCEPT
{
return begin() == end();
}
//*************************************************************************
///\return <b>true</b> if the signal has the maximum number of slots connected.
//*************************************************************************
ETL_CONSTEXPR14 bool full() const ETL_NOEXCEPT
{
return size() == max_size();
}
//*************************************************************************
///\return Total number of slots that can be connected.
//*************************************************************************
ETL_CONSTEXPR14 size_type max_size() const ETL_NOEXCEPT
{
return Size;
}
//*************************************************************************
///\return Total slots currently connected.
//*************************************************************************
ETL_CONSTEXPR14 size_type size() const ETL_NOEXCEPT
{
return etl::distance(begin(), end());
}
//*************************************************************************
///\return Total empty slots available.
//*************************************************************************
ETL_CONSTEXPR14 size_type available() const ETL_NOEXCEPT
{
return max_size() - size();
}
//*************************************************************************
///\brief Invokes all the slots connected to the signal.
/// Checks if the slot is valid to call.
///
///\param args: Arguments to pass to the slots.
//*************************************************************************
template <typename... TArgs>
void operator()(TArgs&&... args) const ETL_NOEXCEPT
{
for (const slot_type& slot : *this)
{
if (slot_is_valid(slot))
{
slot(etl::forward<TArgs>(args)...);
}
}
}
private:
using iterator = slot_type*;
using const_iterator = const slot_type*;
slot_type slot_list[Size];
iterator slot_list_end;
//*************************************************************************
/// Appends a slot to the slot list.
//*************************************************************************
void append_slot(const slot_type& slot) ETL_NOEXCEPT
{
(*slot_list_end) = slot;
slot_list_end = etl::next(slot_list_end);
}
//*************************************************************************
/// For a delegate slot type.
//*************************************************************************
template <typename TSlotType, typename... TArgs>
static
typename etl::enable_if_t<etl::is_delegate<TSlotType>::value, bool>
slot_is_valid(const TSlotType& s) ETL_NOEXCEPT
{
return s.is_valid();
}
//*************************************************************************
/// For a non-delegate slot type.
//*************************************************************************
template <typename TSlotType, typename... TArgs>
static
typename etl::enable_if_t<!etl::is_delegate<TSlotType>::value, bool>
slot_is_valid(const TSlotType&) ETL_NOEXCEPT
{
return true;
}
//*************************************************************************
///\return Iterator to the beginning of the connected slots.
//*************************************************************************
ETL_CONSTEXPR14 iterator begin() ETL_NOEXCEPT
{
return slot_list;
}
//*************************************************************************
///\return Const Iterator to the beginning of the connected slots.
//*************************************************************************
ETL_CONSTEXPR14 const_iterator begin() const ETL_NOEXCEPT
{
return slot_list;
}
//*************************************************************************
///\return Iterator to the end of the connected slots.
//*************************************************************************
ETL_CONSTEXPR14 iterator end() ETL_NOEXCEPT
{
return slot_list_end;
}
//*************************************************************************
///\return Const Iterator to the end of the connected slots.
//*************************************************************************
ETL_CONSTEXPR14 const_iterator end() const ETL_NOEXCEPT
{
return slot_list_end;
}
};
}
#endif
#endif

View File

@ -285,6 +285,7 @@ add_executable(etl_tests
test_scaled_rounding.cpp
test_set.cpp
test_shared_message.cpp
test_signal.cpp
test_singleton.cpp
test_singleton_base.cpp
test_smallest.cpp

View File

@ -290,6 +290,7 @@ target_sources(tests PRIVATE
scheduler.h.t.cpp
set.h.t.cpp
shared_message.h.t.cpp
signal.h.t.cpp
singleton.h.t.cpp
singleton_base.h.t.cpp
smallest.h.t.cpp

View File

@ -0,0 +1,29 @@
/******************************************************************************
The MIT License(MIT)
Embedded Template Library.
https://github.com/ETLCPP/etl
https://www.etlcpp.com
Copyright(c) 2025 John Wellbelove
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files(the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions :
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#include <etl/signal.h>

641
test/test_signal.cpp Normal file
View File

@ -0,0 +1,641 @@
/******************************************************************************
The MIT License(MIT)
Embedded Template Library.
https://github.com/ETLCPP/etl
https://www.etlcpp.com
Copyright(c) 2014 John Wellbelove
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files(the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions :
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#include "UnitTest++/CheckMacros.h"
#include "unit_test_framework.h"
#include <sstream>
#include <string>
#include "etl/signal.h"
namespace
{
using callback_type = void(std::ostream&);
using signal_type = etl::signal<callback_type, 5U>;
using slot_type = signal_type::slot_type;
using span_type = signal_type::span_type;
//*************************************************************************
///\brief Generic output free function
///
///\param out: output stream
///\param str: input string
//*************************************************************************
void output(std::ostream& out, const std::string& str)
{
out << str;
}
//*************************************************************************
///\brief Free function that outputs "free"
///
///\param out: output
//*************************************************************************
void output_free(std::ostream& out)
{
output(out, "free");
}
//*************************************************************************
///\brief Free function that outputs "free"
///
///\param out: output
//*************************************************************************
void output_extra(std::ostream& out)
{
output(out, "extra");
}
//*************************************************************************
///\brief Lambda that outputs "lambda"
///
///\param out: output
//*************************************************************************
auto output_lambda = [](std::ostream& out) { output(out, "lambda"); };
class example_class
{
public:
//*************************************************************************
///\brief Method that outputs "static"
///
///\param out: output
//*************************************************************************
static void static_method(std::ostream& out)
{
output(out, "static");
}
//*************************************************************************
///\brief Method that outputs "method"
///
///\param out: output
//*************************************************************************
void method(std::ostream& out)
{
output(out, "method");
}
//*************************************************************************
///\brief Functor method that outputs "functor"
///
///\param out: output
//*************************************************************************
void operator()(std::ostream& out)
{
output(out, "functor");
}
};
example_class example;
//*************************************************************************
///\brief Makes an empty slot
///
///\return constexpr slot_type
//*************************************************************************
ETL_CONSTEXPR14 slot_type make_empty_slot()
{
return slot_type();
}
//*************************************************************************
///\brief Makes the free function slot
///
///\return constexpr slot_type
//*************************************************************************
ETL_CONSTEXPR14 slot_type make_free_slot()
{
return slot_type::create<output_free>();
}
//*************************************************************************
///\brief Makes the lambda slot
///
///\return constexpr slot_type
//*************************************************************************
ETL_CONSTEXPR14 slot_type make_lambda_slot()
{
return slot_type{output_lambda};
}
//*************************************************************************
///\brief Makes the static method slot
///
///\return constexpr slot_type
//*************************************************************************
ETL_CONSTEXPR14 slot_type make_static_slot()
{
return slot_type::create<&example_class::static_method>();
}
//*************************************************************************
///\brief Makes the class method slot
///
///\return constexpr slot_type
//*************************************************************************
ETL_CONSTEXPR14 slot_type make_instance_slot()
{
return slot_type::create<example_class, example, &example_class::method>();
}
//*************************************************************************
///\brief Makes the functor slot
///
///\return constexpr slot_type
//*************************************************************************
ETL_CONSTEXPR14 slot_type make_functor_slot()
{
return slot_type::create<example_class, example>();
}
//*************************************************************************
///\brief Makes the free function slot
///
///\return constexpr slot_type
//*************************************************************************
ETL_CONSTEXPR14 slot_type make_extra_slot()
{
return slot_type::create<output_extra>();
}
//*************************************************************************
///\brief Makes the incorrect slot type
/// Uncomment for test_construct_with_incorrect_slot_type
///\return An incorrect slot
//*************************************************************************
//ETL_CONSTEXPR14 etl::delegate<int(std::ostream&)> make_incorrect_slot()
//{
// return etl::delegate<int(std::ostream&)>();
//}
//***************************************************************************
SUITE(signal_test)
{
//***************************************************************************
TEST(test_default_construct)
{
const signal_type test_object;
CHECK_EQUAL(0U, test_object.size());
CHECK_EQUAL(5U, test_object.max_size());
CHECK_TRUE(test_object.empty());
CHECK_FALSE(test_object.full());
}
#if ETL_USING_CPP14
//***************************************************************************
TEST(test_constexpr_construct)
{
static constexpr signal_type signal
{
make_free_slot(),
make_lambda_slot(),
make_static_slot(),
make_instance_slot(),
make_functor_slot()
};
CHECK_EQUAL(5U, signal.size());
CHECK_EQUAL(0, signal.available());
CHECK_EQUAL(5U, signal.max_size());
CHECK_FALSE(signal.empty());
CHECK_TRUE(signal.full());
}
#endif
//***************************************************************************
TEST(test_construct_from_slot_list)
{
const auto free_slot = make_free_slot();
const auto lambda_slot = make_lambda_slot();
const auto static_slot = make_static_slot();
const auto instance_slot = make_instance_slot();
const auto functor_slot = make_functor_slot();
const signal_type signal{ free_slot, lambda_slot, static_slot, instance_slot, functor_slot };
CHECK_EQUAL(5, signal.size());
CHECK_EQUAL(0, signal.available());
CHECK_EQUAL(5, signal.max_size());
CHECK_FALSE(signal.empty());
CHECK_TRUE(signal.full());
}
//***************************************************************************
TEST(test_construct_from_too_many_slots)
{
// Uncomment to trigger static_assert "Number of slots exceeds capacity"
//const auto free_slot = make_free_slot();
//const auto lambda_slot = make_lambda_slot();
//const auto static_slot = make_static_slot();
//const auto instance_slot = make_instance_slot();
//const auto functor_slot = make_functor_slot();
//const auto extra_slot = make_extra_slot();
//signal_type signal{ free_slot, lambda_slot, static_slot, instance_slot, functor_slot, extra_slot };
}
#if ETL_USING_CPP14
//***************************************************************************
TEST(test_constexpr_construct_from_slot_list)
{
static constexpr auto free_slot = make_free_slot();
static constexpr auto lambda_slot = make_lambda_slot();
static constexpr auto static_slot = make_static_slot();
static constexpr auto instance_slot = make_instance_slot();
static constexpr auto functor_slot = make_functor_slot();
static constexpr signal_type signal{ free_slot, lambda_slot, static_slot, instance_slot, functor_slot };
CHECK_EQUAL(5, signal.size());
CHECK_EQUAL(0, signal.available());
CHECK_EQUAL(5, signal.max_size());
CHECK_FALSE(signal.empty());
CHECK_TRUE(signal.full());
}
#endif
//***************************************************************************
TEST(test_construct_with_incorrect_slot_type)
{
// Uncomment to trigger static_assert "All slots must be slot_type"
//const auto free_slot = make_free_slot();
//const auto lambda_slot = make_lambda_slot();
//const auto incorrect_slot = make_incorrect_slot(); // Incorrect type
//const auto instance_slot = make_instance_slot();
//const auto functor_slot = make_functor_slot();
//signal_type signal{ free_slot, lambda_slot, incorrect_slot, instance_slot, functor_slot };
}
//***************************************************************************
TEST(test_connect)
{
signal_type signal;
const auto free_slot = make_free_slot();
CHECK_TRUE(signal.connect(free_slot));
CHECK_EQUAL(1U, signal.size());
CHECK_EQUAL(4U, signal.available());
signal.connect(free_slot); // Try to connect it again - nothing should change.
CHECK_EQUAL(1U, signal.size());
CHECK_EQUAL(4U, signal.available());
CHECK_FALSE(signal.empty());
CHECK_FALSE(signal.full());
CHECK_TRUE(signal.connected(free_slot));
const auto lambda_slot = make_lambda_slot();
CHECK_TRUE(signal.connect(lambda_slot));
CHECK_EQUAL(2U, signal.size());
CHECK_EQUAL(3U, signal.available());
CHECK_FALSE(signal.empty());
CHECK_FALSE(signal.full());
CHECK_TRUE(signal.connected(lambda_slot));
const auto static_slot = make_static_slot();
CHECK_TRUE(signal.connect(static_slot));
CHECK_EQUAL(3U, signal.size());
CHECK_EQUAL(2U, signal.available());
CHECK_FALSE(signal.empty());
CHECK_FALSE(signal.full());
CHECK_TRUE(signal.connected(static_slot));
const auto instance_slot = make_instance_slot();
CHECK_TRUE(signal.connect(instance_slot));
CHECK_EQUAL(4U, signal.size());
CHECK_EQUAL(1U, signal.available());
CHECK_FALSE(signal.empty());
CHECK_FALSE(signal.full());
CHECK_TRUE(signal.connected(instance_slot));
const auto functor_slot = make_functor_slot();
CHECK_TRUE(signal.connect(functor_slot));
CHECK_EQUAL(5U, signal.size());
CHECK_EQUAL(0U, signal.available());
CHECK_FALSE(signal.empty());
CHECK_TRUE(signal.full());
CHECK_TRUE(signal.connected(functor_slot));
}
#if ETL_USING_CPP17
//***************************************************************************
TEST(test_connect_from_initializer_list)
{
const auto free_slot = make_free_slot();
const auto lambda_slot = make_lambda_slot();
const auto static_slot = make_static_slot();
const auto instance_slot = make_instance_slot();
const auto functor_slot = make_functor_slot();
signal_type signal;
CHECK_TRUE(signal.connect({ free_slot, lambda_slot, static_slot, instance_slot, functor_slot }));
CHECK_EQUAL(5U, signal.size());
CHECK_TRUE(signal.connected(free_slot));
CHECK_TRUE(signal.connected(lambda_slot));
CHECK_TRUE(signal.connected(static_slot));
CHECK_TRUE(signal.connected(instance_slot));
CHECK_TRUE(signal.connected(functor_slot));
CHECK_EQUAL(0U, signal.available());
CHECK_FALSE(signal.empty());
CHECK_TRUE(signal.full());
}
#endif
#if ETL_USING_CPP17
//***************************************************************************
TEST(test_connect_from_initializer_list_too_many_slots)
{
const auto free_slot = make_free_slot();
const auto lambda_slot = make_lambda_slot();
const auto static_slot = make_static_slot();
const auto instance_slot = make_instance_slot();
const auto functor_slot = make_functor_slot();
const auto extra_slot = make_extra_slot();
signal_type signal;
CHECK_THROW(signal.connect({ free_slot, lambda_slot, static_slot, instance_slot, functor_slot, extra_slot }), etl::signal_full);
}
#endif
//***************************************************************************
TEST(test_connect_from_span)
{
const auto free_slot = make_free_slot();
const auto lambda_slot = make_lambda_slot();
const auto static_slot = make_static_slot();
const auto instance_slot = make_instance_slot();
const auto functor_slot = make_functor_slot();
const slot_type slot_list[] = { free_slot, lambda_slot, static_slot, instance_slot, functor_slot };
signal_type signal;
CHECK_TRUE(signal.connect(slot_list));
}
//***************************************************************************
TEST(test_connect_from_span_too_many_slots)
{
const auto free_slot = make_free_slot();
const auto lambda_slot = make_lambda_slot();
const auto static_slot = make_static_slot();
const auto instance_slot = make_instance_slot();
const auto functor_slot = make_functor_slot();
const auto extra_slot = make_extra_slot();
const slot_type slot_list[] = { free_slot, lambda_slot, static_slot, instance_slot, functor_slot, extra_slot };
signal_type signal;
CHECK_THROW(signal.connect(slot_list), etl::signal_full);
}
//***************************************************************************
TEST(test_disconnect)
{
const auto free_slot = make_free_slot();
const auto lambda_slot = make_lambda_slot();
const auto static_slot = make_static_slot();
const auto instance_slot = make_instance_slot();
const auto functor_slot = make_functor_slot();
const slot_type slot_list[] = { free_slot, lambda_slot, static_slot, instance_slot, functor_slot };
signal_type signal;
CHECK_TRUE(signal.connect(slot_list));
signal.disconnect(free_slot);
CHECK_EQUAL(4U, signal.size());
CHECK_EQUAL(1U, signal.available());
CHECK_FALSE(signal.connected(free_slot));
CHECK_FALSE(signal.empty());
CHECK_FALSE(signal.full());
// Try to remove it again - nothing should change.
signal.disconnect(free_slot);
CHECK_EQUAL(4U, signal.size());
CHECK_EQUAL(1U, signal.available());
CHECK_FALSE(signal.connected(free_slot));
CHECK_FALSE(signal.empty());
CHECK_FALSE(signal.full());
signal.disconnect(lambda_slot);
CHECK_EQUAL(3U, signal.size());
CHECK_EQUAL(2U, signal.available());
CHECK_FALSE(signal.connected(lambda_slot));
CHECK_FALSE(signal.empty());
CHECK_FALSE(signal.full());
signal.disconnect(static_slot);
CHECK_EQUAL(2U, signal.size());
CHECK_EQUAL(3U, signal.available());
CHECK_FALSE(signal.connected(static_slot));
CHECK_FALSE(signal.empty());
CHECK_FALSE(signal.full());
signal.disconnect(instance_slot);
CHECK_EQUAL(1U, signal.size());
CHECK_EQUAL(4U, signal.available());
CHECK_FALSE(signal.connected(instance_slot));
CHECK_FALSE(signal.empty());
CHECK_FALSE(signal.full());
signal.disconnect(functor_slot);
CHECK_EQUAL(0U, signal.size());
CHECK_EQUAL(5U, signal.available());
CHECK_FALSE(signal.connected(functor_slot));
CHECK_TRUE(signal.empty());
CHECK_FALSE(signal.full());
}
}
#if ETL_USING_CPP17
//***************************************************************************
TEST(test_disconnect_from_initializer_list)
{
const auto free_slot = make_free_slot();
const auto lambda_slot = make_lambda_slot();
const auto static_slot = make_static_slot();
const auto instance_slot = make_instance_slot();
const auto functor_slot = make_functor_slot();
signal_type signal;
CHECK_TRUE(signal.connect({ free_slot, lambda_slot, static_slot, instance_slot, functor_slot }));
signal.disconnect({ lambda_slot, instance_slot });
CHECK_EQUAL(3U, signal.size());
CHECK_FALSE(signal.empty());
CHECK_TRUE(signal.connected(free_slot));
CHECK_FALSE(signal.connected(lambda_slot));
CHECK_TRUE(signal.connected(static_slot));
CHECK_FALSE(signal.connected(instance_slot));
CHECK_TRUE(signal.connected(functor_slot));
}
#endif
//***************************************************************************
TEST(test_disconnect_from_span_list)
{
const auto free_slot = make_free_slot();
const auto lambda_slot = make_lambda_slot();
const auto static_slot = make_static_slot();
const auto instance_slot = make_instance_slot();
const auto functor_slot = make_functor_slot();
signal_type signal;
CHECK_TRUE(signal.connect(free_slot));
CHECK_TRUE(signal.connect(lambda_slot));
CHECK_TRUE(signal.connect(static_slot));
CHECK_TRUE(signal.connect(instance_slot));
CHECK_TRUE(signal.connect(functor_slot));
const slot_type slot_list[] = { lambda_slot, instance_slot };
signal.disconnect(span_type(slot_list));
CHECK_EQUAL(3U, signal.size());
CHECK_FALSE(signal.empty());
CHECK_TRUE(signal.connected(free_slot));
CHECK_FALSE(signal.connected(lambda_slot));
CHECK_TRUE(signal.connected(static_slot));
CHECK_FALSE(signal.connected(instance_slot));
CHECK_TRUE(signal.connected(functor_slot));
}
//***************************************************************************
TEST(test_disconnect_all)
{
const auto free_slot = make_free_slot();
const auto lambda_slot = make_lambda_slot();
const auto static_slot = make_static_slot();
const auto instance_slot = make_instance_slot();
const auto functor_slot = make_functor_slot();
const slot_type slot_list[] = { free_slot, lambda_slot, static_slot, instance_slot, functor_slot };
signal_type signal;
CHECK_TRUE(signal.connect(slot_list));
signal.disconnect_all();
CHECK_EQUAL(0U, signal.size());
CHECK_TRUE(signal.empty());
CHECK_FALSE(signal.connected(free_slot));
CHECK_FALSE(signal.connected(lambda_slot));
CHECK_FALSE(signal.connected(static_slot));
CHECK_FALSE(signal.connected(instance_slot));
CHECK_FALSE(signal.connected(functor_slot));
}
//***************************************************************************
TEST(test_call_empty)
{
std::stringstream ss;
signal_type signal;
signal(ss);
CHECK_EQUAL(std::string{""}, ss.str());
}
//***************************************************************************
TEST(test_call)
{
const auto free_slot = make_free_slot();
const auto lambda_slot = make_lambda_slot();
const auto static_slot = make_static_slot();
const auto instance_slot = make_instance_slot();
const auto functor_slot = make_functor_slot();
signal_type signal{ free_slot, lambda_slot, static_slot, instance_slot, functor_slot };
std::stringstream ss;
signal(ss);
// Expect all signals got called
const std::string expected_string{"freelambdastaticmethodfunctor"};
CHECK_EQUAL(expected_string, ss.str());
}
#if ETL_USING_CPP14
//***************************************************************************
TEST(test_constexpr_call)
{
static constexpr auto free_slot = make_free_slot();
static constexpr auto lambda_slot = make_lambda_slot();
static constexpr auto static_slot = make_static_slot();
static constexpr auto instance_slot = make_instance_slot();
static constexpr auto functor_slot = make_functor_slot();
static constexpr signal_type signal{ free_slot, lambda_slot, static_slot, instance_slot, functor_slot };
std::stringstream ss;
signal(ss);
// Expect all slots got called
const std::string expected_string{"freelambdastaticmethodfunctor"};
CHECK_EQUAL(expected_string, ss.str());
}
#endif
//***************************************************************************
TEST(test_call_empty_slots)
{
const auto free_slot = make_free_slot();
const auto lambda_slot = make_empty_slot();
const auto static_slot = make_static_slot();
const auto instance_slot = make_empty_slot();
const auto functor_slot = make_functor_slot();
signal_type signal{ free_slot, lambda_slot, static_slot, instance_slot, functor_slot };
std::stringstream ss;
signal(ss);
// Expect only valid slots got called
const std::string expected_string{"freestaticfunctor"};
CHECK_EQUAL(expected_string, ss.str());
}
#if ETL_USING_CPP14
//***************************************************************************
TEST(test_call_constexpr_empty_slots)
{
static constexpr auto free_slot = make_free_slot();
static constexpr auto lambda_slot = make_empty_slot();
static constexpr auto static_slot = make_static_slot();
static constexpr auto instance_slot = make_empty_slot();
static constexpr auto functor_slot = make_functor_slot();
static constexpr signal_type signal{ free_slot, lambda_slot, static_slot, instance_slot, functor_slot };
std::stringstream ss;
signal(ss);
// Expect only valid slots got called
const std::string expected_string{"freestaticfunctor"};
CHECK_EQUAL(expected_string, ss.str());
}
#endif
}

View File

@ -3651,6 +3651,7 @@
<ClInclude Include="..\..\include\etl\rounded_integral_division.h" />
<ClInclude Include="..\..\include\etl\scaled_rounding.h" />
<ClInclude Include="..\..\include\etl\shared_message.h" />
<ClInclude Include="..\..\include\etl\signal.h" />
<ClInclude Include="..\..\include\etl\singleton.h" />
<ClInclude Include="..\..\include\etl\singleton_base.h" />
<ClInclude Include="..\..\include\etl\span.h" />
@ -8927,6 +8928,26 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug MSVC C++20 - Force C++03|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug MSVC C++20 - Force C++03 - No virtual messages|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\syntax_check\signal.h.t.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug MSVC C++20|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug MSVC C++20 - No virtual imessage|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug MSVC C++ 20 - No Tests|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug MSVC C++23 - No STL|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug MSVC C++23|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug MSVC C++20 - No STL|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug MSVC C++14|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release MSVC C++20 - No STL - Optimised -O2|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release MSVC C++20 - No STL - Optimised -O2 - Sanitiser|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug MSVC C++20 - Force C++03 - No virtual messages|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug MSVC C++17|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug MSVC C++17 - No STL|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release MSVC C++20 - Optimised O2|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug MSVC C++20 - No virtual messages|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug MSVC C++14 - No STL|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug MSVC C++20 - Force C++03|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug Clang C++20|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug Clang C++20 - Optimised -O2|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\syntax_check\singleton.h.t.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug MSVC C++20|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug Clang C++20|Win32'">true</ExcludedFromBuild>
@ -11264,6 +11285,7 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\test_signal.cpp" />
<ClCompile Include="..\test_singleton.cpp" />
<ClCompile Include="..\test_singleton_base.cpp" />
<ClCompile Include="..\test_span_dynamic_extent.cpp" />