Merge remote-tracking branch 'origin/feature/delegates' into development

# Conflicts:
#	include/etl/type_traits.h
#	include/etl/type_traits_generator.h
#	test/test_type_traits.cpp
This commit is contained in:
John Wellbelove 2019-05-19 23:16:24 +01:00
parent d2719cb63d
commit d2d3db1659
22 changed files with 2062 additions and 120 deletions

View File

@ -0,0 +1,149 @@
#include <iostream>
#include "etl/delegate.h"
#include "etl/delegate_service.h"
enum VectorId
{
TIM1_CC_IRQ_HANDLER = 42,
TIM2_IRQ_HANDLER = 43,
TIM3_IRQ_HANDLER = 44,
USART1_IRQ_HANDLER = 52,
USART2_IRQ_HANDLER = 53,
VECTOR_ID_END,
VECTOR_ID_OFFSET = TIM1_CC_IRQ_HANDLER,
VECTOR_ID_RANGE = VECTOR_ID_END - VECTOR_ID_OFFSET
};
typedef etl::delegate_service<VECTOR_ID_RANGE, VECTOR_ID_OFFSET> InterruptVectors;
// Ensure that the callback service is initialised before use.
InterruptVectors& GetInterruptVectorsInstance()
{
static InterruptVectors interruptVectors;
return interruptVectors;
}
extern "C"
{
InterruptVectors& interruptVectors = GetInterruptVectorsInstance();
// Function called from the timer1 interrupt vector.
void TIM1_CC_IRQHandler()
{
interruptVectors.call<TIM1_CC_IRQ_HANDLER>();
}
// Function called from the timer2 interrupt vector.
void TIM2_IRQHandler()
{
interruptVectors.call<TIM2_IRQ_HANDLER>();
}
// Function called from the timer3 interrupt vector.
void TIM3_IRQHandler()
{
interruptVectors.call<TIM3_IRQ_HANDLER>();
}
// Function called from the usart1 interrupt vector.
void USART1_IRQHandler()
{
interruptVectors.call<USART1_IRQ_HANDLER>();
}
// Function called from the usart2 interrupt vector.
void USART2_IRQHandler()
{
interruptVectors.call<USART2_IRQ_HANDLER>();
}
}
//********************************
// Timer driver.
//********************************
class Timer
{
public:
// Handler for interrupts from the timer.
void InterruptHandler(const size_t id)
{
std::cout << "Timer interrupt (member) : ID " << id << "\n";
}
};
//********************************
// Free function timer driver.
//********************************
void FreeTimerInterruptHandler(const size_t id)
{
std::cout << "Timer interrupt (free) : ID " << id << "\n";
}
//********************************
// UART driver.
//********************************
class Uart
{
public:
// Constructor.
Uart(int port_id, size_t interruptId)
: port_id(port_id),
callback(etl::delegate<void(size_t)>::create<Uart, &Uart::InterruptHandler>(*this))
{
GetInterruptVectorsInstance().register_delegate(interruptId, callback);
}
// Handler for interrupts from the UART.
void InterruptHandler(const size_t id)
{
std::cout << "UART" << port_id << " : ID " << id << "\n";
}
etl::delegate<void(size_t)> callback;
int port_id;
};
void UnhandledInterrupt(const size_t id)
{
std::cout << "Unhandled Interrupt : ID " << id << "\n";
}
// Declare the driver instances.
Timer timer;
Uart uart1(0, USART1_IRQ_HANDLER);
Uart uart2(1, USART2_IRQ_HANDLER);
// Declare a global callback for the timer.
// Uses the most efficient callback type for a class, as everthing is known at compile time.
etl::delegate<void(size_t)> timer_member_callback = etl::delegate<void(size_t)>::create<Timer, timer, &Timer::InterruptHandler>();
// Declare the callbacks for the free functions.
etl::delegate<void(size_t)> timer_free_callback = etl::delegate<void(size_t)>::create<FreeTimerInterruptHandler>();
etl::delegate<void(size_t)> unhandled_callback = etl::delegate<void(size_t)>::create<UnhandledInterrupt>();
//********************************
// Test it out.
//********************************
int main()
{
// Setup the callbacks.
InterruptVectors& interruptVectors = GetInterruptVectorsInstance();
interruptVectors.register_delegate<TIM1_CC_IRQ_HANDLER>(timer_member_callback);
interruptVectors.register_delegate<TIM2_IRQ_HANDLER>(timer_free_callback);
interruptVectors.register_unhandled_delegate(unhandled_callback);
// Simulate the interrupts.
TIM1_CC_IRQHandler();
TIM2_IRQHandler();
USART1_IRQHandler();
USART2_IRQHandler();
TIM3_IRQHandler(); // Unhandled!
return 0;
}

View File

@ -0,0 +1,48 @@
///\file
/******************************************************************************
The MIT License(MIT)
Embedded Template Library.
https://github.com/ETLCPP/etl
https://www.etlcpp.com
Copyright(c) 2017 jwellbelove
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_PROFILE_H__
#define __ETL_PROFILE_H__
#define ETL_THROW_EXCEPTIONS
#define ETL_VERBOSE_ERRORS
#define ETL_CHECK_PUSH_POP
#define ETL_ISTRING_REPAIR_ENABLE
#define ETL_IVECTOR_REPAIR_ENABLE
#define ETL_IDEQUE_REPAIR_ENABLE
#define ETL_IN_UNIT_TEST
#ifdef _MSC_VER
#include "profiles/msvc_x86.h"
#else
#include "profiles/gcc_windows_x86.h"
#endif
#endif

View File

@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26730.16
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FunctionInterruptSimulation-Delegates", "FunctionInterruptSimulation-Delegates.vcxproj", "{5157DB15-C255-4E47-9FB1-AF388437F90F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{5157DB15-C255-4E47-9FB1-AF388437F90F}.Debug|x64.ActiveCfg = Debug|x64
{5157DB15-C255-4E47-9FB1-AF388437F90F}.Debug|x64.Build.0 = Debug|x64
{5157DB15-C255-4E47-9FB1-AF388437F90F}.Debug|x86.ActiveCfg = Debug|Win32
{5157DB15-C255-4E47-9FB1-AF388437F90F}.Debug|x86.Build.0 = Debug|Win32
{5157DB15-C255-4E47-9FB1-AF388437F90F}.Release|x64.ActiveCfg = Release|x64
{5157DB15-C255-4E47-9FB1-AF388437F90F}.Release|x64.Build.0 = Release|x64
{5157DB15-C255-4E47-9FB1-AF388437F90F}.Release|x86.ActiveCfg = Release|Win32
{5157DB15-C255-4E47-9FB1-AF388437F90F}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {260225EB-60CB-44CC-A60C-16A23BBC10EB}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,156 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\FunctionInterruptSimulation.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\etl_profile.h" />
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{5157DB15-C255-4E47-9FB1-AF388437F90F}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>FunctionInterruptSimulation</RootNamespace>
<WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>../../../src</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>../../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

334
include/etl/delegate.h Normal file
View File

@ -0,0 +1,334 @@
///\file
/******************************************************************************
The MIT License(MIT)
Embedded Template Library.
https://github.com/ETLCPP/etl
https://www.etlcpp.com
Copyright(c) 2019 jwellbelove
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.
******************************************************************************/
/******************************************************************************
Copyright (C) 2017 by Sergey A Kryukov: derived work
http://www.SAKryukov.org
http://www.codeproject.com/Members/SAKryukov
Based on original work by Sergey Ryazanov:
"The Impossibly Fast C++ Delegates", 18 Jul 2005
https://www.codeproject.com/articles/11015/the-impossibly-fast-c-delegates
MIT license:
http://en.wikipedia.org/wiki/MIT_License
Original publication: https://www.codeproject.com/Articles/1170503/The-Impossibly-Fast-Cplusplus-Delegates-Fixed
******************************************************************************/
#ifndef ETL_DELEGATE_INCLUDED
#define ETL_DELEGATE_INCLUDED
#include "platform.h"
#if ETL_CPP11_SUPPORTED == 0
#error NOT SUPPORTED FOR C++03 OR BELOW
#endif
namespace etl
{
template <typename T> class delegate;
template <typename TReturn, typename... TParams>
class delegate<TReturn(TParams...)> final
{
public:
//*************************************************************************
/// Default constructor.
//*************************************************************************
delegate() = default;
//*************************************************************************
// Copy constructor.
//*************************************************************************
delegate(const delegate& other)
{
other.invocation.clone(invocation);
}
//*************************************************************************
// Constructor from lambda or functor.
//*************************************************************************
template <typename TLambda>
delegate(const TLambda& instance)
{
assign((void*)(&instance), lambda_stub<TLambda>);
}
//*************************************************************************
/// Create from function (Compile time).
//*************************************************************************
template <TReturn(*Method)(TParams...)>
static delegate create()
{
return delegate(nullptr, function_stub<Method>);
}
//*************************************************************************
/// Create from Lambda or Functor.
//*************************************************************************
template <typename TLambda>
static delegate create(const TLambda& instance)
{
return delegate((void*)(&instance), lambda_stub<TLambda>);
}
//*************************************************************************
/// Create from instance method (Run time).
//*************************************************************************
template <typename T, TReturn(T::*Method)(TParams...)>
static delegate create(T& instance)
{
return delegate((void*)(&instance), method_stub<T, Method>);
}
//*************************************************************************
/// Create from const instance method (Run time).
//*************************************************************************
template <typename T, TReturn(T::*Method)(TParams...) const>
static delegate create(const T& instance)
{
return delegate((void*)(&instance), const_method_stub<T, Method>);
}
//*************************************************************************
/// Create from instance method (Compile time).
//*************************************************************************
template <typename T, T& Instance, TReturn(T::*Method)(TParams...)>
static delegate create()
{
return delegate(method_instance_stub<T, Instance, Method>);
}
//*************************************************************************
/// Create from const instance method (Compile time).
//*************************************************************************
template <typename T, T const& Instance, TReturn(T::*Method)(TParams...) const>
static delegate create()
{
return delegate(const_method_instance_stub<T, Instance, Method>);
}
//*************************************************************************
/// Execute the delegate.
//*************************************************************************
TReturn operator()(TParams... args) const
{
return (*invocation.stub)(invocation.object, args...);
}
//*************************************************************************
/// Create from function (Compile time).
//*************************************************************************
delegate& operator =(const delegate& other)
{
other.invocation.clone(invocation);
return *this;
}
//*************************************************************************
/// Create from Lambda or Functor.
//*************************************************************************
template <typename TLambda>
delegate& operator =(const TLambda& instance)
{
assign((void*)(&instance), lambda_stub<TLambda>);
return *this;
}
//*************************************************************************
/// Checks equality.
//*************************************************************************
bool operator == (const delegate& other) const
{
return invocation == other.invocation;
}
//*************************************************************************
/// Returns <b>true</b> if the delegate is valid.
//*************************************************************************
bool operator != (const delegate& other) const
{
return invocation != other.invocation;
}
//*************************************************************************
/// Returns <b>true</b> if the delegate is valid.
//*************************************************************************
bool is_valid() const
{
return invocation.stub != nullptr;
}
//*************************************************************************
/// Returns <b>true</b> if the delegate is valid.
//*************************************************************************
operator bool() const
{
return is_valid();
}
private:
using stub_type = TReturn(*)(void* object, TParams...);
//*************************************************************************
/// The internal invocation object.
//*************************************************************************
struct invocation_element
{
invocation_element() = default;
//***********************************************************************
invocation_element(void* object_, stub_type stub_)
: object(object_)
, stub(stub_)
{
}
//***********************************************************************
void clone(invocation_element& target) const
{
target.stub = stub;
target.object = object;
}
//***********************************************************************
bool operator ==(const invocation_element& another) const
{
return (another.stub == stub) && (another.object == object);
}
//***********************************************************************
bool operator !=(const invocation_element& another) const
{
return (another.stub != stub) || (another.object != object);
}
//***********************************************************************
void* object = nullptr;
stub_type stub = nullptr;
};
//*************************************************************************
/// Constructs a delegate from an object and stub.
//*************************************************************************
delegate(void* object, stub_type stub)
{
invocation.object = object;
invocation.stub = stub;
}
//*************************************************************************
/// Constructs a delegate from a stub.
//*************************************************************************
delegate(stub_type stub)
{
invocation.object = nullptr;
invocation.stub = stub;
}
//*************************************************************************
/// Assign from an object and stub.
//*************************************************************************
void assign(void* object, stub_type stub)
{
invocation.object = object;
invocation.stub = stub;
}
//*************************************************************************
/// Stub call for a member function. Run time instance.
//*************************************************************************
template <typename T, TReturn(T::*Method)(TParams...)>
static TReturn method_stub(void* object, TParams... params)
{
T* p = static_cast<T*>(object);
return (p->*Method)(params...);
}
//*************************************************************************
/// Stub call for a const member function. Run time instance.
//*************************************************************************
template <typename T, TReturn(T::*Method)(TParams...) const>
static TReturn const_method_stub(void* object, TParams... params)
{
T* const p = static_cast<T*>(object);
return (p->*Method)(params...);
}
//*************************************************************************
/// Stub call for a member function. Compile time instance.
//*************************************************************************
template <typename T, T& Instance, TReturn(T::*Method)(TParams...)>
static TReturn method_instance_stub(void*, TParams... params)
{
return (Instance.*Method)(params...);
}
//*************************************************************************
/// Stub call for a const member function. Compile time instance.
//*************************************************************************
template <typename T, const T& Instance, TReturn(T::*Method)(TParams...) const>
static TReturn const_method_instance_stub(void*, TParams... params)
{
return (Instance.*Method)(params...);
}
//*************************************************************************
/// Stub call for a free function.
//*************************************************************************
template <TReturn(*Method)(TParams...)>
static TReturn function_stub(void*, TParams... params)
{
return (Method)(params...);
}
//*************************************************************************
/// Stub call for a lambda or functor function.
//*************************************************************************
template <typename TLambda>
static TReturn lambda_stub(void* object, TParams... arg)
{
TLambda* p = static_cast<TLambda*>(object);
return (p->operator())(arg...);
}
//*************************************************************************
/// The invocation object.
//*************************************************************************
invocation_element invocation;
};
}
#endif

View File

@ -0,0 +1,157 @@
///\file
/******************************************************************************
The MIT License(MIT)
Embedded Template Library.
https://github.com/ETLCPP/etl
https://www.etlcpp.com
Copyright(c) 2019 jwellbelove
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_DELEGATE_SERVICE_INCLUDED
#define ETL_DELEGATE_SERVICE_INCLUDED
#include "platform.h"
#include "nullptr.h"
#include "static_assert.h"
#include "delegate.h"
#include "array.h"
namespace etl
{
//***************************************************************************
/// An indexed delegate service.
/// \tparam RANGE The number of delegates to handle.
/// \tparam OFFSET The lowest delegate id value.
/// The delegate ids must range between OFFSET and OFFSET + RANGE - 1.
//***************************************************************************
template <const size_t RANGE, const size_t OFFSET = 0U>
class delegate_service
{
public:
//*************************************************************************
/// Reset the delegate service.
/// Sets all delegates to the internal default.
//*************************************************************************
delegate_service()
{
etl::delegate<void(size_t)> default_delegate = etl::delegate<void(size_t)>::create<delegate_service<RANGE, OFFSET>, &delegate_service<RANGE, OFFSET>::unhandled>(*this);
lookup.fill(default_delegate);
}
//*************************************************************************
/// Registers a delegate for the specified id.
/// Compile time assert if the id is out of range.
/// \tparam ID The id of the delegate.
/// \param delegate Reference to the delegate.
//*************************************************************************
template <const size_t ID>
void register_delegate(etl::delegate<void(size_t)> callback)
{
ETL_STATIC_ASSERT(ID < (OFFSET + RANGE), "Callback Id out of range");
ETL_STATIC_ASSERT(ID >= OFFSET, "Callback Id out of range");
lookup[ID - OFFSET] = callback;
}
//*************************************************************************
/// Registers a delegate for the specified id.
/// No action if the id is out of range.
/// \param id Id of the delegate.
/// \param delegate Reference to the delegate.
//*************************************************************************
void register_delegate(const size_t id, etl::delegate<void(size_t)> callback)
{
if ((id >= OFFSET) && (id < (OFFSET + RANGE)))
{
lookup[id - OFFSET] = callback;
}
}
//*************************************************************************
/// Registers an alternative delegate for unhandled ids.
/// \param delegate A reference to the user supplied 'unhandled' delegate.
//*************************************************************************
void register_unhandled_delegate(etl::delegate<void(size_t)> callback)
{
unhandled_delegate = callback;
}
//*************************************************************************
/// Executes the delegate function for the index.
/// Compile time assert if the id is out of range.
/// \tparam ID The id of the delegate.
//*************************************************************************
template <const size_t ID>
void call()
{
ETL_STATIC_ASSERT(ID < (OFFSET + RANGE), "Callback Id out of range");
ETL_STATIC_ASSERT(ID >= OFFSET, "Callback Id out of range");
lookup[ID - OFFSET](ID);
}
//*************************************************************************
/// Executes the delegate function for the index.
/// \param id Id of the delegate.
//*************************************************************************
void call(const size_t id)
{
if ((id >= OFFSET) && (id < (OFFSET + RANGE)))
{
lookup[id - OFFSET](id);
}
else
{
if (unhandled_delegate.is_valid())
{
unhandled_delegate(id);
}
}
}
private:
//*************************************************************************
/// The default callback function.
/// Calls the user defined 'unhandled' callback if it exists.
//*************************************************************************
void unhandled(size_t id)
{
if (unhandled_delegate.is_valid())
{
unhandled_delegate(id);
}
}
/// The default delegate for unhandled ids.
etl::delegate<void(size_t)> unhandled_delegate;
/// Lookup table of delegates.
etl::array<etl::delegate<void(size_t)>, RANGE> lookup;
};
}
#endif

View File

@ -0,0 +1,143 @@
///\file
/******************************************************************************
The MIT License(MIT)
Embedded Template Library.
https://github.com/ETLCPP/etl
https://www.etlcpp.com
Copyright(c) 2019 jwellbelove
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.
******************************************************************************/
/******************************************************************************
Copyright (C) 2017 by Sergey A Kryukov: derived work
http://www.SAKryukov.org
http://www.codeproject.com/Members/SAKryukov
Based on original work by Sergey Ryazanov:
"The Impossibly Fast C++ Delegates", 18 Jul 2005
https://www.codeproject.com/articles/11015/the-impossibly-fast-c-delegates
MIT license:
http://en.wikipedia.org/wiki/MIT_License
Original publication: https://www.codeproject.com/Articles/1170503/The-Impossibly-Fast-Cplusplus-Delegates-Fixed
******************************************************************************/
//#pragma once
//#include "delegate.h"
//#include <list>
//#include <functional>
//
//namespace SA {
//
// template<typename RET, typename ...PARAMS>
// class multicast_delegate<RET(PARAMS...)> final : private delegate_base<RET(PARAMS...)> {
// public:
//
// multicast_delegate() = default;
// ~multicast_delegate() {
// for (auto& element : invocationList) delete element;
// invocationList.clear();
// } //~multicast_delegate
//
// bool isNull() const { return invocationList.size() < 1; }
// bool operator ==(void* ptr) const {
// return (ptr == nullptr) && this->isNull();
// } //operator ==
// bool operator !=(void* ptr) const {
// return (ptr != nullptr) || (!this->isNull());
// } //operator !=
//
// size_t size() const { return invocationList.size(); }
//
// multicast_delegate& operator =(const multicast_delegate&) = delete;
// multicast_delegate(const multicast_delegate&) = delete;
//
// bool operator ==(const multicast_delegate& another) const {
// if (invocationList.size() != another.invocationList.size()) return false;
// auto anotherIt = another.invocationList.begin();
// for (auto it = invocationList.begin(); it != invocationList.end(); ++it)
// if (**it != **anotherIt) return false;
// return true;
// } //==
// bool operator !=(const multicast_delegate& another) const { return !(*this == another); }
//
// bool operator ==(const delegate<RET(PARAMS...)>& another) const {
// if (isNull() && another.isNull()) return true;
// if (another.isNull() || (size() != 1)) return false;
// return (another.invocation == **invocationList.begin());
// } //==
// bool operator !=(const delegate<RET(PARAMS...)>& another) const { return !(*this == another); }
//
// multicast_delegate& operator +=(const multicast_delegate& another) {
// for (auto& item : another.invocationList) // clone, not copy; flattens hierarchy:
// this->invocationList.push_back(new typename delegate_base<RET(PARAMS...)>::InvocationElement(item->object, item->stub));
// return *this;
// } //operator +=
//
// template <typename LAMBDA> // template instantiation is not neededm, will be deduced/inferred:
// multicast_delegate& operator +=(const LAMBDA & lambda) {
// delegate<RET(PARAMS...)> d = delegate<RET(PARAMS...)>::template create<LAMBDA>(lambda);
// return *this += d;
// } //operator +=
//
// multicast_delegate& operator +=(const delegate<RET(PARAMS...)>& another) {
// if (another.isNull()) return *this;
// this->invocationList.push_back(new typename delegate_base<RET(PARAMS...)>::InvocationElement(another.invocation.object, another.invocation.stub));
// return *this;
// } //operator +=
//
// // will work even if RET is void, return values are ignored:
// // (for handling return values, see operator(..., handler))
// void operator()(PARAMS... arg) const {
// for (auto& item : invocationList)
// (*(item->stub))(item->object, arg...);
// } //operator()
//
// template<typename HANDLER>
// void operator()(PARAMS... arg, HANDLER handler) const {
// size_t index = 0;
// for (auto& item : invocationList) {
// RET value = (*(item->stub))(item->object, arg...);
// handler(index, &value);
// ++index;
// } //loop
// } //operator()
//
// void operator()(PARAMS... arg, delegate<void(size_t, RET*)> handler) const {
// operator()<decltype(handler)>(arg..., handler);
// } //operator()
// void operator()(PARAMS... arg, std::function<void(size_t, RET*)> handler) const {
// operator()<decltype(handler)>(arg..., handler);
// } //operator()
//
// private:
//
// std::list<typename delegate_base<RET(PARAMS...)>::InvocationElement *> invocationList;
//
// }; //class multicast_delegate
//
//} /* namespace SA */
//

View File

@ -600,13 +600,19 @@ namespace etl
template <typename T>
struct size_of
{
static const size_t size = sizeof(T);
enum
{
size = sizeof(T)
};
};
template <>
struct size_of<void>
{
static const size_t size = 1;
enum
{
size = 1
};
};
}

View File

@ -605,13 +605,19 @@ namespace etl
template <typename T>
struct size_of
{
static const size_t size = sizeof(T);
enum
{
size = sizeof(T)
};
};
template <>
struct size_of<void>
{
static const size_t size = 1;
enum
{
size = 1
};
};
}

View File

@ -181,6 +181,8 @@
<Unit filename="../../include/etl/cyclic_value.h" />
<Unit filename="../../include/etl/debounce.h" />
<Unit filename="../../include/etl/debug_count.h" />
<Unit filename="../../include/etl/delegate.h" />
<Unit filename="../../include/etl/delegate_service.h" />
<Unit filename="../../include/etl/deque.h" />
<Unit filename="../../include/etl/doxygen.h" />
<Unit filename="../../include/etl/endianness.h" />
@ -248,6 +250,9 @@
<Unit filename="../../include/etl/pool.h" />
<Unit filename="../../include/etl/power.h" />
<Unit filename="../../include/etl/priority_queue.h" />
<Unit filename="../../include/etl/private/delegate_base.h" />
<Unit filename="../../include/etl/private/delegate_base_cpp03.h" />
<Unit filename="../../include/etl/private/delegate_cpp03.h" />
<Unit filename="../../include/etl/private/ivectorpointer.h" />
<Unit filename="../../include/etl/private/pvoidvector.h" />
<Unit filename="../../include/etl/private/to_string_helper.h" />
@ -362,6 +367,8 @@
<Unit filename="../test_crc.cpp" />
<Unit filename="../test_cyclic_value.cpp" />
<Unit filename="../test_debounce.cpp" />
<Unit filename="../test_delegate.cpp" />
<Unit filename="../test_delegate_service.cpp" />
<Unit filename="../test_deque.cpp" />
<Unit filename="../test_endian.cpp" />
<Unit filename="../test_enum_type.cpp" />

View File

@ -101,7 +101,6 @@ namespace
// Callback for 'unhandled'.
etl::function_fp<size_t, unhandled> unhandled_callback;
}
//*****************************************************************************
// Initialises the test results.
@ -117,6 +116,7 @@ struct SetupFixture
unhandled_called = false;
}
};
}
namespace
{

506
test/test_delegate.cpp Normal file
View File

@ -0,0 +1,506 @@
/******************************************************************************
The MIT License(MIT)
Embedded Template Library.
https://github.com/ETLCPP/etl
http://www.etlcpp.com
Copyright(c) 2014 jwellbelove
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++.h"
#include "etl/delegate.h"
namespace
{
//*****************************************************************************
const int VALUE1 = 1;
const int VALUE2 = 2;
bool function_called = false;
bool parameter_correct = false;
//*****************************************************************************
// Test data structure.
//*****************************************************************************
struct Data
{
int d;
};
Data data;
//*****************************************************************************
// The free function taking no parameters.
//*****************************************************************************
void free_void()
{
function_called = true;
}
//*****************************************************************************
// The free function taking an int parameter.
//*****************************************************************************
void free_int(int i, int j)
{
function_called = true;
parameter_correct = (i == VALUE1) && (j == VALUE2);
}
//*****************************************************************************
// The free function taking a Data reference parameter.
//*****************************************************************************
void free_reference(const Data& data, int j)
{
function_called = true;
parameter_correct = (data.d == VALUE1) && (j = VALUE2);
}
//*****************************************************************************
// The test class with member functions.
//*****************************************************************************
class Test
{
public:
//*******************************************
// void
void member_void()
{
function_called = true;
}
void member_void_const() const
{
function_called = true;
}
//*******************************************
// int
void member_int(int i, int j)
{
function_called = true;
parameter_correct = (i == VALUE1) && (j == VALUE2);
}
void member_int_const(int i, int j) const
{
function_called = true;
parameter_correct = (i == VALUE1) && (j == VALUE2);
}
//*******************************************
// reference
void member_reference(const Data& data, int j)
{
function_called = true;
parameter_correct = (data.d == VALUE1) && (j = VALUE2);
}
void member_reference_const(const Data& data, int j) const
{
function_called = true;
parameter_correct = (data.d == VALUE1) && (j = VALUE2);
}
//*******************************************
// static
static void member_static(const Data& data, int j)
{
function_called = true;
parameter_correct = (data.d == VALUE1) && (j = VALUE2);
}
//*******************************************
// operator()
void operator()()
{
function_called = true;
}
void operator()() const
{
function_called = true;
}
};
Test test_static;
const Test const_test_static;
}
//*****************************************************************************
// Initialises the test results.
//*****************************************************************************
struct SetupFixture
{
SetupFixture()
{
function_called = false;
parameter_correct = false;
}
};
namespace
{
SUITE(test_delegate)
{
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_is_valid_false)
{
etl::delegate<void(void)> d;
CHECK(!d.is_valid());
CHECK(!d);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_is_valid_true)
{
etl::delegate<void(void)> d([] {});
CHECK(d.is_valid());
CHECK(d);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_free_void)
{
etl::delegate<void(void)> d = etl::delegate<void(void)>::create<free_void>();
d();
CHECK(function_called);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_free_int)
{
etl::delegate<void(int, int)> d = etl::delegate<void(int, int)>::create<free_int>();
d(VALUE1, VALUE2);
CHECK(function_called);
CHECK(parameter_correct);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_free_reference)
{
etl::delegate<void(const Data&, int)> d = etl::delegate<void(const Data&, int)>::create<free_reference>();
Data data;
data.d = VALUE1;
d(data, VALUE2);
CHECK(function_called);
CHECK(parameter_correct);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_lambda_int)
{
etl::delegate<void(int, int)> d([](int i, int j) { function_called = true; parameter_correct = (i == VALUE1) && (j == VALUE2); });
d(VALUE1, VALUE2);
CHECK(function_called);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_lambda_int_create)
{
auto lambda = [](int i, int j) { function_called = true; parameter_correct = (i == VALUE1) && (j == VALUE2); };
etl::delegate<void(int, int)> d(lambda);
d(VALUE1, VALUE2);
CHECK(function_called);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_member_operator_void)
{
Test test;
etl::delegate<void(void)> d(test);
d();
CHECK(function_called);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_member_operator_void_create)
{
Test test;
etl::delegate<void(void)> d = etl::delegate<void(void)>::create(test);
d();
CHECK(function_called);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_member_operator_void_const)
{
const Test test;
etl::delegate<void(void)> d(test);
d();
CHECK(function_called);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_assignment_member_operator_void)
{
Test test;
etl::delegate<void(void)> d;
d = test;
d();
CHECK(function_called);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_member_void)
{
Test test;
etl::delegate<void(void)> d = etl::delegate<void(void)>::create<Test, &Test::member_void>(test);
d();
CHECK(function_called);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_member_void_const)
{
const Test test;
etl::delegate<void(void)> d = etl::delegate<void(void)>::create<Test, &Test::member_void_const>(test);
d();
CHECK(function_called);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_member_int)
{
Test test;
etl::delegate<void(int, int)> d = etl::delegate<void(int, int)>::create<Test, &Test::member_int>(test);
d(VALUE1, VALUE2);
CHECK(function_called);
CHECK(parameter_correct);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_member_int_const)
{
const Test test;
etl::delegate<void(int, int)> d = etl::delegate<void(int, int)>::create<Test, &Test::member_int_const>(test);
d(VALUE1, VALUE2);
CHECK(function_called);
CHECK(parameter_correct);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_member_reference)
{
Test test;
etl::delegate<void(const Data&, int)> d = etl::delegate<void(const Data&, int)>::create<Test, &Test::member_reference>(test);
Data data;
data.d = VALUE1;
d(data, VALUE2);
CHECK(function_called);
CHECK(parameter_correct);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_member_reference_const)
{
const Test test;
etl::delegate<void(const Data&, int)> d = etl::delegate<void(const Data&, int)>::create<Test, &Test::member_reference_const>(test);
Data data;
data.d = VALUE1;
d(data, VALUE2);
CHECK(function_called);
CHECK(parameter_correct);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_member_static)
{
etl::delegate<void(const Data&, int)> d = etl::delegate<void(const Data&, int)>::create<Test::member_static>();
Data data;
data.d = VALUE1;
d(data, VALUE2);
CHECK(function_called);
CHECK(parameter_correct);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_member_void_compile_time)
{
etl::delegate<void(void)> d = etl::delegate<void(void)>::create<Test, test_static, &Test::member_void>();
d();
CHECK(function_called);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_member_void_const_compile_time)
{
etl::delegate<void(void)> d = etl::delegate<void(void)>::create<Test, const_test_static, &Test::member_void_const>();
d();
CHECK(function_called);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_member_int_compile_time)
{
etl::delegate<void(int, int)> d = etl::delegate<void(int, int)>::create<Test, test_static, &Test::member_int>();
d(VALUE1, VALUE2);
CHECK(function_called);
CHECK(parameter_correct);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_member_int_const_compile_time)
{
etl::delegate<void(int, int)> d = etl::delegate<void(int, int)>::create<Test, const_test_static, &Test::member_int_const>();
d(VALUE1, VALUE2);
CHECK(function_called);
CHECK(parameter_correct);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_member_reference_compile_time)
{
etl::delegate<void(const Data&, int)> d = etl::delegate<void(const Data&, int)>::create<Test, test_static, &Test::member_reference>();
Data data;
data.d = VALUE1;
d(data, VALUE2);
CHECK(function_called);
CHECK(parameter_correct);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_member_reference_const_compile_time)
{
etl::delegate<void(const Data&, int)> d = etl::delegate<void(const Data&, int)>::create<Test, const_test_static, &Test::member_reference_const>();
Data data;
data.d = VALUE1;
d(data, VALUE2);
CHECK(function_called);
CHECK(parameter_correct);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_copy_construct)
{
Test test;
etl::delegate<void(int, int)> d1 = etl::delegate<void(int, int)>::create<Test, &Test::member_int>(test);
etl::delegate<void(int, int)> d2(d1);
d2(VALUE1, VALUE2);
CHECK(function_called);
CHECK(parameter_correct);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_assignment)
{
Test test;
etl::delegate<void(int, int)> d1 = etl::delegate<void(int, int)>::create<Test, &Test::member_int>(test);
etl::delegate<void(int, int)> d2;
d2 = d1;
d2(VALUE1, VALUE2);
CHECK(function_called);
CHECK(parameter_correct);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_delegate_equal)
{
Test test;
etl::delegate<void(int, int)> d1 = etl::delegate<void(int, int)>::create<Test, &Test::member_int>(test);
etl::delegate<void(int, int)> d2 = d1;
CHECK(d1 == d2);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_delegate_not_equal)
{
Test test;
etl::delegate<void(int, int)> d1 = etl::delegate<void(int, int)>::create<Test, &Test::member_int>(test);
etl::delegate<void(int, int)> d2 = etl::delegate<void(int, int)>::create<Test, &Test::member_int_const>(test);;
CHECK(d1 != d2);
}
};
}

View File

@ -0,0 +1,333 @@
/******************************************************************************
The MIT License(MIT)
Embedded Template Library.
https://github.com/ETLCPP/etl
https://www.etlcpp.com
Copyright(c) 2019 jwellbelove
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++.h"
#include "etl/delegate.h"
#include "etl/delegate_service.h"
namespace
{
const size_t SIZE = 3U;
const size_t OFFSET = 5U;
using Service = etl::delegate_service<SIZE, OFFSET>;
//*****************************************************************************
bool global_called = false;
bool member1_called = false;
bool member2_called = false;
bool unhandled_called = false;
size_t called_id = UINT_MAX;
//*****************************************************************************
// The global function taking no parameters.
//*****************************************************************************
void global(size_t id)
{
global_called = true;
called_id = id;
}
//*****************************************************************************
// The external unhandled callback.
//*****************************************************************************
void unhandled(size_t id)
{
unhandled_called = true;
called_id = id;
}
//*****************************************************************************
// The test class with member functions.
//*****************************************************************************
class Test
{
public:
Test()
: callback(etl::delegate<void(size_t)>::create<Test, &Test::member1>(*this))
{
}
void member1(size_t id)
{
member1_called = true;
called_id = id;
}
void member2(size_t id)
{
member2_called = true;
called_id = id;
}
// Callback for 'member1'.
etl::delegate<void(size_t)> callback;
};
Test test;
// Callback for 'member2'.
etl::delegate<void(size_t)> member_callback = etl::delegate<void(size_t)>::create<Test, test, &Test::member2>();
// Callback for 'global'.
etl::delegate<void(size_t)> global_callback = etl::delegate<void(size_t)>::create<global>();
// Callback for 'unhandled'.
etl::delegate<void(size_t)> unhandled_callback = etl::delegate<void(size_t)>::create<unhandled>();
//*****************************************************************************
// Initialises the test results.
//*****************************************************************************
struct SetupFixture
{
SetupFixture()
{
called_id = UINT_MAX;
global_called = false;
member1_called = false;
member2_called = false;
unhandled_called = false;
}
};
}
namespace
{
enum
{
GLOBAL = OFFSET,
MEMBER1,
MEMBER2,
OUT_OF_RANGE
};
SUITE(test_delegate_service)
{
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_delegate_global_compile_time)
{
Service service;
service.register_delegate<GLOBAL>(global_callback);
service.register_delegate<MEMBER1>(test.callback);
service.register_delegate<MEMBER2>(member_callback);
service.call<GLOBAL>();
CHECK_EQUAL(GLOBAL, called_id);
CHECK(global_called);
CHECK(!member1_called);
CHECK(!member2_called);
CHECK(!unhandled_called);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_delegate_global_run_time)
{
Service service;
service.register_delegate(GLOBAL, global_callback);
service.register_delegate(MEMBER1, test.callback);
service.register_delegate(MEMBER2, member_callback);
service.call(GLOBAL);
CHECK_EQUAL(GLOBAL, called_id);
CHECK(global_called);
CHECK(!member1_called);
CHECK(!member2_called);
CHECK(!unhandled_called);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_delegate_member1_compile_time)
{
Service service;
service.register_delegate<GLOBAL>(global_callback);
service.register_delegate<MEMBER1>(test.callback);
service.register_delegate<MEMBER2>(member_callback);
service.call<MEMBER1>();
CHECK_EQUAL(MEMBER1, called_id);
CHECK(!global_called);
CHECK(member1_called);
CHECK(!member2_called);
CHECK(!unhandled_called);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_delegate_member1_run_time)
{
Service service;
service.register_delegate(GLOBAL, global_callback);
service.register_delegate(MEMBER1, test.callback);
service.register_delegate(MEMBER2, member_callback);
service.call(MEMBER1);
CHECK_EQUAL(MEMBER1, called_id);
CHECK(!global_called);
CHECK(member1_called);
CHECK(!member2_called);
CHECK(!unhandled_called);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_delegate_member2_compile_time)
{
Service service;
service.register_delegate<GLOBAL>(global_callback);
service.register_delegate<MEMBER1>(test.callback);
service.register_delegate<MEMBER2>(member_callback);
service.call<MEMBER2>();
CHECK_EQUAL(MEMBER2, called_id);
CHECK(!global_called);
CHECK(!member1_called);
CHECK(member2_called);
CHECK(!unhandled_called);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_delegate_unhandled_out_of_range_run_time_default)
{
Service service;
service.register_delegate<GLOBAL>(global_callback);
service.register_delegate<MEMBER1>(test.callback);
service.register_delegate<MEMBER2>(member_callback);
service.call(OUT_OF_RANGE);
CHECK_EQUAL(UINT_MAX, called_id);
CHECK(!global_called);
CHECK(!member1_called);
CHECK(!member2_called);
CHECK(!unhandled_called);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_delegate_unhandled_out_of_range_run_time_user_supplied)
{
Service service;
service.register_delegate<GLOBAL>(global_callback);
service.register_delegate<MEMBER1>(test.callback);
service.register_delegate<MEMBER2>(member_callback);
service.register_unhandled_delegate(unhandled_callback);
service.call(OUT_OF_RANGE);
CHECK_EQUAL(OUT_OF_RANGE, called_id);
CHECK(!global_called);
CHECK(!member1_called);
CHECK(!member2_called);
CHECK(unhandled_called);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_delegate_unhandled_not_registered_compile_time_default)
{
Service service;
service.register_delegate<GLOBAL>(global_callback);
service.register_delegate<MEMBER2>(member_callback);
service.call<MEMBER1>();
CHECK_EQUAL(UINT_MAX, called_id);
CHECK(!global_called);
CHECK(!member1_called);
CHECK(!member2_called);
CHECK(!unhandled_called);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_delegate_unhandled_not_registered_run_time_default)
{
Service service;
service.register_delegate(GLOBAL, global_callback);
service.register_delegate(MEMBER2, member_callback);
service.call(MEMBER1);
CHECK_EQUAL(UINT_MAX, called_id);
CHECK(!global_called);
CHECK(!member1_called);
CHECK(!member2_called);
CHECK(!unhandled_called);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_delegate_not_registered_compile_time_user_supplied)
{
Service service;
service.register_delegate<GLOBAL>(global_callback);
service.register_delegate<MEMBER2>(member_callback);
service.register_unhandled_delegate(unhandled_callback);
service.call<MEMBER1>();
CHECK_EQUAL(MEMBER1, called_id);
CHECK(!global_called);
CHECK(!member1_called);
CHECK(!member2_called);
CHECK(unhandled_called);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_delegate_unhandled_run_time_user_supplied)
{
Service service;
service.register_delegate(GLOBAL, global_callback);
service.register_delegate(MEMBER2, member_callback);
service.register_unhandled_delegate(unhandled_callback);
service.call(MEMBER1);
CHECK_EQUAL(MEMBER1, called_id);
CHECK(!global_called);
CHECK(!member1_called);
CHECK(!member2_called);
CHECK(unhandled_called);
}
};
}

View File

@ -30,6 +30,8 @@ SOFTWARE.
#include "etl/function.h"
namespace
{
//*****************************************************************************
const int VALUE = 1;
bool function_called = false;
@ -147,6 +149,7 @@ public:
};
Test test_static;
}
//*****************************************************************************
// Initialises the test results.

View File

@ -3688,6 +3688,20 @@ namespace
CHECK(std::find_if(text.end(), pe, [](Text::value_type x) { return x != 0; }) == pe);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_secure_after_resize_down)
{
Text text;
text.set_secure();
text.assign(STR("ABCDEF"));
Text::pointer pe = text.end();
text.resize(text.size() - 3U);
CHECK(std::find_if(text.end(), pe, [](Text::value_type x) { return x != 0; }) == pe);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_secure_after_erase)
{

View File

@ -3688,6 +3688,20 @@ namespace
CHECK(std::find_if(text.end(), pe, [](Text::value_type x) { return x != 0; }) == pe);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_secure_after_resize_down)
{
Text text;
text.set_secure();
text.assign(STR("ABCDEF"));
Text::pointer pe = text.end();
text.resize(text.size() - 3U);
CHECK(std::find_if(text.end(), pe, [](Text::value_type x) { return x != 0; }) == pe);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_secure_after_erase)
{

View File

@ -3688,6 +3688,20 @@ namespace
CHECK(std::find_if(text.end(), pe, [](Text::value_type x) { return x != 0; }) == pe);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_secure_after_resize_down)
{
Text text;
text.set_secure();
text.assign(STR("ABCDEF"));
Text::pointer pe = text.end();
text.resize(text.size() - 3U);
CHECK(std::find_if(text.end(), pe, [](Text::value_type x) { return x != 0; }) == pe);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_secure_after_erase)
{

View File

@ -49,9 +49,12 @@ namespace
namespace etl
{
template <>
struct etl::size_of<TestData>
struct size_of<TestData>
{
static const size_t size = 20;
enum
{
size = 20
};
};
}

View File

@ -372,6 +372,8 @@
<ClInclude Include="..\..\include\etl\crc32_c.h" />
<ClInclude Include="..\..\include\etl\cumulative_moving_average.h" />
<ClInclude Include="..\..\include\etl\c\ecl_timer.h" />
<ClInclude Include="..\..\include\etl\delegate.h" />
<ClInclude Include="..\..\include\etl\delegate_service.h" />
<ClInclude Include="..\..\include\etl\format_spec.h" />
<ClInclude Include="..\..\include\etl\frame_check_sequence.h" />
<ClInclude Include="..\..\include\etl\fsm.h" />
@ -582,6 +584,8 @@
<ClCompile Include="..\test_alignment.cpp" />
<ClCompile Include="..\test_callback_service.cpp" />
<ClCompile Include="..\test_cumulative_moving_average.cpp" />
<ClCompile Include="..\test_delegate.cpp" />
<ClCompile Include="..\test_delegate_service.cpp" />
<ClCompile Include="..\test_forward_list_shared_pool.cpp" />
<ClCompile Include="..\test_bit_stream.cpp" />
<ClCompile Include="..\test_list_shared_pool.cpp" />

View File

@ -768,6 +768,12 @@
<ClInclude Include="..\..\include\etl\multi_array.h">
<Filter>ETL\Containers</Filter>
</ClInclude>
<ClInclude Include="..\..\include\etl\delegate.h">
<Filter>ETL\Utilities</Filter>
</ClInclude>
<ClInclude Include="..\..\include\etl\delegate_service.h">
<Filter>ETL\Frameworks</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\main.cpp">
@ -1220,6 +1226,12 @@
<ClCompile Include="..\test_multi_array.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\test_delegate.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\test_delegate_service.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="..\..\library.properties">