From 0f00454410bb31971fbb118b42e64d20547f600c Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Thu, 28 Nov 2019 14:50:16 +0100 Subject: [PATCH 01/55] Delegate class template. Potential issue: automatic conversion from bind<>() doesn't work --- cores/esp8266/Delegate.h | 417 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 417 insertions(+) create mode 100644 cores/esp8266/Delegate.h diff --git a/cores/esp8266/Delegate.h b/cores/esp8266/Delegate.h new file mode 100644 index 0000000000..0d7441f5b6 --- /dev/null +++ b/cores/esp8266/Delegate.h @@ -0,0 +1,417 @@ +/* +Delegate.h - An efficient interchangeable C function ptr and C++ std::function delegate +Copyright (c) 2019 Dirk O. Kaar. All rights reserved. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef __Delegate_h +#define __Delegate_h + +#if defined(ARDUINO) +#include +#if !defined(ESP32) && !defined(ESP8266) +#define ICACHE_RAM_ATTR +#define IRAM_ATTR +#endif +#endif + +#include +#include + +namespace detail +{ + + template + class DelegateImpl { + public: + using FunPtr = R(*)(A, P...); + using FunctionType = std::function; + + DelegateImpl() + { + fn = nullptr; + obj = {}; + } + + DelegateImpl(std::nullptr_t) + { + fn = nullptr; + obj = {}; + } + + ~DelegateImpl() + { + if (FUNC == type) + functional.~FunctionType(); + } + + DelegateImpl(const DelegateImpl& del) + { + type = del.type; + if (FUNC == del.type) + { + new (&functional) FunctionType(); + functional = del.functional; + } + else + { + fn = del.fn; + obj = del.obj; + } + } + + DelegateImpl(DelegateImpl&& del) + { + type = del.type; + if (FUNC == del.type) + { + new (&functional) FunctionType(); + functional = std::move(del.functional); + } + else + { + fn = del.fn; + obj = del.obj; + } + } + + DelegateImpl(FunPtr fn, const A& obj) + { + type = FP; + DelegateImpl::fn = fn; + DelegateImpl::obj = obj; + } + + DelegateImpl(FunPtr fn, A&& obj) + { + type = FP; + DelegateImpl::fn = fn; + DelegateImpl::obj = std::move(obj); + } + + DelegateImpl(const FunctionType& functional) + { + type = FUNC; + new (&this->functional) FunctionType(); + DelegateImpl::functional = functional; + } + + DelegateImpl(FunctionType&& functional) + { + type = FUNC; + new (&this->functional) FunctionType(); + DelegateImpl::functional = std::move(functional); + } + + DelegateImpl& operator=(const DelegateImpl& del) + { + if (this == &del) return *this; + if (FUNC == type && FUNC != del.type) + { + functional.~FunctionType(); + } + else if (FUNC != type && FUNC == del.type) + { + new (&this->functional) FunctionType(); + } + type = del.type; + if (FUNC == del.type) + { + functional = del.functional; + } + else + { + fn = del.fn; + obj = del.obj; + } + return *this; + } + + DelegateImpl& operator=(DelegateImpl&& del) + { + if (this == &del) return *this; + if (FUNC == type && FUNC != del.type) + { + functional.~FunctionType(); + } + else if (FUNC != type && FUNC == del.type) + { + new (&this->functional) FunctionType(); + } + type = del.type; + if (FUNC == del.type) + { + functional = std::move(del.functional); + } + else + { + fn = del.fn; + obj = del.obj; + } + return *this; + } + + DelegateImpl& operator=(const FunctionType& functional) + { + if (FUNC != type) + { + new (&this->functional) FunctionType(); + type = FUNC; + } + this->functional = functional; + return *this; + } + + DelegateImpl& operator=(FunctionType&& functional) + { + if (FUNC != type) + { + new (&this->functional) FunctionType(); + type = FUNC; + } + this->functional = std::move(functional); + return *this; + } + + DelegateImpl& IRAM_ATTR operator=(std::nullptr_t) + { + if (FUNC == type) + { + functional.~FunctionType(); + } + type = FP; + fn = nullptr; + obj = {}; + return *this; + } + + operator bool() const + { + if (FUNC == type) + { + return functional ? true : false; + } + else + { + return fn; + } + } + + R IRAM_ATTR operator()(P... args) const + { + if (FUNC == type) + { + return functional(args...); + } + else + { + return fn(obj, args...); + } + } + + protected: + enum { FUNC, FP } type = FP; + union { + FunctionType functional; + struct { + FunPtr fn; + A obj; + }; + }; + }; + + template + class DelegateImpl { + public: + using FunPtr = R(*)(P...); + using FunctionType = std::function; + + DelegateImpl() + { + fn = nullptr; + } + + ~DelegateImpl() + { + if (FUNC == type) + functional.~FunctionType(); + } + + DelegateImpl(const DelegateImpl& del) + { + type = del.type; + if (FUNC == del.type) + { + new (&functional) FunctionType(); + functional = del.functional; + } + else + { + fn = del.fn; + } + } + + DelegateImpl(DelegateImpl&& del) + { + type = del.type; + if (FUNC == del.type) + { + new (&functional) FunctionType(); + functional = std::move(del.functional); + } + else + { + fn = del.fn; + } + } + + DelegateImpl(FunPtr fn) + { + type = FP; + DelegateImpl::fn = fn; + } + + DelegateImpl(const FunctionType& functional) + { + type = FUNC; + new (&this->functional) FunctionType(); + DelegateImpl::functional = functional; + } + + DelegateImpl(FunctionType&& functional) + { + type = FUNC; + new (&this->functional) FunctionType(); + DelegateImpl::functional = std::move(functional); + } + + DelegateImpl& operator=(const DelegateImpl& del) + { + if (this == &del) return *this; + if (FUNC == type && FUNC != del.type) + { + functional.~FunctionType(); + } + else if (FUNC != type && FUNC == del.type) + { + new (&this->functional) FunctionType(); + } + type = del.type; + if (FUNC == del.type) + { + functional = del.functional; + } + else + { + fn = del.fn; + } + return *this; + } + + DelegateImpl& operator=(DelegateImpl&& del) + { + if (this == &del) return *this; + if (FUNC == type && FUNC != del.type) + { + functional.~FunctionType(); + } + else if (FUNC != type && FUNC == del.type) + { + new (&this->functional) FunctionType(); + } + type = del.type; + if (FUNC == del.type) + { + functional = std::move(del.functional); + } + else + { + fn = del.fn; + } + return *this; + } + + DelegateImpl& operator=(const FunctionType& functional) + { + if (FUNC != type) + { + new (&this->functional) FunctionType(); + type = FUNC; + } + this->functional = functional; + return *this; + } + + DelegateImpl& operator=(FunctionType&& functional) + { + if (FUNC != type) + { + new (&this->functional) FunctionType(); + type = FUNC; + } + this->functional = std::move(functional); + return *this; + } + + DelegateImpl& IRAM_ATTR operator=(std::nullptr_t) + { + if (FUNC == type) + { + functional.~FunctionType(); + } + type = FP; + fn = nullptr; + return *this; + } + + operator bool() const + { + if (FUNC == type) + { + return functional ? true : false; + } + else + { + return fn; + } + } + + R IRAM_ATTR operator()(P... args) const + { + if (FUNC == type) + { + return functional(args...); + } + else + { + return fn(args...); + } + } + + protected: + enum { FUNC, FP } type = FP; + union { + FunctionType functional; + FunPtr fn; + }; + }; + +} + +template +using Delegate = detail::DelegateImpl; + +#endif // __Delegate_h From 4b6020cffde95f155c9af2b0a4cf9276abbd809e Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Thu, 28 Nov 2019 17:19:30 +0100 Subject: [PATCH 02/55] Solves problems with lambdas and std::bind --- cores/esp8266/Delegate.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/cores/esp8266/Delegate.h b/cores/esp8266/Delegate.h index 0d7441f5b6..905859d045 100644 --- a/cores/esp8266/Delegate.h +++ b/cores/esp8266/Delegate.h @@ -102,14 +102,14 @@ namespace detail DelegateImpl::obj = std::move(obj); } - DelegateImpl(const FunctionType& functional) + template DelegateImpl(const F& functional) { type = FUNC; new (&this->functional) FunctionType(); DelegateImpl::functional = functional; } - DelegateImpl(FunctionType&& functional) + template DelegateImpl(F&& functional) { type = FUNC; new (&this->functional) FunctionType(); @@ -164,7 +164,7 @@ namespace detail return *this; } - DelegateImpl& operator=(const FunctionType& functional) + template DelegateImpl& operator=(const F& functional) { if (FUNC != type) { @@ -175,7 +175,7 @@ namespace detail return *this; } - DelegateImpl& operator=(FunctionType&& functional) + template DelegateImpl& operator=(F&& functional) { if (FUNC != type) { @@ -284,14 +284,14 @@ namespace detail DelegateImpl::fn = fn; } - DelegateImpl(const FunctionType& functional) + template DelegateImpl(const F& functional) { type = FUNC; new (&this->functional) FunctionType(); DelegateImpl::functional = functional; } - DelegateImpl(FunctionType&& functional) + template DelegateImpl(F&& functional) { type = FUNC; new (&this->functional) FunctionType(); @@ -344,7 +344,7 @@ namespace detail return *this; } - DelegateImpl& operator=(const FunctionType& functional) + template DelegateImpl& operator=(const F& functional) { if (FUNC != type) { @@ -355,7 +355,7 @@ namespace detail return *this; } - DelegateImpl& operator=(FunctionType&& functional) + template DelegateImpl& operator=(F&& functional) { if (FUNC != type) { From 4363ce92f567237eb9c98c9fc20b50b413ad4ffc Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Thu, 28 Nov 2019 19:45:39 +0100 Subject: [PATCH 03/55] MSVC compiler picked up missing std::forward --- cores/esp8266/Delegate.h | 410 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 397 insertions(+), 13 deletions(-) diff --git a/cores/esp8266/Delegate.h b/cores/esp8266/Delegate.h index 905859d045..66e7ab5daa 100644 --- a/cores/esp8266/Delegate.h +++ b/cores/esp8266/Delegate.h @@ -22,11 +22,11 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #if defined(ARDUINO) #include +#endif #if !defined(ESP32) && !defined(ESP8266) #define ICACHE_RAM_ATTR #define IRAM_ATTR #endif -#endif #include #include @@ -35,11 +35,386 @@ namespace detail { template - class DelegateImpl { + class DelegatePImpl { public: using FunPtr = R(*)(A, P...); using FunctionType = std::function; + DelegatePImpl() + { + fn = nullptr; + obj = {}; + } + + DelegatePImpl(std::nullptr_t) + { + fn = nullptr; + obj = {}; + } + + ~DelegatePImpl() + { + if (FUNC == type) + functional.~FunctionType(); + } + + DelegatePImpl(const DelegatePImpl& del) + { + type = del.type; + if (FUNC == del.type) + { + new (&functional) FunctionType(); + functional = del.functional; + } + else + { + fn = del.fn; + obj = del.obj; + } + } + + DelegatePImpl(DelegatePImpl&& del) + { + type = del.type; + if (FUNC == del.type) + { + new (&functional) FunctionType(); + functional = std::move(del.functional); + } + else + { + fn = del.fn; + obj = del.obj; + } + } + + DelegatePImpl(FunPtr fn, const A& obj) + { + type = FP; + DelegatePImpl::fn = fn; + DelegatePImpl::obj = obj; + } + + DelegatePImpl(FunPtr fn, A&& obj) + { + type = FP; + DelegatePImpl::fn = fn; + DelegatePImpl::obj = std::move(obj); + } + + template DelegatePImpl(const F& functional) + { + type = FUNC; + new (&this->functional) FunctionType(); + DelegatePImpl::functional = functional; + } + + template DelegatePImpl(F&& functional) + { + type = FUNC; + new (&this->functional) FunctionType(); + DelegatePImpl::functional = std::move(functional); + } + + DelegatePImpl& operator=(const DelegatePImpl& del) + { + if (this == &del) return *this; + if (FUNC == type && FUNC != del.type) + { + functional.~FunctionType(); + } + else if (FUNC != type && FUNC == del.type) + { + new (&this->functional) FunctionType(); + } + type = del.type; + if (FUNC == del.type) + { + functional = del.functional; + } + else + { + fn = del.fn; + obj = del.obj; + } + return *this; + } + + DelegatePImpl& operator=(DelegatePImpl&& del) + { + if (this == &del) return *this; + if (FUNC == type && FUNC != del.type) + { + functional.~FunctionType(); + } + else if (FUNC != type && FUNC == del.type) + { + new (&this->functional) FunctionType(); + } + type = del.type; + if (FUNC == del.type) + { + functional = std::move(del.functional); + } + else + { + fn = del.fn; + obj = del.obj; + } + return *this; + } + + template DelegatePImpl& operator=(const F& functional) + { + if (FUNC != type) + { + new (&this->functional) FunctionType(); + type = FUNC; + } + this->functional = functional; + return *this; + } + + template DelegatePImpl& operator=(F&& functional) + { + if (FUNC != type) + { + new (&this->functional) FunctionType(); + type = FUNC; + } + this->functional = std::move(functional); + return *this; + } + + DelegatePImpl& IRAM_ATTR operator=(std::nullptr_t) + { + if (FUNC == type) + { + functional.~FunctionType(); + } + type = FP; + fn = nullptr; + obj = {}; + return *this; + } + + operator bool() const + { + if (FUNC == type) + { + return functional ? true : false; + } + else + { + return fn; + } + } + + R IRAM_ATTR operator()(P... args) const + { + if (FUNC == type) + { + return functional(std::forward(args...)); + } + else + { + return fn(obj, std::forward(args...)); + } + } + + protected: + enum { FUNC, FP } type = FP; + union { + FunctionType functional; + struct { + FunPtr fn; + A obj; + }; + }; + }; + + template + class DelegatePImpl { + public: + using FunPtr = R(*)(P...); + using FunctionType = std::function; + + DelegatePImpl() + { + fn = nullptr; + } + + ~DelegatePImpl() + { + if (FUNC == type) + functional.~FunctionType(); + } + + DelegatePImpl(const DelegatePImpl& del) + { + type = del.type; + if (FUNC == del.type) + { + new (&functional) FunctionType(); + functional = del.functional; + } + else + { + fn = del.fn; + } + } + + DelegatePImpl(DelegatePImpl&& del) + { + type = del.type; + if (FUNC == del.type) + { + new (&functional) FunctionType(); + functional = std::move(del.functional); + } + else + { + fn = del.fn; + } + } + + DelegatePImpl(FunPtr fn) + { + type = FP; + DelegatePImpl::fn = fn; + } + + template DelegatePImpl(const F& functional) + { + type = FUNC; + new (&this->functional) FunctionType(); + DelegatePImpl::functional = functional; + } + + template DelegatePImpl(F&& functional) + { + type = FUNC; + new (&this->functional) FunctionType(); + DelegatePImpl::functional = std::move(functional); + } + + DelegatePImpl& operator=(const DelegatePImpl& del) + { + if (this == &del) return *this; + if (FUNC == type && FUNC != del.type) + { + functional.~FunctionType(); + } + else if (FUNC != type && FUNC == del.type) + { + new (&this->functional) FunctionType(); + } + type = del.type; + if (FUNC == del.type) + { + functional = del.functional; + } + else + { + fn = del.fn; + } + return *this; + } + + DelegatePImpl& operator=(DelegatePImpl&& del) + { + if (this == &del) return *this; + if (FUNC == type && FUNC != del.type) + { + functional.~FunctionType(); + } + else if (FUNC != type && FUNC == del.type) + { + new (&this->functional) FunctionType(); + } + type = del.type; + if (FUNC == del.type) + { + functional = std::move(del.functional); + } + else + { + fn = del.fn; + } + return *this; + } + + template DelegatePImpl& operator=(const F& functional) + { + if (FUNC != type) + { + new (&this->functional) FunctionType(); + type = FUNC; + } + this->functional = functional; + return *this; + } + + template DelegatePImpl& operator=(F&& functional) + { + if (FUNC != type) + { + new (&this->functional) FunctionType(); + type = FUNC; + } + this->functional = std::move(functional); + return *this; + } + + DelegatePImpl& IRAM_ATTR operator=(std::nullptr_t) + { + if (FUNC == type) + { + functional.~FunctionType(); + } + type = FP; + fn = nullptr; + return *this; + } + + operator bool() const + { + if (FUNC == type) + { + return functional ? true : false; + } + else + { + return fn; + } + } + + R IRAM_ATTR operator()(P... args) const + { + if (FUNC == type) + { + return functional(std::forward(args...)); + } + else + { + return fn(std::forward(args...)); + } + } + + protected: + enum { FUNC, FP } type = FP; + union { + FunctionType functional; + FunPtr fn; + }; + }; + + template + class DelegateImpl { + public: + using FunPtr = R(*)(A); + using FunctionType = std::function; + DelegateImpl() { fn = nullptr; @@ -210,15 +585,15 @@ namespace detail } } - R IRAM_ATTR operator()(P... args) const + R IRAM_ATTR operator()() const { if (FUNC == type) { - return functional(args...); + return functional(); } else { - return fn(obj, args...); + return fn(obj); } } @@ -233,11 +608,11 @@ namespace detail }; }; - template - class DelegateImpl { + template + class DelegateImpl { public: - using FunPtr = R(*)(P...); - using FunctionType = std::function; + using FunPtr = R(*)(); + using FunctionType = std::function; DelegateImpl() { @@ -389,15 +764,15 @@ namespace detail } } - R IRAM_ATTR operator()(P... args) const + R IRAM_ATTR operator()() const { if (FUNC == type) { - return functional(args...); + return functional(); } else { - return fn(args...); + return fn(); } } @@ -412,6 +787,15 @@ namespace detail } template -using Delegate = detail::DelegateImpl; +class Delegate : public detail::DelegatePImpl +{ + using detail::DelegatePImpl::DelegatePImpl; +}; + +template +class Delegate : public detail::DelegateImpl +{ + using detail::DelegateImpl::DelegateImpl; +}; #endif // __Delegate_h From d133e30bffabe1ef68fa581edae22588aa7a6024 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Fri, 29 Nov 2019 11:52:46 +0100 Subject: [PATCH 04/55] Circular include issue fixed --- cores/esp8266/Delegate.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/cores/esp8266/Delegate.h b/cores/esp8266/Delegate.h index 66e7ab5daa..0a2de775bd 100644 --- a/cores/esp8266/Delegate.h +++ b/cores/esp8266/Delegate.h @@ -20,10 +20,11 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #ifndef __Delegate_h #define __Delegate_h -#if defined(ARDUINO) -#include -#endif -#if !defined(ESP32) && !defined(ESP8266) +#if defined(ESP8266) +#include +#elif defined(ESP32) +#include +#else #define ICACHE_RAM_ATTR #define IRAM_ATTR #endif From c56fa87b74dfb1e7fc6fe9b4bc1202593321a4a0 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Fri, 29 Nov 2019 12:45:42 +0100 Subject: [PATCH 05/55] Use function declaration syntax in template type specification --- cores/esp8266/Delegate.h | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/cores/esp8266/Delegate.h b/cores/esp8266/Delegate.h index 0a2de775bd..11a639a680 100644 --- a/cores/esp8266/Delegate.h +++ b/cores/esp8266/Delegate.h @@ -785,18 +785,28 @@ namespace detail }; }; + template + class Delegate : public detail::DelegatePImpl + { + using detail::DelegatePImpl::DelegatePImpl; + }; + + template + class Delegate : public detail::DelegateImpl + { + using detail::DelegateImpl::DelegateImpl; + }; + } -template -class Delegate : public detail::DelegatePImpl +template class Delegate; +template class Delegate : public detail::Delegate { - using detail::DelegatePImpl::DelegatePImpl; + using detail::Delegate::Delegate; }; - -template -class Delegate : public detail::DelegateImpl +template class Delegate : public detail::Delegate { - using detail::DelegateImpl::DelegateImpl; + using detail::Delegate::Delegate; }; #endif // __Delegate_h From 48ed02b6ee22c08a7e3b90da283def59b26c8522 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Fri, 29 Nov 2019 16:09:07 +0100 Subject: [PATCH 06/55] Use terse function notation - match std::function, the optional 1st argument for C-style FP is now ONLY in 3rd template argument. --- cores/esp8266/Delegate.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cores/esp8266/Delegate.h b/cores/esp8266/Delegate.h index 11a639a680..6a550f3988 100644 --- a/cores/esp8266/Delegate.h +++ b/cores/esp8266/Delegate.h @@ -800,7 +800,7 @@ namespace detail } template class Delegate; -template class Delegate : public detail::Delegate +template class Delegate : public detail::Delegate { using detail::Delegate::Delegate; }; From bc8a0e684ef815e0d5a592deca1e275e59764a96 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Wed, 4 Dec 2019 20:16:05 +0100 Subject: [PATCH 07/55] Performance improvement for Delegate specialization without additional C-function ptr argument. --- cores/esp8266/Delegate.h | 175 +-------------------------------------- 1 file changed, 3 insertions(+), 172 deletions(-) diff --git a/cores/esp8266/Delegate.h b/cores/esp8266/Delegate.h index 6a550f3988..0596ceb5e5 100644 --- a/cores/esp8266/Delegate.h +++ b/cores/esp8266/Delegate.h @@ -235,179 +235,10 @@ namespace detail }; template - class DelegatePImpl { + class DelegatePImpl : public std::function { public: - using FunPtr = R(*)(P...); - using FunctionType = std::function; - - DelegatePImpl() - { - fn = nullptr; - } - - ~DelegatePImpl() - { - if (FUNC == type) - functional.~FunctionType(); - } - - DelegatePImpl(const DelegatePImpl& del) - { - type = del.type; - if (FUNC == del.type) - { - new (&functional) FunctionType(); - functional = del.functional; - } - else - { - fn = del.fn; - } - } - - DelegatePImpl(DelegatePImpl&& del) - { - type = del.type; - if (FUNC == del.type) - { - new (&functional) FunctionType(); - functional = std::move(del.functional); - } - else - { - fn = del.fn; - } - } - - DelegatePImpl(FunPtr fn) - { - type = FP; - DelegatePImpl::fn = fn; - } - - template DelegatePImpl(const F& functional) - { - type = FUNC; - new (&this->functional) FunctionType(); - DelegatePImpl::functional = functional; - } - - template DelegatePImpl(F&& functional) - { - type = FUNC; - new (&this->functional) FunctionType(); - DelegatePImpl::functional = std::move(functional); - } - - DelegatePImpl& operator=(const DelegatePImpl& del) - { - if (this == &del) return *this; - if (FUNC == type && FUNC != del.type) - { - functional.~FunctionType(); - } - else if (FUNC != type && FUNC == del.type) - { - new (&this->functional) FunctionType(); - } - type = del.type; - if (FUNC == del.type) - { - functional = del.functional; - } - else - { - fn = del.fn; - } - return *this; - } - - DelegatePImpl& operator=(DelegatePImpl&& del) - { - if (this == &del) return *this; - if (FUNC == type && FUNC != del.type) - { - functional.~FunctionType(); - } - else if (FUNC != type && FUNC == del.type) - { - new (&this->functional) FunctionType(); - } - type = del.type; - if (FUNC == del.type) - { - functional = std::move(del.functional); - } - else - { - fn = del.fn; - } - return *this; - } - - template DelegatePImpl& operator=(const F& functional) - { - if (FUNC != type) - { - new (&this->functional) FunctionType(); - type = FUNC; - } - this->functional = functional; - return *this; - } - - template DelegatePImpl& operator=(F&& functional) - { - if (FUNC != type) - { - new (&this->functional) FunctionType(); - type = FUNC; - } - this->functional = std::move(functional); - return *this; - } - - DelegatePImpl& IRAM_ATTR operator=(std::nullptr_t) - { - if (FUNC == type) - { - functional.~FunctionType(); - } - type = FP; - fn = nullptr; - return *this; - } - - operator bool() const - { - if (FUNC == type) - { - return functional ? true : false; - } - else - { - return fn; - } - } - - R IRAM_ATTR operator()(P... args) const - { - if (FUNC == type) - { - return functional(std::forward(args...)); - } - else - { - return fn(std::forward(args...)); - } - } - - protected: - enum { FUNC, FP } type = FP; - union { - FunctionType functional; - FunPtr fn; - }; + using std::function::function; + using std::function::operator=; }; template From 05e18114822e6046c48402922ffd0a8256761505 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Sun, 8 Dec 2019 00:13:01 +0100 Subject: [PATCH 08/55] Updated Delegate and new MultiDelegate template. --- cores/esp8266/Delegate.h | 245 +++++++++++---------- cores/esp8266/MultiDelegate.h | 400 ++++++++++++++++++++++++++++++++++ 2 files changed, 527 insertions(+), 118 deletions(-) create mode 100644 cores/esp8266/MultiDelegate.h diff --git a/cores/esp8266/Delegate.h b/cores/esp8266/Delegate.h index 0596ceb5e5..a9d47e357e 100644 --- a/cores/esp8266/Delegate.h +++ b/cores/esp8266/Delegate.h @@ -38,98 +38,99 @@ namespace detail template class DelegatePImpl { public: + using target_type = R(P...); using FunPtr = R(*)(A, P...); - using FunctionType = std::function; + using FunctionType = std::function; DelegatePImpl() { fn = nullptr; - obj = {}; + new (&obj) A; } DelegatePImpl(std::nullptr_t) { fn = nullptr; - obj = {}; + new (&obj) A; } ~DelegatePImpl() { - if (FUNC == type) + if (FUNC == kind) functional.~FunctionType(); + else + obj.~A(); } DelegatePImpl(const DelegatePImpl& del) { - type = del.type; - if (FUNC == del.type) + kind = del.kind; + if (FUNC == del.kind) { - new (&functional) FunctionType(); - functional = del.functional; + new (&functional) FunctionType(del.functional); } else { fn = del.fn; - obj = del.obj; + new (&obj) A(del.obj); } } DelegatePImpl(DelegatePImpl&& del) { - type = del.type; - if (FUNC == del.type) + kind = del.kind; + if (FUNC == del.kind) { - new (&functional) FunctionType(); - functional = std::move(del.functional); + new (&functional) FunctionType(std::move(del.functional)); } else { fn = del.fn; - obj = del.obj; + new (&obj) A(std::move(del.obj)); } } DelegatePImpl(FunPtr fn, const A& obj) { - type = FP; + kind = FP; DelegatePImpl::fn = fn; - DelegatePImpl::obj = obj; + new (&this->obj) A(obj); } DelegatePImpl(FunPtr fn, A&& obj) { - type = FP; + kind = FP; DelegatePImpl::fn = fn; - DelegatePImpl::obj = std::move(obj); + new (&this->obj) A(std::move(obj)); } template DelegatePImpl(const F& functional) { - type = FUNC; - new (&this->functional) FunctionType(); - DelegatePImpl::functional = functional; + kind = FUNC; + new (&this->functional) FunctionType(functional); } template DelegatePImpl(F&& functional) { - type = FUNC; - new (&this->functional) FunctionType(); - DelegatePImpl::functional = std::move(functional); + kind = FUNC; + new (&this->functional) FunctionType(std::move(functional)); } DelegatePImpl& operator=(const DelegatePImpl& del) { if (this == &del) return *this; - if (FUNC == type && FUNC != del.type) + if (FUNC == kind && FUNC != del.kind) { functional.~FunctionType(); + new (&obj) A; } - else if (FUNC != type && FUNC == del.type) + else if (FUNC != kind && FUNC == del.kind) { + obj.~A(); new (&this->functional) FunctionType(); } - type = del.type; - if (FUNC == del.type) + kind = del.kind; + if (FUNC == del.kind) { functional = del.functional; } @@ -144,33 +145,36 @@ namespace detail DelegatePImpl& operator=(DelegatePImpl&& del) { if (this == &del) return *this; - if (FUNC == type && FUNC != del.type) + if (FUNC == kind && FUNC != del.kind) { functional.~FunctionType(); + new (&obj) A; } - else if (FUNC != type && FUNC == del.type) + else if (FUNC != kind && FUNC == del.kind) { + obj.~A(); new (&this->functional) FunctionType(); } - type = del.type; - if (FUNC == del.type) + kind = del.kind; + if (FUNC == del.kind) { functional = std::move(del.functional); } else { fn = del.fn; - obj = del.obj; + obj = std::move(del.obj); } return *this; } template DelegatePImpl& operator=(const F& functional) { - if (FUNC != type) + if (FUNC != kind) { + obj.~A(); new (&this->functional) FunctionType(); - type = FUNC; + kind = FUNC; } this->functional = functional; return *this; @@ -178,10 +182,11 @@ namespace detail template DelegatePImpl& operator=(F&& functional) { - if (FUNC != type) + if (FUNC != kind) { + obj.~A(); new (&this->functional) FunctionType(); - type = FUNC; + kind = FUNC; } this->functional = std::move(functional); return *this; @@ -189,11 +194,12 @@ namespace detail DelegatePImpl& IRAM_ATTR operator=(std::nullptr_t) { - if (FUNC == type) + if (FUNC == kind) { functional.~FunctionType(); + new (&obj) A; } - type = FP; + kind = FP; fn = nullptr; obj = {}; return *this; @@ -201,7 +207,7 @@ namespace detail operator bool() const { - if (FUNC == type) + if (FUNC == kind) { return functional ? true : false; } @@ -213,7 +219,7 @@ namespace detail R IRAM_ATTR operator()(P... args) const { - if (FUNC == type) + if (FUNC == kind) { return functional(std::forward(args...)); } @@ -224,7 +230,7 @@ namespace detail } protected: - enum { FUNC, FP } type = FP; + enum { FUNC, FP } kind = FP; union { FunctionType functional; struct { @@ -244,98 +250,99 @@ namespace detail template class DelegateImpl { public: + using target_type = R(); using FunPtr = R(*)(A); - using FunctionType = std::function; + using FunctionType = std::function; DelegateImpl() { fn = nullptr; - obj = {}; + new (&obj) A; } DelegateImpl(std::nullptr_t) { fn = nullptr; - obj = {}; + new (&obj) A; } ~DelegateImpl() { - if (FUNC == type) + if (FUNC == kind) functional.~FunctionType(); + else + obj.~A(); } DelegateImpl(const DelegateImpl& del) { - type = del.type; - if (FUNC == del.type) + kind = del.kind; + if (FUNC == del.kind) { - new (&functional) FunctionType(); - functional = del.functional; + new (&functional) FunctionType(del.functional); } else { fn = del.fn; - obj = del.obj; + new (&obj) A(del.obj); } } DelegateImpl(DelegateImpl&& del) { - type = del.type; - if (FUNC == del.type) + kind = del.kind; + if (FUNC == del.kind) { - new (&functional) FunctionType(); - functional = std::move(del.functional); + new (&functional) FunctionType(std::move(del.functional)); } else { fn = del.fn; - obj = del.obj; + new (&obj) A(std::move(del.obj)); } } DelegateImpl(FunPtr fn, const A& obj) { - type = FP; + kind = FP; DelegateImpl::fn = fn; - DelegateImpl::obj = obj; + new (&this->obj) A(obj); } DelegateImpl(FunPtr fn, A&& obj) { - type = FP; + kind = FP; DelegateImpl::fn = fn; - DelegateImpl::obj = std::move(obj); + new (&this->obj) A(std::move(obj)); } template DelegateImpl(const F& functional) { - type = FUNC; - new (&this->functional) FunctionType(); - DelegateImpl::functional = functional; + kind = FUNC; + new (&this->functional) FunctionType(functional); } template DelegateImpl(F&& functional) { - type = FUNC; - new (&this->functional) FunctionType(); - DelegateImpl::functional = std::move(functional); + kind = FUNC; + new (&this->functional) FunctionType(std::move(functional)); } DelegateImpl& operator=(const DelegateImpl& del) { if (this == &del) return *this; - if (FUNC == type && FUNC != del.type) + if (FUNC == kind && FUNC != del.kind) { functional.~FunctionType(); + new (&obj) A; } - else if (FUNC != type && FUNC == del.type) + else if (FUNC != kind && FUNC == del.kind) { + obj.~A(); new (&this->functional) FunctionType(); } - type = del.type; - if (FUNC == del.type) + kind = del.kind; + if (FUNC == del.kind) { functional = del.functional; } @@ -350,33 +357,36 @@ namespace detail DelegateImpl& operator=(DelegateImpl&& del) { if (this == &del) return *this; - if (FUNC == type && FUNC != del.type) + if (FUNC == kind && FUNC != del.kind) { functional.~FunctionType(); + new (&obj) A; } - else if (FUNC != type && FUNC == del.type) + else if (FUNC != kind && FUNC == del.kind) { + obj.~A(); new (&this->functional) FunctionType(); } - type = del.type; - if (FUNC == del.type) + kind = del.kind; + if (FUNC == del.kind) { functional = std::move(del.functional); } else { fn = del.fn; - obj = del.obj; + obj = std::move(del.obj); } return *this; } template DelegateImpl& operator=(const F& functional) { - if (FUNC != type) + if (FUNC != kind) { + obj.~A(); new (&this->functional) FunctionType(); - type = FUNC; + kind = FUNC; } this->functional = functional; return *this; @@ -384,10 +394,11 @@ namespace detail template DelegateImpl& operator=(F&& functional) { - if (FUNC != type) + if (FUNC != kind) { + obj.~A(); new (&this->functional) FunctionType(); - type = FUNC; + kind = FUNC; } this->functional = std::move(functional); return *this; @@ -395,11 +406,12 @@ namespace detail DelegateImpl& IRAM_ATTR operator=(std::nullptr_t) { - if (FUNC == type) + if (FUNC == kind) { functional.~FunctionType(); + new (&obj) A; } - type = FP; + kind = FP; fn = nullptr; obj = {}; return *this; @@ -407,7 +419,7 @@ namespace detail operator bool() const { - if (FUNC == type) + if (FUNC == kind) { return functional ? true : false; } @@ -419,7 +431,7 @@ namespace detail R IRAM_ATTR operator()() const { - if (FUNC == type) + if (FUNC == kind) { return functional(); } @@ -430,7 +442,7 @@ namespace detail } protected: - enum { FUNC, FP } type = FP; + enum { FUNC, FP } kind = FP; union { FunctionType functional; struct { @@ -443,8 +455,9 @@ namespace detail template class DelegateImpl { public: + using target_type = R(); using FunPtr = R(*)(); - using FunctionType = std::function; + using FunctionType = std::function; DelegateImpl() { @@ -453,17 +466,16 @@ namespace detail ~DelegateImpl() { - if (FUNC == type) + if (FUNC == kind) functional.~FunctionType(); } DelegateImpl(const DelegateImpl& del) { - type = del.type; - if (FUNC == del.type) + kind = del.kind; + if (FUNC == del.kind) { - new (&functional) FunctionType(); - functional = del.functional; + new (&functional) FunctionType(del.functional); } else { @@ -473,11 +485,10 @@ namespace detail DelegateImpl(DelegateImpl&& del) { - type = del.type; - if (FUNC == del.type) + kind = del.kind; + if (FUNC == del.kind) { - new (&functional) FunctionType(); - functional = std::move(del.functional); + new (&functional) FunctionType(std::move(del.functional)); } else { @@ -487,37 +498,35 @@ namespace detail DelegateImpl(FunPtr fn) { - type = FP; + kind = FP; DelegateImpl::fn = fn; } template DelegateImpl(const F& functional) { - type = FUNC; - new (&this->functional) FunctionType(); - DelegateImpl::functional = functional; + kind = FUNC; + new (&this->functional) FunctionType(functional); } template DelegateImpl(F&& functional) { - type = FUNC; - new (&this->functional) FunctionType(); - DelegateImpl::functional = std::move(functional); + kind = FUNC; + new (&this->functional) FunctionType(std::move(functional)); } DelegateImpl& operator=(const DelegateImpl& del) { if (this == &del) return *this; - if (FUNC == type && FUNC != del.type) + if (FUNC == kind && FUNC != del.kind) { functional.~FunctionType(); } - else if (FUNC != type && FUNC == del.type) + else if (FUNC != kind && FUNC == del.kind) { new (&this->functional) FunctionType(); } - type = del.type; - if (FUNC == del.type) + kind = del.kind; + if (FUNC == del.kind) { functional = del.functional; } @@ -531,16 +540,16 @@ namespace detail DelegateImpl& operator=(DelegateImpl&& del) { if (this == &del) return *this; - if (FUNC == type && FUNC != del.type) + if (FUNC == kind && FUNC != del.kind) { functional.~FunctionType(); } - else if (FUNC != type && FUNC == del.type) + else if (FUNC != kind && FUNC == del.kind) { new (&this->functional) FunctionType(); } - type = del.type; - if (FUNC == del.type) + kind = del.kind; + if (FUNC == del.kind) { functional = std::move(del.functional); } @@ -553,10 +562,10 @@ namespace detail template DelegateImpl& operator=(const F& functional) { - if (FUNC != type) + if (FUNC != kind) { new (&this->functional) FunctionType(); - type = FUNC; + kind = FUNC; } this->functional = functional; return *this; @@ -564,10 +573,10 @@ namespace detail template DelegateImpl& operator=(F&& functional) { - if (FUNC != type) + if (FUNC != kind) { new (&this->functional) FunctionType(); - type = FUNC; + kind = FUNC; } this->functional = std::move(functional); return *this; @@ -575,18 +584,18 @@ namespace detail DelegateImpl& IRAM_ATTR operator=(std::nullptr_t) { - if (FUNC == type) + if (FUNC == kind) { functional.~FunctionType(); } - type = FP; + kind = FP; fn = nullptr; return *this; } operator bool() const { - if (FUNC == type) + if (FUNC == kind) { return functional ? true : false; } @@ -598,7 +607,7 @@ namespace detail R IRAM_ATTR operator()() const { - if (FUNC == type) + if (FUNC == kind) { return functional(); } @@ -609,7 +618,7 @@ namespace detail } protected: - enum { FUNC, FP } type = FP; + enum { FUNC, FP } kind = FP; union { FunctionType functional; FunPtr fn; diff --git a/cores/esp8266/MultiDelegate.h b/cores/esp8266/MultiDelegate.h new file mode 100644 index 0000000000..f5f75cd0e6 --- /dev/null +++ b/cores/esp8266/MultiDelegate.h @@ -0,0 +1,400 @@ +#ifndef __MULTIDELEGATE_H +#define __MULTIDELEGATE_H + +#include + +namespace detail +{ + namespace + { + template< typename Delegate, typename R, typename... P> + struct CallP + { + static R execute(Delegate& del, P... args) + { + return del(std::forward(args...)); + } + }; + + template< typename Delegate, typename... P> + struct CallP + { + static bool execute(Delegate& del, P... args) + { + del(std::forward(args...)); + return true; + } + }; + + template< typename Delegate, typename R> + struct Call + { + static R execute(Delegate& del) + { + return del(); + } + }; + + template< typename Delegate> + struct Call + { + static bool execute(Delegate& del) + { + del(); + return true; + } + }; + }; + + template< typename Delegate, typename R = void, uint32_t MULTICALLBACK_MAX_COUNT = 32, typename... P> + class MultiDelegatePImpl + { + public: + MultiDelegatePImpl() = default; + ~MultiDelegatePImpl() + { + *this = nullptr; + } + + MultiDelegatePImpl(const MultiDelegatePImpl&) = delete; + MultiDelegatePImpl& operator=(const MultiDelegatePImpl&) = delete; + + MultiDelegatePImpl(MultiDelegatePImpl&& md) + { + first = md.first; + last = md.last; + unused = md.unused; + nodeCount = md.nodeCount; + md.first = nullptr; + md.last = nullptr; + md.unused = nullptr; + md.nodeCount = 0; + } + + MultiDelegatePImpl(const Delegate& del) + { + add(del); + } + + MultiDelegatePImpl(Delegate&& del) + { + add(std::move(del)); + } + + MultiDelegatePImpl& operator=(MultiDelegatePImpl&& md) + { + first = md.first; + last = md.last; + unused = md.unused; + nodeCount = md.nodeCount; + md.first = nullptr; + md.last = nullptr; + md.unused = nullptr; + md.nodeCount = 0; + return *this; + } + + MultiDelegatePImpl& operator=(std::nullptr_t) + { + if (last) + last->mNext = unused; + if (first) + unused = first; + while (unused) + { + auto to_delete = unused; + unused = unused->mNext; + delete(to_delete); + } + return *this; + } + + MultiDelegatePImpl& operator+=(const Delegate& del) + { + add(del); + return *this; + } + + MultiDelegatePImpl& operator+=(Delegate&& del) + { + add(std::move(del)); + return *this; + } + + protected: + struct Node_t + { + ~Node_t() + { + mDelegate = nullptr; // special overload in Delegate + } + Node_t* mNext = nullptr; + Delegate mDelegate; + }; + + Node_t* first = nullptr; + Node_t* last = nullptr; + Node_t* unused = nullptr; + int nodeCount = 0; + + // Returns a pointer to an unused Node_t, + // or if none are available allocates a new one, + // or nullptr if limit is reached + Node_t* IRAM_ATTR get_node_unsafe() + { + Node_t* result = nullptr; + // try to get an item from unused items list + if (unused) + { + result = unused; + unused = unused->mNext; + } + // if no unused items, and count not too high, allocate a new one + else if (nodeCount < MULTICALLBACK_MAX_COUNT) + { + result = new (std::nothrow) Node_t; + if (result) + ++nodeCount; + } + return result; + } + + void recycle_node_unsafe(Node_t* node) + { + node->mDelegate = nullptr; // special overload in Delegate + node->mNext = unused; + unused = node; + } + + public: + const Delegate* IRAM_ATTR add(const Delegate& del) + { + return add(Delegate(del)); + } + + const Delegate* IRAM_ATTR add(Delegate&& del) + { + if (!del) + return nullptr; + + esp8266::InterruptLock lockAllInterruptsInThisScope; + + Node_t* item = get_node_unsafe(); + if (!item) + return nullptr; + + item->mDelegate = std::move(del); + item->mNext = nullptr; + + if (last) + last->mNext = item; + else + first = item; + last = item; + + return &item->mDelegate; + } + + bool remove(const Delegate* del) + { + auto current = first; + if (!current) + return false; + + Node_t* prev = nullptr; + do + { + if (del == ¤t->mDelegate) + { + // remove callback from stack + esp8266::InterruptLock lockAllInterruptsInThisScope; + + auto to_recycle = current; + + // removing rLast + if (last == current) + last = prev; + + current = current->mNext; + if (prev) + { + prev->mNext = current; + } + else + { + first = current; + } + + recycle_node_unsafe(to_recycle); + return true; + } + else + { + prev = current; + current = current->mNext; + } + } while (current); + return false; + } + + void operator()(P... args) + { + auto current = first; + if (!current) + return; + + static bool fence = false; + { + esp8266::InterruptLock lockAllInterruptsInThisScope; + + // prevent recursive calls + if (fence) + return; + fence = true; + } + + Node_t* prev = nullptr; + // prevent execution of new callbacks during this run + auto stop = last; + + bool done; + do + { + done = current == stop; + if (!CallP::execute(current->mDelegate, std::forward(args...))) + { + // remove callback from stack + esp8266::InterruptLock lockAllInterruptsInThisScope; + + auto to_recycle = current; + + // removing rLast + if (last == current) + last = prev; + + current = current->mNext; + if (prev) + { + prev->mNext = current; + } + else + { + first = current; + } + + recycle_node_unsafe(to_recycle); + } + else + { + prev = current; + current = current->mNext; + } + + // running callbacks might last too long for watchdog etc. + optimistic_yield(10000); + } while (current && !done); + + fence = false; + } + }; + + template< typename Delegate, typename R = void, uint32_t MULTICALLBACK_MAX_COUNT = 32> + class MultiDelegateImpl : public MultiDelegatePImpl + { + protected: + using typename MultiDelegatePImpl::Node_t; + using MultiDelegatePImpl::first; + using MultiDelegatePImpl::last; + using MultiDelegatePImpl::unused; + using MultiDelegatePImpl::nodeCount; + using MultiDelegatePImpl::recycle_node_unsafe; + + public: + using MultiDelegatePImpl::MultiDelegatePImpl; + + void operator()() + { + auto current = first; + if (!current) + return; + + static bool fence = false; + { + esp8266::InterruptLock lockAllInterruptsInThisScope; + + // prevent recursive calls + if (fence) + return; + fence = true; + } + + Node_t* prev = nullptr; + // prevent execution of new callbacks during this run + auto stop = last; + + bool done; + do + { + done = current == stop; + if (!Call::execute(current->mDelegate)) + { + // remove callback from stack + esp8266::InterruptLock lockAllInterruptsInThisScope; + + auto to_recycle = current; + + // removing rLast + if (last == current) + last = prev; + + current = current->mNext; + if (prev) + { + prev->mNext = current; + } + else + { + first = current; + } + + recycle_node_unsafe(to_recycle); + } + else + { + prev = current; + current = current->mNext; + } + + // running callbacks might last too long for watchdog etc. + optimistic_yield(10000); + } while (current && !done); + + fence = false; + } + }; + + template< typename Delegate, typename R, uint32_t MULTICALLBACK_MAX_COUNT, typename... P> class MultiDelegate; + + template< typename Delegate, typename R, uint32_t MULTICALLBACK_MAX_COUNT, typename... P> + class MultiDelegate : public MultiDelegatePImpl + { + public: + using MultiDelegatePImpl::MultiDelegatePImpl; + }; + + template< typename Delegate, typename R, uint32_t MULTICALLBACK_MAX_COUNT> + class MultiDelegate : public MultiDelegateImpl + { + public: + using MultiDelegateImpl::MultiDelegateImpl; + }; +}; + +template< typename Delegate, uint32_t MULTICALLBACK_MAX_COUNT = 32> +class MultiDelegate : public detail::MultiDelegate +{ +public: + using detail::MultiDelegate::MultiDelegatePImpl; +}; + +#endif // __MULTIDELEGATE_H From a5ee0653ba3a48657b6bfeff72afc73d27d33b4b Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Sun, 8 Dec 2019 09:10:56 +0100 Subject: [PATCH 09/55] MultiDelegate template argument to switch queue/event behavior. --- cores/esp8266/MultiDelegate.h | 64 +++++++++++++++++------------------ 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/cores/esp8266/MultiDelegate.h b/cores/esp8266/MultiDelegate.h index f5f75cd0e6..1400303219 100644 --- a/cores/esp8266/MultiDelegate.h +++ b/cores/esp8266/MultiDelegate.h @@ -7,46 +7,46 @@ namespace detail { namespace { - template< typename Delegate, typename R, typename... P> + template< typename Delegate, typename R, bool ISQUEUE = false, typename... P> struct CallP { static R execute(Delegate& del, P... args) { - return del(std::forward(args...)); + return del(std::forward(args...)) ? !ISQUEUE : ISQUEUE; } }; - template< typename Delegate, typename... P> - struct CallP + template< typename Delegate, bool ISQUEUE, typename... P> + struct CallP { static bool execute(Delegate& del, P... args) { del(std::forward(args...)); - return true; + return !ISQUEUE; } }; - template< typename Delegate, typename R> + template< typename Delegate, typename R, bool ISQUEUE = false> struct Call { static R execute(Delegate& del) { - return del(); + return del() ? !ISQUEUE : ISQUEUE; } }; - template< typename Delegate> - struct Call + template< typename Delegate, bool ISQUEUE> + struct Call { static bool execute(Delegate& del) { del(); - return true; + return !ISQUEUE; } }; }; - template< typename Delegate, typename R = void, uint32_t MULTICALLBACK_MAX_COUNT = 32, typename... P> + template< typename Delegate, typename R = void, bool ISQUEUE = false, uint32_t MULTICALLBACK_MAX_COUNT = 32, typename... P> class MultiDelegatePImpl { public: @@ -261,7 +261,7 @@ namespace detail do { done = current == stop; - if (!CallP::execute(current->mDelegate, std::forward(args...))) + if (!CallP::execute(current->mDelegate, std::forward(args...))) { // remove callback from stack esp8266::InterruptLock lockAllInterruptsInThisScope; @@ -298,19 +298,19 @@ namespace detail } }; - template< typename Delegate, typename R = void, uint32_t MULTICALLBACK_MAX_COUNT = 32> - class MultiDelegateImpl : public MultiDelegatePImpl + template< typename Delegate, typename R = void, bool ISQUEUE = false, uint32_t MULTICALLBACK_MAX_COUNT = 32> + class MultiDelegateImpl : public MultiDelegatePImpl { protected: - using typename MultiDelegatePImpl::Node_t; - using MultiDelegatePImpl::first; - using MultiDelegatePImpl::last; - using MultiDelegatePImpl::unused; - using MultiDelegatePImpl::nodeCount; - using MultiDelegatePImpl::recycle_node_unsafe; + using typename MultiDelegatePImpl::Node_t; + using MultiDelegatePImpl::first; + using MultiDelegatePImpl::last; + using MultiDelegatePImpl::unused; + using MultiDelegatePImpl::nodeCount; + using MultiDelegatePImpl::recycle_node_unsafe; public: - using MultiDelegatePImpl::MultiDelegatePImpl; + using MultiDelegatePImpl::MultiDelegatePImpl; void operator()() { @@ -336,7 +336,7 @@ namespace detail do { done = current == stop; - if (!Call::execute(current->mDelegate)) + if (!Call::execute(current->mDelegate)) { // remove callback from stack esp8266::InterruptLock lockAllInterruptsInThisScope; @@ -373,28 +373,28 @@ namespace detail } }; - template< typename Delegate, typename R, uint32_t MULTICALLBACK_MAX_COUNT, typename... P> class MultiDelegate; + template< typename Delegate, typename R, bool ISQUEUE, uint32_t MULTICALLBACK_MAX_COUNT, typename... P> class MultiDelegate; - template< typename Delegate, typename R, uint32_t MULTICALLBACK_MAX_COUNT, typename... P> - class MultiDelegate : public MultiDelegatePImpl + template< typename Delegate, typename R, bool ISQUEUE, uint32_t MULTICALLBACK_MAX_COUNT, typename... P> + class MultiDelegate : public MultiDelegatePImpl { public: - using MultiDelegatePImpl::MultiDelegatePImpl; + using MultiDelegatePImpl::MultiDelegatePImpl; }; - template< typename Delegate, typename R, uint32_t MULTICALLBACK_MAX_COUNT> - class MultiDelegate : public MultiDelegateImpl + template< typename Delegate, typename R, bool ISQUEUE, uint32_t MULTICALLBACK_MAX_COUNT> + class MultiDelegate : public MultiDelegateImpl { public: - using MultiDelegateImpl::MultiDelegateImpl; + using MultiDelegateImpl::MultiDelegateImpl; }; }; -template< typename Delegate, uint32_t MULTICALLBACK_MAX_COUNT = 32> -class MultiDelegate : public detail::MultiDelegate +template< typename Delegate, bool ISQUEUE = false, uint32_t MULTICALLBACK_MAX_COUNT = 32> +class MultiDelegate : public detail::MultiDelegate { public: - using detail::MultiDelegate::MultiDelegatePImpl; + using detail::MultiDelegate::MultiDelegatePImpl; }; #endif // __MULTIDELEGATE_H From 79c3816ecf93c41615842fc24f909f96b1342d7b Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Sun, 8 Dec 2019 10:15:07 +0100 Subject: [PATCH 10/55] Fix deletion of argument value caused by forwarding to Delegate. --- cores/esp8266/MultiDelegate.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cores/esp8266/MultiDelegate.h b/cores/esp8266/MultiDelegate.h index 1400303219..3880d28f32 100644 --- a/cores/esp8266/MultiDelegate.h +++ b/cores/esp8266/MultiDelegate.h @@ -261,7 +261,7 @@ namespace detail do { done = current == stop; - if (!CallP::execute(current->mDelegate, std::forward(args...))) + if (!CallP::execute(current->mDelegate, args...)) { // remove callback from stack esp8266::InterruptLock lockAllInterruptsInThisScope; From edbeeabb21f37b2214d19b16aeb3450ddb4fc1a9 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Sun, 8 Dec 2019 12:00:18 +0100 Subject: [PATCH 11/55] Readied MultiDelegate for ESP32 ISR safeness. --- cores/esp8266/MultiDelegate.h | 60 +++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/cores/esp8266/MultiDelegate.h b/cores/esp8266/MultiDelegate.h index 3880d28f32..eb84e85f68 100644 --- a/cores/esp8266/MultiDelegate.h +++ b/cores/esp8266/MultiDelegate.h @@ -1,7 +1,21 @@ #ifndef __MULTIDELEGATE_H #define __MULTIDELEGATE_H +#include +#ifdef ESP8266 #include +using esp8266::InterruptLock; +#else +class InterruptLock { +public: + InterruptLock() { + noInterrupts(); + } + ~InterruptLock() { + interrupts(); + } +}; +#endif namespace detail { @@ -177,7 +191,7 @@ namespace detail if (!del) return nullptr; - esp8266::InterruptLock lockAllInterruptsInThisScope; + InterruptLock lockAllInterruptsInThisScope; Node_t* item = get_node_unsafe(); if (!item) @@ -207,7 +221,7 @@ namespace detail if (del == ¤t->mDelegate) { // remove callback from stack - esp8266::InterruptLock lockAllInterruptsInThisScope; + InterruptLock lockAllInterruptsInThisScope; auto to_recycle = current; @@ -243,15 +257,14 @@ namespace detail if (!current) return; - static bool fence = false; - { - esp8266::InterruptLock lockAllInterruptsInThisScope; - - // prevent recursive calls - if (fence) - return; - fence = true; - } + static std::atomic fence(false); + // prevent recursive calls +#ifdef ESP8266 + if (fence.load()) return; + fence.store(true); +#else + if (fence.exchange(true)) return; +#endif Node_t* prev = nullptr; // prevent execution of new callbacks during this run @@ -264,7 +277,7 @@ namespace detail if (!CallP::execute(current->mDelegate, args...)) { // remove callback from stack - esp8266::InterruptLock lockAllInterruptsInThisScope; + InterruptLock lockAllInterruptsInThisScope; auto to_recycle = current; @@ -294,7 +307,7 @@ namespace detail optimistic_yield(10000); } while (current && !done); - fence = false; + fence.store(false); } }; @@ -318,15 +331,14 @@ namespace detail if (!current) return; - static bool fence = false; - { - esp8266::InterruptLock lockAllInterruptsInThisScope; - - // prevent recursive calls - if (fence) - return; - fence = true; - } + static std::atomic fence(false); + // prevent recursive calls +#ifdef ESP8266 + if (fence.load()) return; + fence.store(true); +#else + if (fence.exchange(true)) return; +#endif Node_t* prev = nullptr; // prevent execution of new callbacks during this run @@ -339,7 +351,7 @@ namespace detail if (!Call::execute(current->mDelegate)) { // remove callback from stack - esp8266::InterruptLock lockAllInterruptsInThisScope; + InterruptLock lockAllInterruptsInThisScope; auto to_recycle = current; @@ -369,7 +381,7 @@ namespace detail optimistic_yield(10000); } while (current && !done); - fence = false; + fence.store(false); } }; From cda54ff14aba4182c8983621a29ed21e5aa33572 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Mon, 9 Dec 2019 14:32:56 +0100 Subject: [PATCH 12/55] Completed port of Delegate and MultiDelegate to Non-Arduino platforms --- cores/esp8266/Delegate.h | 506 ++++++++++++++++++++++++++++++++++ cores/esp8266/MultiDelegate.h | 47 +++- 2 files changed, 548 insertions(+), 5 deletions(-) diff --git a/cores/esp8266/Delegate.h b/cores/esp8266/Delegate.h index a9d47e357e..8731b6fbf9 100644 --- a/cores/esp8266/Delegate.h +++ b/cores/esp8266/Delegate.h @@ -29,12 +29,17 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define IRAM_ATTR #endif +#if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) #include #include +#else +#include "circular_queue/ghostl.h" +#endif namespace detail { +#if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) template class DelegatePImpl { public: @@ -239,14 +244,267 @@ namespace detail }; }; }; +#else + template + class DelegatePImpl { + public: + using target_type = R(P...); + using FunPtr = R(*)(A, P...); + using FunctionType = R(*)(P...); + + DelegatePImpl() + { + fn = nullptr; + obj = {}; + } + + DelegatePImpl(std::nullptr_t) + { + fn = nullptr; + obj = {}; + } + + DelegatePImpl(const DelegatePImpl& del) + { + kind = del.kind; + if (FUNC == del.kind) + { + functional = del.functional; + } + else + { + fn = del.fn; + obj = del.obj; + } + } + + DelegatePImpl(DelegatePImpl&& del) + { + kind = del.kind; + if (FUNC == del.kind) + { + functional = std::move(del.functional); + } + else + { + fn = del.fn; + obj = std::move(del.obj); + } + } + + DelegatePImpl(FunPtr fn, const A& obj) + { + kind = FP; + DelegatePImpl::fn = fn; + this->obj = obj; + } + + DelegatePImpl(FunPtr fn, A&& obj) + { + kind = FP; + DelegatePImpl::fn = fn; + this->obj = std::move(obj); + } + + template DelegatePImpl(const F& functional) + { + kind = FUNC; + this->functional = functional; + } + + template DelegatePImpl(F&& functional) + { + kind = FUNC; + this->functional = std::move(functional); + } + + DelegatePImpl& operator=(const DelegatePImpl& del) + { + if (this == &del) return *this; + if (FUNC != kind && FUNC == del.kind) + { + obj = {}; + } + kind = del.kind; + if (FUNC == del.kind) + { + functional = del.functional; + } + else + { + fn = del.fn; + obj = del.obj; + } + return *this; + } + DelegatePImpl& operator=(DelegatePImpl&& del) + { + if (this == &del) return *this; + if (FUNC != kind && FUNC == del.kind) + { + obj = {}; + } + kind = del.kind; + if (FUNC == del.kind) + { + functional = std::move(del.functional); + } + else + { + fn = del.fn; + obj = std::move(del.obj); + } + return *this; + } + + template DelegatePImpl& operator=(const F& functional) + { + if (FUNC != kind) + { + obj = {}; + kind = FUNC; + } + this->functional = functional; + return *this; + } + + template DelegatePImpl& operator=(F&& functional) + { + if (FUNC != kind) + { + obj = {}; + kind = FUNC; + } + this->functional = std::move(functional); + return *this; + } + + DelegatePImpl& IRAM_ATTR operator=(std::nullptr_t) + { + kind = FP; + fn = nullptr; + obj = {}; + return *this; + } + + operator bool() const + { + if (FUNC == kind) + { + return functional ? true : false; + } + else + { + return fn; + } + } + + R IRAM_ATTR operator()(P... args) const + { + if (FUNC == kind) + { + return functional(std::forward(args...)); + } + else + { + return fn(obj, std::forward(args...)); + } + } + + protected: + enum { FUNC, FP } kind = FP; + union { + FunctionType functional; + FunPtr fn; + }; + A obj; + }; +#endif + +#if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) template class DelegatePImpl : public std::function { public: using std::function::function; using std::function::operator=; }; +#else + template + class DelegatePImpl { + public: + using target_type = R(P...); + using FunPtr = R(*)(P...); + + DelegatePImpl() + { + fn = nullptr; + } + + DelegatePImpl(std::nullptr_t) + { + fn = nullptr; + } + + DelegatePImpl(const DelegatePImpl& del) + { + fn = del.fn; + } + + DelegatePImpl(DelegatePImpl&& del) + { + fn = std::move(del.fn); + } + + DelegatePImpl(FunPtr fn) + { + DelegatePImpl::fn = fn; + } + + DelegatePImpl& operator=(const DelegatePImpl& del) + { + if (this == &del) return *this; + fn = del.fn; + return *this; + } + + DelegatePImpl& operator=(DelegatePImpl&& del) + { + if (this == &del) return *this; + fn = std::move(del.fn); + return *this; + } + + DelegatePImpl& operator=(FunPtr fn) + { + DelegatePImpl::fn = fn; + return *this; + } + + DelegatePImpl& IRAM_ATTR operator=(std::nullptr_t) + { + fn = nullptr; + return *this; + } + + operator bool() const + { + return fn; + } + + R IRAM_ATTR operator()(P... args) const + { + return fn(std::forward(args...)); + } + + protected: + FunPtr fn; + }; +#endif + + +#if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) template class DelegateImpl { public: @@ -451,7 +709,185 @@ namespace detail }; }; }; +#else + template + class DelegateImpl { + public: + using target_type = R(); + using FunPtr = R(*)(A); + using FunctionType = R(*)(); + + DelegateImpl() + { + fn = nullptr; + obj = {}; + } + + DelegateImpl(std::nullptr_t) + { + fn = nullptr; + obj = {}; + } + + DelegateImpl(const DelegateImpl& del) + { + kind = del.kind; + if (FUNC == del.kind) + { + functional = del.functional; + } + else + { + fn = del.fn; + obj = del.obj; + } + } + + DelegateImpl(DelegateImpl&& del) + { + kind = del.kind; + if (FUNC == del.kind) + { + functional = std::move(del.functional); + } + else + { + fn = del.fn; + obj = std::move(del.obj); + } + } + + DelegateImpl(FunPtr fn, const A& obj) + { + kind = FP; + DelegateImpl::fn = fn; + this->obj = obj; + } + + DelegateImpl(FunPtr fn, A&& obj) + { + kind = FP; + DelegateImpl::fn = fn; + this->obj = std::move(obj); + } + + template DelegateImpl(const F& functional) + { + kind = FUNC; + this->functional = functional; + } + + template DelegateImpl(F&& functional) + { + kind = FUNC; + this->functional = std::move(functional); + } + + DelegateImpl& operator=(const DelegateImpl& del) + { + if (this == &del) return *this; + if (FUNC != kind && FUNC == del.kind) + { + obj = {}; + } + kind = del.kind; + if (FUNC == del.kind) + { + functional = del.functional; + } + else + { + fn = del.fn; + obj = del.obj; + } + return *this; + } + DelegateImpl& operator=(DelegateImpl&& del) + { + if (this == &del) return *this; + if (FUNC != kind && FUNC == del.kind) + { + obj = {}; + } + kind = del.kind; + if (FUNC == del.kind) + { + functional = std::move(del.functional); + } + else + { + fn = del.fn; + obj = std::move(del.obj); + } + return *this; + } + + template DelegateImpl& operator=(const F& functional) + { + if (FUNC != kind) + { + obj = {}; + kind = FUNC; + } + this->functional = functional; + return *this; + } + + template DelegateImpl& operator=(F&& functional) + { + if (FUNC != kind) + { + obj = {}; + kind = FUNC; + } + this->functional = std::move(functional); + return *this; + } + + DelegateImpl& IRAM_ATTR operator=(std::nullptr_t) + { + kind = FP; + fn = nullptr; + obj = {}; + return *this; + } + + operator bool() const + { + if (FUNC == kind) + { + return functional ? true : false; + } + else + { + return fn; + } + } + + R IRAM_ATTR operator()() const + { + if (FUNC == kind) + { + return functional(); + } + else + { + return fn(obj); + } + } + + protected: + enum { FUNC, FP } kind = FP; + union { + FunctionType functional; + FunPtr fn; + }; + A obj; + }; +#endif + +#if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) template class DelegateImpl { public: @@ -560,6 +996,17 @@ namespace detail return *this; } + DelegateImpl& operator=(FunPtr fn) + { + if (FUNC == kind) + { + functional.~FunctionType(); + } + kind = FP; + DelegateImpl::fn = fn; + return *this; + } + template DelegateImpl& operator=(const F& functional) { if (FUNC != kind) @@ -624,6 +1071,65 @@ namespace detail FunPtr fn; }; }; +#else + template + class DelegateImpl { + public: + using target_type = R(); + using FunPtr = R(*)(); + + DelegateImpl() + { + fn = nullptr; + } + + DelegateImpl(std::nullptr_t) + { + fn = nullptr; + } + + DelegateImpl(const DelegateImpl& del) + { + fn = del.fn; + } + + DelegateImpl(FunPtr fn) + { + DelegateImpl::fn = fn; + } + + DelegateImpl& operator=(const DelegateImpl& del) + { + fn = del.fn; + return *this; + } + + DelegateImpl& operator=(FunPtr fn) + { + DelegateImpl::fn = fn; + return *this; + } + + DelegateImpl& IRAM_ATTR operator=(std::nullptr_t) + { + fn = nullptr; + return *this; + } + + operator bool() const + { + return fn; + } + + R IRAM_ATTR operator()() const + { + return fn(); + } + + protected: + FunPtr fn; + }; +#endif template class Delegate : public detail::DelegatePImpl diff --git a/cores/esp8266/MultiDelegate.h b/cores/esp8266/MultiDelegate.h index eb84e85f68..853b24334b 100644 --- a/cores/esp8266/MultiDelegate.h +++ b/cores/esp8266/MultiDelegate.h @@ -1,11 +1,16 @@ #ifndef __MULTIDELEGATE_H #define __MULTIDELEGATE_H +#if defined(ESP8266) || defined(ESP32) || !defined(ARDUINO) #include -#ifdef ESP8266 +#else +#include "circular_queue/ghostl.h" +#endif + +#if defined(ESP8266) #include using esp8266::InterruptLock; -#else +#elif defined(ARDUINO) class InterruptLock { public: InterruptLock() { @@ -15,6 +20,8 @@ class InterruptLock { interrupts(); } }; +#else +#include #endif namespace detail @@ -166,7 +173,11 @@ namespace detail // if no unused items, and count not too high, allocate a new one else if (nodeCount < MULTICALLBACK_MAX_COUNT) { +#if defined(ESP8266) || defined(ESP32) result = new (std::nothrow) Node_t; +#else + result = new Node_t; +#endif if (result) ++nodeCount; } @@ -180,6 +191,9 @@ namespace detail unused = node; } +#ifndef ARDUINO + std::mutex mutex_unused; +#endif public: const Delegate* IRAM_ATTR add(const Delegate& del) { @@ -191,7 +205,11 @@ namespace detail if (!del) return nullptr; +#ifdef ARDUINO InterruptLock lockAllInterruptsInThisScope; +#else + std::lock_guard lock(mutex_unused); +#endif Node_t* item = get_node_unsafe(); if (!item) @@ -221,7 +239,11 @@ namespace detail if (del == ¤t->mDelegate) { // remove callback from stack +#ifdef ARDUINO InterruptLock lockAllInterruptsInThisScope; +#else + std::lock_guard lock(mutex_unused); +#endif auto to_recycle = current; @@ -259,7 +281,7 @@ namespace detail static std::atomic fence(false); // prevent recursive calls -#ifdef ESP8266 +#if defined(ARDUINO) && !defined(ESP32) if (fence.load()) return; fence.store(true); #else @@ -277,7 +299,11 @@ namespace detail if (!CallP::execute(current->mDelegate, args...)) { // remove callback from stack +#ifdef ARDUINO InterruptLock lockAllInterruptsInThisScope; +#else + std::lock_guard lock(mutex_unused); +#endif auto to_recycle = current; @@ -303,8 +329,10 @@ namespace detail current = current->mNext; } +#if defined(ESP8266) || defined(ESP32) // running callbacks might last too long for watchdog etc. optimistic_yield(10000); +#endif } while (current && !done); fence.store(false); @@ -321,6 +349,9 @@ namespace detail using MultiDelegatePImpl::unused; using MultiDelegatePImpl::nodeCount; using MultiDelegatePImpl::recycle_node_unsafe; +#ifndef ARDUINO + using MultiDelegatePImpl::mutex_unused; +#endif public: using MultiDelegatePImpl::MultiDelegatePImpl; @@ -333,7 +364,7 @@ namespace detail static std::atomic fence(false); // prevent recursive calls -#ifdef ESP8266 +#if defined(ARDUINO) && !defined(ESP32) if (fence.load()) return; fence.store(true); #else @@ -351,7 +382,11 @@ namespace detail if (!Call::execute(current->mDelegate)) { // remove callback from stack +#ifdef ARDUINO InterruptLock lockAllInterruptsInThisScope; +#else + std::lock_guard lock(mutex_unused); +#endif auto to_recycle = current; @@ -377,8 +412,10 @@ namespace detail current = current->mNext; } +#if defined(ESP8266) || defined(ESP32) // running callbacks might last too long for watchdog etc. optimistic_yield(10000); +#endif } while (current && !done); fence.store(false); @@ -406,7 +443,7 @@ template< typename Delegate, bool ISQUEUE = false, uint32_t MULTICALLBACK_MAX_CO class MultiDelegate : public detail::MultiDelegate { public: - using detail::MultiDelegate::MultiDelegatePImpl; + using detail::MultiDelegate::MultiDelegate; }; #endif // __MULTIDELEGATE_H From c6fb8bc3aed87a1e0a88e499230725da498829e9 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Mon, 9 Dec 2019 22:41:29 +0100 Subject: [PATCH 13/55] Add missing LGPL license header. --- cores/esp8266/MultiDelegate.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/cores/esp8266/MultiDelegate.h b/cores/esp8266/MultiDelegate.h index 853b24334b..218ddb2048 100644 --- a/cores/esp8266/MultiDelegate.h +++ b/cores/esp8266/MultiDelegate.h @@ -1,3 +1,23 @@ +/* +MultiDelegate.h - A queue or event multiplexer based on the efficient Delegate +class +Copyright (c) 2019 Dirk O. Kaar. All rights reserved. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + #ifndef __MULTIDELEGATE_H #define __MULTIDELEGATE_H From da5f0d4c81c7f5f599980666762cfb4452f0ecba Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Tue, 10 Dec 2019 14:01:15 +0100 Subject: [PATCH 14/55] Directly derive from std::function for DelegateImpl, too. --- cores/esp8266/Delegate.h | 192 +++------------------------------------ 1 file changed, 15 insertions(+), 177 deletions(-) diff --git a/cores/esp8266/Delegate.h b/cores/esp8266/Delegate.h index 8731b6fbf9..495492f4c7 100644 --- a/cores/esp8266/Delegate.h +++ b/cores/esp8266/Delegate.h @@ -426,6 +426,7 @@ namespace detail template class DelegatePImpl : public std::function { public: + using target_type = R(P...); using std::function::function; using std::function::operator=; }; @@ -888,219 +889,56 @@ namespace detail #endif #if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) + template + class DelegateImpl : public std::function { + public: + using target_type = R(); + using std::function::function; + using std::function::operator=; + }; +#else template class DelegateImpl { public: using target_type = R(); using FunPtr = R(*)(); - using FunctionType = std::function; DelegateImpl() { fn = nullptr; } - ~DelegateImpl() + DelegateImpl(std::nullptr_t) { - if (FUNC == kind) - functional.~FunctionType(); + fn = nullptr; } DelegateImpl(const DelegateImpl& del) { - kind = del.kind; - if (FUNC == del.kind) - { - new (&functional) FunctionType(del.functional); - } - else - { - fn = del.fn; - } + fn = del.fn; } DelegateImpl(DelegateImpl&& del) { - kind = del.kind; - if (FUNC == del.kind) - { - new (&functional) FunctionType(std::move(del.functional)); - } - else - { - fn = del.fn; - } + fn = std::move(del.fn); } DelegateImpl(FunPtr fn) { - kind = FP; DelegateImpl::fn = fn; } - template DelegateImpl(const F& functional) - { - kind = FUNC; - new (&this->functional) FunctionType(functional); - } - - template DelegateImpl(F&& functional) - { - kind = FUNC; - new (&this->functional) FunctionType(std::move(functional)); - } - DelegateImpl& operator=(const DelegateImpl& del) { if (this == &del) return *this; - if (FUNC == kind && FUNC != del.kind) - { - functional.~FunctionType(); - } - else if (FUNC != kind && FUNC == del.kind) - { - new (&this->functional) FunctionType(); - } - kind = del.kind; - if (FUNC == del.kind) - { - functional = del.functional; - } - else - { - fn = del.fn; - } + fn = del.fn; return *this; } DelegateImpl& operator=(DelegateImpl&& del) { if (this == &del) return *this; - if (FUNC == kind && FUNC != del.kind) - { - functional.~FunctionType(); - } - else if (FUNC != kind && FUNC == del.kind) - { - new (&this->functional) FunctionType(); - } - kind = del.kind; - if (FUNC == del.kind) - { - functional = std::move(del.functional); - } - else - { - fn = del.fn; - } - return *this; - } - - DelegateImpl& operator=(FunPtr fn) - { - if (FUNC == kind) - { - functional.~FunctionType(); - } - kind = FP; - DelegateImpl::fn = fn; - return *this; - } - - template DelegateImpl& operator=(const F& functional) - { - if (FUNC != kind) - { - new (&this->functional) FunctionType(); - kind = FUNC; - } - this->functional = functional; - return *this; - } - - template DelegateImpl& operator=(F&& functional) - { - if (FUNC != kind) - { - new (&this->functional) FunctionType(); - kind = FUNC; - } - this->functional = std::move(functional); - return *this; - } - - DelegateImpl& IRAM_ATTR operator=(std::nullptr_t) - { - if (FUNC == kind) - { - functional.~FunctionType(); - } - kind = FP; - fn = nullptr; - return *this; - } - - operator bool() const - { - if (FUNC == kind) - { - return functional ? true : false; - } - else - { - return fn; - } - } - - R IRAM_ATTR operator()() const - { - if (FUNC == kind) - { - return functional(); - } - else - { - return fn(); - } - } - - protected: - enum { FUNC, FP } kind = FP; - union { - FunctionType functional; - FunPtr fn; - }; - }; -#else - template - class DelegateImpl { - public: - using target_type = R(); - using FunPtr = R(*)(); - - DelegateImpl() - { - fn = nullptr; - } - - DelegateImpl(std::nullptr_t) - { - fn = nullptr; - } - - DelegateImpl(const DelegateImpl& del) - { - fn = del.fn; - } - - DelegateImpl(FunPtr fn) - { - DelegateImpl::fn = fn; - } - - DelegateImpl& operator=(const DelegateImpl& del) - { - fn = del.fn; + fn = std::move(del.fn); return *this; } From 15bbc1c9b5c78d3edab11b0b294ee1a81c80f502 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Wed, 11 Dec 2019 13:56:52 +0100 Subject: [PATCH 15/55] Fixed queue and event multiplexer modes (ISQUEUE template argument) for performance. Added documentation to the MultiDelegate class template. --- cores/esp8266/MultiDelegate.h | 86 ++++++++++++++++++++++++----------- 1 file changed, 60 insertions(+), 26 deletions(-) diff --git a/cores/esp8266/MultiDelegate.h b/cores/esp8266/MultiDelegate.h index 218ddb2048..92a31fb91f 100644 --- a/cores/esp8266/MultiDelegate.h +++ b/cores/esp8266/MultiDelegate.h @@ -87,7 +87,7 @@ namespace detail }; }; - template< typename Delegate, typename R = void, bool ISQUEUE = false, uint32_t MULTICALLBACK_MAX_COUNT = 32, typename... P> + template< typename Delegate, typename R = void, bool ISQUEUE = false, uint32_t QUEUE_CAPACITY = 32, typename... P> class MultiDelegatePImpl { public: @@ -191,7 +191,7 @@ namespace detail unused = unused->mNext; } // if no unused items, and count not too high, allocate a new one - else if (nodeCount < MULTICALLBACK_MAX_COUNT) + else if (nodeCount < QUEUE_CAPACITY) { #if defined(ESP8266) || defined(ESP32) result = new (std::nothrow) Node_t; @@ -231,7 +231,12 @@ namespace detail std::lock_guard lock(mutex_unused); #endif - Node_t* item = get_node_unsafe(); + Node_t* item = ISQUEUE ? get_node_unsafe() : +#if defined(ESP8266) || defined(ESP32) + new (std::nothrow) Node_t; +#else + new Node_t; +#endif if (!item) return nullptr; @@ -281,7 +286,10 @@ namespace detail first = current; } - recycle_node_unsafe(to_recycle); + if (ISQUEUE) + recycle_node_unsafe(to_recycle); + else + delete to_recycle; return true; } else @@ -341,7 +349,10 @@ namespace detail first = current; } - recycle_node_unsafe(to_recycle); + if (ISQUEUE) + recycle_node_unsafe(to_recycle); + else + delete to_recycle; } else { @@ -359,22 +370,22 @@ namespace detail } }; - template< typename Delegate, typename R = void, bool ISQUEUE = false, uint32_t MULTICALLBACK_MAX_COUNT = 32> - class MultiDelegateImpl : public MultiDelegatePImpl + template< typename Delegate, typename R = void, bool ISQUEUE = false, uint32_t QUEUE_CAPACITY = 32> + class MultiDelegateImpl : public MultiDelegatePImpl { protected: - using typename MultiDelegatePImpl::Node_t; - using MultiDelegatePImpl::first; - using MultiDelegatePImpl::last; - using MultiDelegatePImpl::unused; - using MultiDelegatePImpl::nodeCount; - using MultiDelegatePImpl::recycle_node_unsafe; + using typename MultiDelegatePImpl::Node_t; + using MultiDelegatePImpl::first; + using MultiDelegatePImpl::last; + using MultiDelegatePImpl::unused; + using MultiDelegatePImpl::nodeCount; + using MultiDelegatePImpl::recycle_node_unsafe; #ifndef ARDUINO - using MultiDelegatePImpl::mutex_unused; + using MultiDelegatePImpl::mutex_unused; #endif public: - using MultiDelegatePImpl::MultiDelegatePImpl; + using MultiDelegatePImpl::MultiDelegatePImpl; void operator()() { @@ -424,7 +435,10 @@ namespace detail first = current; } - recycle_node_unsafe(to_recycle); + if (ISQUEUE) + recycle_node_unsafe(to_recycle); + else + delete to_recycle; } else { @@ -442,28 +456,48 @@ namespace detail } }; - template< typename Delegate, typename R, bool ISQUEUE, uint32_t MULTICALLBACK_MAX_COUNT, typename... P> class MultiDelegate; + template< typename Delegate, typename R, bool ISQUEUE, uint32_t QUEUE_CAPACITY, typename... P> class MultiDelegate; - template< typename Delegate, typename R, bool ISQUEUE, uint32_t MULTICALLBACK_MAX_COUNT, typename... P> - class MultiDelegate : public MultiDelegatePImpl + template< typename Delegate, typename R, bool ISQUEUE, uint32_t QUEUE_CAPACITY, typename... P> + class MultiDelegate : public MultiDelegatePImpl { public: - using MultiDelegatePImpl::MultiDelegatePImpl; + using MultiDelegatePImpl::MultiDelegatePImpl; }; - template< typename Delegate, typename R, bool ISQUEUE, uint32_t MULTICALLBACK_MAX_COUNT> - class MultiDelegate : public MultiDelegateImpl + template< typename Delegate, typename R, bool ISQUEUE, uint32_t QUEUE_CAPACITY> + class MultiDelegate : public MultiDelegateImpl { public: - using MultiDelegateImpl::MultiDelegateImpl; + using MultiDelegateImpl::MultiDelegateImpl; }; }; -template< typename Delegate, bool ISQUEUE = false, uint32_t MULTICALLBACK_MAX_COUNT = 32> -class MultiDelegate : public detail::MultiDelegate +/** +The MultiDelegate class template can be specialized to either a queue or an event multiplexer. +It is designed to be used with Delegate, the efficient runtime wrapper for C function ptr and C++ std::function. +@tparam Delegate specifies the concrete type that MultiDelegate bases the queue or event multiplexer on. +@tparam ISQUEUE modifies the generated MultiDelegate class in subtle ways. In queue mode (ISQUEUE == true), + the value of QUEUE_CAPACITY enforces the maximum number of simultaneous items the queue can contain. + This is exploited to minimize the use of new and delete by reusing already allocated items, thus + reducing heap fragmentation. In event multiplexer mode (ISQUEUE = false), new and delete are + used for allocation of the event handler items. + If the result type of the function call operator of Delegate is void, calling a MultiDelegate queue + removes each item after calling it; a Multidelegate event multiplexer keeps event handlers until + explicitly removed. + If the result type of the function call operator of Delegate is non-void, the type-conversion to bool + of that result determines if the item is immediately removed or kept after each call: a Multidelegate + queue removes an item only if true is returned, but a Multidelegate event multiplexer removes event + handlers that return false. +@tparam QUEUE_CAPACITY is only used if ISQUEUE == true. Then, it sets the maximum capacity that the queue dynamically + allocates from the heap. Unused items are not returned to the heap, but are managed by the MultiDelegate + instance during its own lifetime for efficiency. +*/ +template< typename Delegate, bool ISQUEUE = false, uint32_t QUEUE_CAPACITY = 32> +class MultiDelegate : public detail::MultiDelegate { public: - using detail::MultiDelegate::MultiDelegate; + using detail::MultiDelegate::MultiDelegate; }; #endif // __MULTIDELEGATE_H From e1c3d2232b9ec1ffe4dfac9853984410b1c6edd9 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Thu, 12 Dec 2019 20:47:12 +0100 Subject: [PATCH 16/55] Signed-unsigned mismatch caught by ESP2866 Arduino CI. --- cores/esp8266/MultiDelegate.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cores/esp8266/MultiDelegate.h b/cores/esp8266/MultiDelegate.h index 92a31fb91f..1fd4188d69 100644 --- a/cores/esp8266/MultiDelegate.h +++ b/cores/esp8266/MultiDelegate.h @@ -176,7 +176,7 @@ namespace detail Node_t* first = nullptr; Node_t* last = nullptr; Node_t* unused = nullptr; - int nodeCount = 0; + uint32_t nodeCount = 0; // Returns a pointer to an unused Node_t, // or if none are available allocates a new one, From 534d016bbc1ff8e890589462db52a6f5d7996935 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Fri, 13 Dec 2019 14:41:34 +0100 Subject: [PATCH 17/55] Performance and ease of use, more comprehensible ctor and operator=: accept C-func ptr w/o A obj argument in Delegate<..., A, P...> specializations. --- cores/esp8266/Delegate.h | 1026 ++++++++++++++++++++++++++++---------- 1 file changed, 754 insertions(+), 272 deletions(-) diff --git a/cores/esp8266/Delegate.h b/cores/esp8266/Delegate.h index 495492f4c7..881344a6cb 100644 --- a/cores/esp8266/Delegate.h +++ b/cores/esp8266/Delegate.h @@ -44,26 +44,25 @@ namespace detail class DelegatePImpl { public: using target_type = R(P...); - using FunPtr = R(*)(A, P...); + using FunPtr = R(*)(P...); + using FunAPtr = R(*)(A, P...); using FunctionType = std::function; DelegatePImpl() { fn = nullptr; - new (&obj) A; } DelegatePImpl(std::nullptr_t) { fn = nullptr; - new (&obj) A; } ~DelegatePImpl() { if (FUNC == kind) functional.~FunctionType(); - else + else if (FPA == kind) obj.~A(); } @@ -74,10 +73,14 @@ namespace detail { new (&functional) FunctionType(del.functional); } + else if (FPA == del.kind) + { + fnA = del.fnA; + new (&obj) A(del.obj); + } else { fn = del.fn; - new (&obj) A(del.obj); } } @@ -88,25 +91,35 @@ namespace detail { new (&functional) FunctionType(std::move(del.functional)); } + else if (FPA == del.kind) + { + fnA = del.fnA; + new (&obj) A(std::move(del.obj)); + } else { fn = del.fn; - new (&obj) A(std::move(del.obj)); } } - DelegatePImpl(FunPtr fn, const A& obj) + DelegatePImpl(FunAPtr fnA, const A& obj) { - kind = FP; - DelegatePImpl::fn = fn; + kind = FPA; + DelegatePImpl::fnA = fnA; new (&this->obj) A(obj); } - DelegatePImpl(FunPtr fn, A&& obj) + DelegatePImpl(FunAPtr fnA, A&& obj) + { + kind = FPA; + DelegatePImpl::fnA = fnA; + new (&this->obj) A(std::move(obj)); + } + + DelegatePImpl(FunPtr fn) { kind = FP; DelegatePImpl::fn = fn; - new (&this->obj) A(std::move(obj)); } template DelegatePImpl(const F& functional) @@ -124,25 +137,38 @@ namespace detail DelegatePImpl& operator=(const DelegatePImpl& del) { if (this == &del) return *this; - if (FUNC == kind && FUNC != del.kind) - { - functional.~FunctionType(); - new (&obj) A; - } - else if (FUNC != kind && FUNC == del.kind) - { - obj.~A(); - new (&this->functional) FunctionType(); + if (kind != del.kind) + { + if (FUNC == kind) + { + functional.~FunctionType(); + } + else if (FPA == kind) + { + obj.~A(); + } + if (FUNC == del.kind) + { + new (&this->functional) FunctionType(); + } + else if (FPA == del.kind) + { + new (&obj) A; + } + kind = del.kind; } - kind = del.kind; if (FUNC == del.kind) { functional = del.functional; } + else if (FPA == del.kind) + { + fnA = del.fnA; + obj = del.obj; + } else { fn = del.fn; - obj = del.obj; } return *this; } @@ -150,34 +176,65 @@ namespace detail DelegatePImpl& operator=(DelegatePImpl&& del) { if (this == &del) return *this; - if (FUNC == kind && FUNC != del.kind) - { - functional.~FunctionType(); - new (&obj) A; - } - else if (FUNC != kind && FUNC == del.kind) - { - obj.~A(); - new (&this->functional) FunctionType(); + if (kind != del.kind) + { + if (FUNC == kind) + { + functional.~FunctionType(); + } + else if (FPA == kind) + { + obj.~A(); + } + if (FUNC == del.kind) + { + new (&this->functional) FunctionType(); + } + else if (FPA == del.kind) + { + new (&obj) A; + } + kind = del.kind; } - kind = del.kind; if (FUNC == del.kind) { functional = std::move(del.functional); } + else if (FPA == del.kind) + { + fnA = del.fnA; + obj = std::move(del.obj); + } else { fn = del.fn; - obj = std::move(del.obj); } return *this; } + DelegatePImpl& operator=(FunPtr fn) + { + if (FUNC == kind) + { + functional.~FunctionType(); + } + else if (FPA == kind) + { + obj.~A(); + } + kind = FP; + this->fn = fn; + return *this; + } + template DelegatePImpl& operator=(const F& functional) { if (FUNC != kind) { - obj.~A(); + if (FPA == kind) + { + obj.~A(); + } new (&this->functional) FunctionType(); kind = FUNC; } @@ -189,7 +246,10 @@ namespace detail { if (FUNC != kind) { - obj.~A(); + if (FPA == kind) + { + obj.~A(); + } new (&this->functional) FunctionType(); kind = FUNC; } @@ -202,44 +262,55 @@ namespace detail if (FUNC == kind) { functional.~FunctionType(); - new (&obj) A; + } + else if (FPA == kind) + { + obj.~A(); } kind = FP; fn = nullptr; - obj = {}; return *this; } operator bool() const { - if (FUNC == kind) + if (FP == kind) { - return functional ? true : false; + return fn; + } + else if (FPA == kind) + { + return fnA; } else { - return fn; + return functional ? true : false; } } R IRAM_ATTR operator()(P... args) const { - if (FUNC == kind) + if (FP == kind) { - return functional(std::forward(args...)); + return fn(std::forward(args...)); + } + else if (FPA == kind) + { + return fnA(obj, std::forward(args...)); } else { - return fn(obj, std::forward(args...)); + return functional(std::forward(args...)); } } protected: - enum { FUNC, FP } kind = FP; + enum { FUNC, FP, FPA } kind = FP; union { FunctionType functional; + FunPtr fn; struct { - FunPtr fn; + FunAPtr fnA; A obj; }; }; @@ -249,91 +320,86 @@ namespace detail class DelegatePImpl { public: using target_type = R(P...); - using FunPtr = R(*)(A, P...); - using FunctionType = R(*)(P...); + using FunPtr = R(*)(P...); + using FunAPtr = R(*)(A, P...); DelegatePImpl() { fn = nullptr; - obj = {}; } DelegatePImpl(std::nullptr_t) { fn = nullptr; - obj = {}; } DelegatePImpl(const DelegatePImpl& del) { kind = del.kind; - if (FUNC == del.kind) + if (FPA == del.kind) { - functional = del.functional; + fnA = del.fnA; + obj = del.obj; } else { fn = del.fn; - obj = del.obj; } } DelegatePImpl(DelegatePImpl&& del) { kind = del.kind; - if (FUNC == del.kind) + if (FPA == del.kind) { - functional = std::move(del.functional); + fnA = del.fnA; + obj = std::move(del.obj); } else { fn = del.fn; - obj = std::move(del.obj); } } - DelegatePImpl(FunPtr fn, const A& obj) + DelegatePImpl(FunAPtr fnA, const A& obj) { - kind = FP; - DelegatePImpl::fn = fn; + kind = FPA; + DelegatePImpl::fnA = fnA; this->obj = obj; } - DelegatePImpl(FunPtr fn, A&& obj) + DelegatePImpl(FunAPtr fnA, A&& obj) { - kind = FP; - DelegatePImpl::fn = fn; + kind = FPA; + DelegatePImpl::fnA = fnA; this->obj = std::move(obj); } - template DelegatePImpl(const F& functional) - { - kind = FUNC; - this->functional = functional; - } - - template DelegatePImpl(F&& functional) + DelegatePImpl(FunPtr fn) { - kind = FUNC; - this->functional = std::move(functional); + kind = FP; + DelegatePImpl::fn = fn; } DelegatePImpl& operator=(const DelegatePImpl& del) { if (this == &del) return *this; - if (FUNC != kind && FUNC == del.kind) + if (kind != del.kind) { - obj = {}; + if (FPA == kind) + { + obj = {}; + } + kind = del.kind; } - kind = del.kind; - if (FUNC == del.kind) + if (FPA == del.kind) { - functional = del.functional; + fnA = del.fnA; + obj = del.obj; } else { fn = del.fn; - obj = del.obj; } return *this; } @@ -341,101 +407,89 @@ namespace detail DelegatePImpl& operator=(DelegatePImpl&& del) { if (this == &del) return *this; - if (FUNC != kind && FUNC == del.kind) + if (kind != del.kind) { - obj = {}; + if (FPA == kind) + { + obj = {}; + } + kind = del.kind; } - kind = del.kind; - if (FUNC == del.kind) + if (FPA == del.kind) { - functional = std::move(del.functional); + fnA = del.fnA; + obj = std::move(del.obj); } else { fn = del.fn; - obj = std::move(del.obj); } return *this; } - template DelegatePImpl& operator=(const F& functional) + DelegatePImpl& operator=(FunPtr fn) { - if (FUNC != kind) + if (FPA == kind) { obj = {}; - kind = FUNC; } - this->functional = functional; + kind = FP; + this->fn = fn; return *this; } - template DelegatePImpl& operator=(F&& functional) + DelegatePImpl& IRAM_ATTR operator=(std::nullptr_t) { - if (FUNC != kind) + if (FPA == kind) { obj = {}; - kind = FUNC; } - this->functional = std::move(functional); - return *this; - } - - DelegatePImpl& IRAM_ATTR operator=(std::nullptr_t) - { kind = FP; fn = nullptr; - obj = {}; return *this; } operator bool() const { - if (FUNC == kind) + if (FP == kind) { - return functional ? true : false; + return fn; } else { - return fn; + return fnA; } } R IRAM_ATTR operator()(P... args) const { - if (FUNC == kind) + if (FP == kind) { - return functional(std::forward(args...)); + return fn(std::forward(args...)); } else { - return fn(obj, std::forward(args...)); + return fnA(obj, std::forward(args...)); } } protected: - enum { FUNC, FP } kind = FP; + enum { FP, FPA } kind = FP; union { - FunctionType functional; FunPtr fn; + FunAPtr fnA; }; A obj; }; #endif #if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) - template - class DelegatePImpl : public std::function { - public: - using target_type = R(P...); - using std::function::function; - using std::function::operator=; - }; -#else template class DelegatePImpl { public: using target_type = R(P...); using FunPtr = R(*)(P...); + using FunctionType = std::function; DelegatePImpl() { @@ -447,93 +501,13 @@ namespace detail fn = nullptr; } - DelegatePImpl(const DelegatePImpl& del) - { - fn = del.fn; - } - - DelegatePImpl(DelegatePImpl&& del) - { - fn = std::move(del.fn); - } - - DelegatePImpl(FunPtr fn) - { - DelegatePImpl::fn = fn; - } - - DelegatePImpl& operator=(const DelegatePImpl& del) - { - if (this == &del) return *this; - fn = del.fn; - return *this; - } - - DelegatePImpl& operator=(DelegatePImpl&& del) - { - if (this == &del) return *this; - fn = std::move(del.fn); - return *this; - } - - DelegatePImpl& operator=(FunPtr fn) - { - DelegatePImpl::fn = fn; - return *this; - } - - DelegatePImpl& IRAM_ATTR operator=(std::nullptr_t) - { - fn = nullptr; - return *this; - } - - operator bool() const - { - return fn; - } - - R IRAM_ATTR operator()(P... args) const - { - return fn(std::forward(args...)); - } - - protected: - FunPtr fn; - }; -#endif - - - -#if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) - template - class DelegateImpl { - public: - using target_type = R(); - using FunPtr = R(*)(A); - using FunctionType = std::function; - - DelegateImpl() - { - fn = nullptr; - new (&obj) A; - } - - DelegateImpl(std::nullptr_t) - { - fn = nullptr; - new (&obj) A; - } - - ~DelegateImpl() + ~DelegatePImpl() { if (FUNC == kind) functional.~FunctionType(); - else - obj.~A(); } - DelegateImpl(const DelegateImpl& del) + DelegatePImpl(const DelegatePImpl& del) { kind = del.kind; if (FUNC == del.kind) @@ -543,11 +517,10 @@ namespace detail else { fn = del.fn; - new (&obj) A(del.obj); } } - DelegateImpl(DelegateImpl&& del) + DelegatePImpl(DelegatePImpl&& del) { kind = del.kind; if (FUNC == del.kind) @@ -557,47 +530,36 @@ namespace detail else { fn = del.fn; - new (&obj) A(std::move(del.obj)); } } - DelegateImpl(FunPtr fn, const A& obj) - { - kind = FP; - DelegateImpl::fn = fn; - new (&this->obj) A(obj); - } - - DelegateImpl(FunPtr fn, A&& obj) + DelegatePImpl(FunPtr fn) { kind = FP; - DelegateImpl::fn = fn; - new (&this->obj) A(std::move(obj)); + DelegatePImpl::fn = fn; } - template DelegateImpl(const F& functional) + template DelegatePImpl(const F& functional) { kind = FUNC; new (&this->functional) FunctionType(functional); } - template DelegateImpl(F&& functional) + template DelegatePImpl(F&& functional) { kind = FUNC; new (&this->functional) FunctionType(std::move(functional)); } - DelegateImpl& operator=(const DelegateImpl& del) + DelegatePImpl& operator=(const DelegatePImpl& del) { if (this == &del) return *this; if (FUNC == kind && FUNC != del.kind) { functional.~FunctionType(); - new (&obj) A; } else if (FUNC != kind && FUNC == del.kind) { - obj.~A(); new (&this->functional) FunctionType(); } kind = del.kind; @@ -608,22 +570,19 @@ namespace detail else { fn = del.fn; - obj = del.obj; } return *this; } - DelegateImpl& operator=(DelegateImpl&& del) + DelegatePImpl& operator=(DelegatePImpl&& del) { if (this == &del) return *this; if (FUNC == kind && FUNC != del.kind) { functional.~FunctionType(); - new (&obj) A; } else if (FUNC != kind && FUNC == del.kind) { - obj.~A(); new (&this->functional) FunctionType(); } kind = del.kind; @@ -634,16 +593,14 @@ namespace detail else { fn = del.fn; - obj = std::move(del.obj); } return *this; } - template DelegateImpl& operator=(const F& functional) + template DelegatePImpl& operator=(const F& functional) { if (FUNC != kind) { - obj.~A(); new (&this->functional) FunctionType(); kind = FUNC; } @@ -651,11 +608,10 @@ namespace detail return *this; } - template DelegateImpl& operator=(F&& functional) + template DelegatePImpl& operator=(F&& functional) { if (FUNC != kind) { - obj.~A(); new (&this->functional) FunctionType(); kind = FUNC; } @@ -663,49 +619,404 @@ namespace detail return *this; } - DelegateImpl& IRAM_ATTR operator=(std::nullptr_t) + DelegatePImpl& operator=(FunPtr fn) + { + if (FUNC == kind) + { + functional.~FunctionType(); + kind = FP; + } + DelegatePImpl::fn = fn; + return *this; + } + + DelegatePImpl& IRAM_ATTR operator=(std::nullptr_t) { if (FUNC == kind) { functional.~FunctionType(); - new (&obj) A; } kind = FP; fn = nullptr; - obj = {}; return *this; } operator bool() const { - if (FUNC == kind) + if (FP == kind) + { + return fn; + } + else { return functional ? true : false; } + } + + R IRAM_ATTR operator()(P... args) const + { + if (FP == kind) + { + return fn(std::forward(args...)); + } + else + { + return functional(std::forward(args...)); + } + } + + protected: + enum { FUNC, FP } kind = FP; + union { + FunctionType functional; + FunPtr fn; + }; + }; +#else + template + class DelegatePImpl { + public: + using target_type = R(P...); + using FunPtr = R(*)(P...); + + DelegatePImpl() + { + fn = nullptr; + } + + DelegatePImpl(std::nullptr_t) + { + fn = nullptr; + } + + DelegatePImpl(const DelegatePImpl& del) + { + fn = del.fn; + } + + DelegatePImpl(DelegatePImpl&& del) + { + fn = std::move(del.fn); + } + + DelegatePImpl(FunPtr fn) + { + DelegatePImpl::fn = fn; + } + + DelegatePImpl& operator=(const DelegatePImpl& del) + { + if (this == &del) return *this; + fn = del.fn; + return *this; + } + + DelegatePImpl& operator=(DelegatePImpl&& del) + { + if (this == &del) return *this; + fn = std::move(del.fn); + return *this; + } + + DelegatePImpl& operator=(FunPtr fn) + { + DelegatePImpl::fn = fn; + return *this; + } + + DelegatePImpl& IRAM_ATTR operator=(std::nullptr_t) + { + fn = nullptr; + return *this; + } + + operator bool() const + { + return fn; + } + + R IRAM_ATTR operator()(P... args) const + { + return fn(std::forward(args...)); + } + + protected: + FunPtr fn; + }; +#endif + +#if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) + template + class DelegateImpl { + public: + using target_type = R(); + using FunPtr = R(*)(); + using FunAPtr = R(*)(A); + using FunctionType = std::function; + + DelegateImpl() + { + fn = nullptr; + } + + DelegateImpl(std::nullptr_t) + { + fn = nullptr; + } + + ~DelegateImpl() + { + if (FUNC == kind) + functional.~FunctionType(); + else if (FPA == kind) + obj.~A(); + } + + DelegateImpl(const DelegateImpl& del) + { + kind = del.kind; + if (FUNC == del.kind) + { + new (&functional) FunctionType(del.functional); + } + else if (FPA == del.kind) + { + fnA = del.fnA; + new (&obj) A(del.obj); + } + else + { + fn = del.fn; + } + } + + DelegateImpl(DelegateImpl&& del) + { + kind = del.kind; + if (FUNC == del.kind) + { + new (&functional) FunctionType(std::move(del.functional)); + } + else if (FPA == del.kind) + { + fnA = del.fnA; + new (&obj) A(std::move(del.obj)); + } else + { + fn = del.fn; + } + } + + DelegateImpl(FunAPtr fnA, const A& obj) + { + kind = FPA; + DelegateImpl::fnA = fnA; + new (&this->obj) A(obj); + } + + DelegateImpl(FunAPtr fnA, A&& obj) + { + kind = FPA; + DelegateImpl::fnA = fnA; + new (&this->obj) A(std::move(obj)); + } + + DelegateImpl(FunPtr fn) + { + kind = FP; + DelegateImpl::fn = fn; + } + + template DelegateImpl(const F& functional) + { + kind = FUNC; + new (&this->functional) FunctionType(functional); + } + + template DelegateImpl(F&& functional) + { + kind = FUNC; + new (&this->functional) FunctionType(std::move(functional)); + } + + DelegateImpl& operator=(const DelegateImpl& del) + { + if (this == &del) return *this; + if (kind != del.kind) + { + if (FUNC == kind) + { + functional.~FunctionType(); + } + else if (FPA == kind) + { + obj.~A(); + } + if (FUNC == del.kind) + { + new (&this->functional) FunctionType(); + } + else if (FPA == del.kind) + { + new (&obj) A; + } + kind = del.kind; + } + if (FUNC == del.kind) + { + functional = del.functional; + } + else if (FPA == del.kind) + { + fnA = del.fnA; + obj = del.obj; + } + else + { + fn = del.fn; + } + return *this; + } + + DelegateImpl& operator=(DelegateImpl&& del) + { + if (this == &del) return *this; + if (kind != del.kind) + { + if (FUNC == kind) + { + functional.~FunctionType(); + } + else if (FPA == kind) + { + obj.~A(); + } + if (FUNC == del.kind) + { + new (&this->functional) FunctionType(); + } + else if (FPA == del.kind) + { + new (&obj) A; + } + kind = del.kind; + } + if (FUNC == del.kind) + { + functional = std::move(del.functional); + } + else if (FPA == del.kind) + { + fnA = del.fnA; + obj = std::move(del.obj); + } + else + { + fn = del.fn; + } + return *this; + } + + DelegateImpl& operator=(FunPtr fn) + { + if (FUNC == kind) + { + functional.~FunctionType(); + } + else if (FPA == kind) + { + obj.~A(); + } + kind = FP; + this->fn = fn; + return *this; + } + + template DelegateImpl& operator=(const F& functional) + { + if (FUNC != kind) + { + if (FPA == kind) + { + obj.~A(); + } + new (&this->functional) FunctionType(); + kind = FUNC; + } + this->functional = functional; + return *this; + } + + template DelegateImpl& operator=(F&& functional) + { + if (FUNC != kind) + { + if (FPA == kind) + { + obj.~A(); + } + new (&this->functional) FunctionType(); + kind = FUNC; + } + this->functional = std::move(functional); + return *this; + } + + DelegateImpl& IRAM_ATTR operator=(std::nullptr_t) + { + if (FUNC == kind) + { + functional.~FunctionType(); + } + else if (FPA == kind) + { + obj.~A(); + } + kind = FP; + fn = nullptr; + return *this; + } + + operator bool() const + { + if (FP == kind) { return fn; } + else if (FPA == kind) + { + return fnA; + } + else + { + return functional ? true : false; + } } R IRAM_ATTR operator()() const { - if (FUNC == kind) + if (FP == kind) { - return functional(); + return fn(); + } + else if (FPA == kind) + { + return fnA(obj); } else { - return fn(obj); + return functional(); } } protected: - enum { FUNC, FP } kind = FP; + enum { FUNC, FP, FPA } kind = FP; union { FunctionType functional; + FunPtr fn; struct { - FunPtr fn; + FunAPtr fnA; A obj; }; }; @@ -715,81 +1026,247 @@ namespace detail class DelegateImpl { public: using target_type = R(); - using FunPtr = R(*)(A); - using FunctionType = R(*)(); + using FunPtr = R(*)(); + using FunAPtr = R(*)(A); DelegateImpl() { fn = nullptr; - obj = {}; } DelegateImpl(std::nullptr_t) { fn = nullptr; - obj = {}; } DelegateImpl(const DelegateImpl& del) { kind = del.kind; - if (FUNC == del.kind) + if (FPA == del.kind) { - functional = del.functional; + fnA = del.fnA; + obj = del.obj; } else { fn = del.fn; - obj = del.obj; } } DelegateImpl(DelegateImpl&& del) { kind = del.kind; - if (FUNC == del.kind) + if (FPA == del.kind) { - functional = std::move(del.functional); + fnA = del.fnA; + obj = std::move(del.obj); } else { fn = del.fn; - obj = std::move(del.obj); } } - DelegateImpl(FunPtr fn, const A& obj) + DelegateImpl(FunAPtr fnA, const A& obj) + { + kind = FPA; + DelegateImpl::fnA = fnA; + this->obj = obj; + } + + DelegateImpl(FunAPtr fnA, A&& obj) + { + kind = FPA; + DelegateImpl::fnA = fnA; + this->obj = std::move(obj); + } + + DelegateImpl(FunPtr fn) { kind = FP; DelegateImpl::fn = fn; - this->obj = obj; } - DelegateImpl(FunPtr fn, A&& obj) + DelegateImpl& operator=(const DelegateImpl& del) + { + if (this == &del) return *this; + if (kind != del.kind) + { + if (FPA == kind) + { + obj = {}; + } + kind = del.kind; + } + if (FPA == del.kind) + { + fnA = del.fnA; + obj = del.obj; + } + else + { + fn = del.fn; + } + return *this; + } + + DelegateImpl& operator=(DelegateImpl&& del) + { + if (this == &del) return *this; + if (kind != del.kind) + { + if (FPA == kind) + { + obj = {}; + } + kind = del.kind; + } + if (FPA == del.kind) + { + fnA = del.fnA; + obj = std::move(del.obj); + } + else + { + fn = del.fn; + } + return *this; + } + + DelegateImpl& operator=(FunPtr fn) + { + if (FPA == kind) + { + obj = {}; + } + kind = FP; + this->fn = fn; + return *this; + } + + DelegateImpl& IRAM_ATTR operator=(std::nullptr_t) + { + if (FPA == kind) + { + obj = {}; + } + kind = FP; + fn = nullptr; + return *this; + } + + operator bool() const + { + if (FP == kind) + { + return fn; + } + else + { + return fnA; + } + } + + R IRAM_ATTR operator()() const + { + if (FP == kind) + { + return fn(); + } + else + { + return fnA(obj); + } + } + + protected: + enum { FP, FPA } kind = FP; + union { + FunPtr fn; + FunAPtr fnA; + }; + A obj; + }; +#endif + +#if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) + template + class DelegateImpl { + public: + using target_type = R(); + using FunPtr = R(*)(); + using FunctionType = std::function; + + DelegateImpl() + { + fn = nullptr; + } + + DelegateImpl(std::nullptr_t) + { + fn = nullptr; + } + + ~DelegateImpl() + { + if (FUNC == kind) + functional.~FunctionType(); + } + + DelegateImpl(const DelegateImpl& del) + { + kind = del.kind; + if (FUNC == del.kind) + { + new (&functional) FunctionType(del.functional); + } + else + { + fn = del.fn; + } + } + + DelegateImpl(DelegateImpl&& del) + { + kind = del.kind; + if (FUNC == del.kind) + { + new (&functional) FunctionType(std::move(del.functional)); + } + else + { + fn = del.fn; + } + } + + DelegateImpl(FunPtr fn) { kind = FP; DelegateImpl::fn = fn; - this->obj = std::move(obj); } template DelegateImpl(const F& functional) { kind = FUNC; - this->functional = functional; + new (&this->functional) FunctionType(functional); } template DelegateImpl(F&& functional) { kind = FUNC; - this->functional = std::move(functional); + new (&this->functional) FunctionType(std::move(functional)); } DelegateImpl& operator=(const DelegateImpl& del) { if (this == &del) return *this; - if (FUNC != kind && FUNC == del.kind) + if (FUNC == kind && FUNC != del.kind) { - obj = {}; + functional.~FunctionType(); + } + else if (FUNC != kind && FUNC == del.kind) + { + new (&this->functional) FunctionType(); } kind = del.kind; if (FUNC == del.kind) @@ -799,7 +1276,6 @@ namespace detail else { fn = del.fn; - obj = del.obj; } return *this; } @@ -807,9 +1283,13 @@ namespace detail DelegateImpl& operator=(DelegateImpl&& del) { if (this == &del) return *this; - if (FUNC != kind && FUNC == del.kind) + if (FUNC == kind && FUNC != del.kind) { - obj = {}; + functional.~FunctionType(); + } + else if (FUNC != kind && FUNC == del.kind) + { + new (&this->functional) FunctionType(); } kind = del.kind; if (FUNC == del.kind) @@ -819,7 +1299,6 @@ namespace detail else { fn = del.fn; - obj = std::move(del.obj); } return *this; } @@ -828,7 +1307,7 @@ namespace detail { if (FUNC != kind) { - obj = {}; + new (&this->functional) FunctionType(); kind = FUNC; } this->functional = functional; @@ -839,42 +1318,56 @@ namespace detail { if (FUNC != kind) { - obj = {}; + new (&this->functional) FunctionType(); kind = FUNC; } this->functional = std::move(functional); return *this; } + DelegateImpl& operator=(FunPtr fn) + { + if (FUNC == kind) + { + functional.~FunctionType(); + kind = FP; + } + DelegateImpl::fn = fn; + return *this; + } + DelegateImpl& IRAM_ATTR operator=(std::nullptr_t) { + if (FUNC == kind) + { + functional.~FunctionType(); + } kind = FP; fn = nullptr; - obj = {}; return *this; } operator bool() const { - if (FUNC == kind) + if (FP == kind) { - return functional ? true : false; + return fn; } else { - return fn; + return functional ? true : false; } } R IRAM_ATTR operator()() const { - if (FUNC == kind) + if (FP == kind) { - return functional(); + return fn(); } else { - return fn(obj); + return functional(); } } @@ -884,17 +1377,6 @@ namespace detail FunctionType functional; FunPtr fn; }; - A obj; - }; -#endif - -#if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) - template - class DelegateImpl : public std::function { - public: - using target_type = R(); - using std::function::function; - using std::function::operator=; }; #else template From ee86f2ed05c2ef1e5c539dd69cde712b18cedf56 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Sat, 14 Dec 2019 11:35:10 +0100 Subject: [PATCH 18/55] Interface full lockdown: mark implementation details private instead of protected. --- cores/esp8266/Delegate.h | 60 ++++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/cores/esp8266/Delegate.h b/cores/esp8266/Delegate.h index 881344a6cb..0066a474e0 100644 --- a/cores/esp8266/Delegate.h +++ b/cores/esp8266/Delegate.h @@ -44,10 +44,11 @@ namespace detail class DelegatePImpl { public: using target_type = R(P...); - using FunPtr = R(*)(P...); + private: + using FunPtr = target_type*; using FunAPtr = R(*)(A, P...); using FunctionType = std::function; - + public: DelegatePImpl() { fn = nullptr; @@ -304,7 +305,7 @@ namespace detail } } - protected: + private: enum { FUNC, FP, FPA } kind = FP; union { FunctionType functional; @@ -320,9 +321,10 @@ namespace detail class DelegatePImpl { public: using target_type = R(P...); - using FunPtr = R(*)(P...); + private: + using FunPtr = target_type*; using FunAPtr = R(*)(A, P...); - + public: DelegatePImpl() { fn = nullptr; @@ -473,7 +475,7 @@ namespace detail } } - protected: + private: enum { FP, FPA } kind = FP; union { FunPtr fn; @@ -488,9 +490,10 @@ namespace detail class DelegatePImpl { public: using target_type = R(P...); - using FunPtr = R(*)(P...); + private: + using FunPtr = target_type*; using FunctionType = std::function; - + public: DelegatePImpl() { fn = nullptr; @@ -665,7 +668,7 @@ namespace detail } } - protected: + private: enum { FUNC, FP } kind = FP; union { FunctionType functional; @@ -677,8 +680,9 @@ namespace detail class DelegatePImpl { public: using target_type = R(P...); - using FunPtr = R(*)(P...); - + private: + using FunPtr = target_type*; + public: DelegatePImpl() { fn = nullptr; @@ -740,7 +744,7 @@ namespace detail return fn(std::forward(args...)); } - protected: + private: FunPtr fn; }; #endif @@ -750,10 +754,11 @@ namespace detail class DelegateImpl { public: using target_type = R(); - using FunPtr = R(*)(); + private: + using FunPtr = target_type*; using FunAPtr = R(*)(A); using FunctionType = std::function; - + public: DelegateImpl() { fn = nullptr; @@ -1010,7 +1015,7 @@ namespace detail } } - protected: + private: enum { FUNC, FP, FPA } kind = FP; union { FunctionType functional; @@ -1026,9 +1031,10 @@ namespace detail class DelegateImpl { public: using target_type = R(); - using FunPtr = R(*)(); + private: + using FunPtr = target_type*; using FunAPtr = R(*)(A); - + public: DelegateImpl() { fn = nullptr; @@ -1179,7 +1185,7 @@ namespace detail } } - protected: + private: enum { FP, FPA } kind = FP; union { FunPtr fn; @@ -1194,9 +1200,10 @@ namespace detail class DelegateImpl { public: using target_type = R(); - using FunPtr = R(*)(); + private: + using FunPtr = target_type*; using FunctionType = std::function; - + public: DelegateImpl() { fn = nullptr; @@ -1371,7 +1378,7 @@ namespace detail } } - protected: + private: enum { FUNC, FP } kind = FP; union { FunctionType functional; @@ -1383,8 +1390,9 @@ namespace detail class DelegateImpl { public: using target_type = R(); - using FunPtr = R(*)(); - + private: + using FunPtr = target_type*; + public: DelegateImpl() { fn = nullptr; @@ -1446,7 +1454,7 @@ namespace detail return fn(); } - protected: + private: FunPtr fn; }; #endif @@ -1454,12 +1462,14 @@ namespace detail template class Delegate : public detail::DelegatePImpl { + public: using detail::DelegatePImpl::DelegatePImpl; }; template class Delegate : public detail::DelegateImpl { + public: using detail::DelegateImpl::DelegateImpl; }; @@ -1468,10 +1478,12 @@ namespace detail template class Delegate; template class Delegate : public detail::Delegate { +public: using detail::Delegate::Delegate; }; template class Delegate : public detail::Delegate { +public: using detail::Delegate::Delegate; }; From 0db6c956d6be969b658d18c42435a47990948413 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Mon, 16 Dec 2019 00:54:28 +0100 Subject: [PATCH 19/55] For use of Delegate as callback in functions that take C-fun ptr and void* arg, added facility to type convert Delegate to R (*)(void*, P...) and function void* arg(). Wraps as needed, fast-tracks Callback constructed with matching C-fun ptr and arg. --- cores/esp8266/Delegate.h | 394 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 376 insertions(+), 18 deletions(-) diff --git a/cores/esp8266/Delegate.h b/cores/esp8266/Delegate.h index 0066a474e0..b1d325cc50 100644 --- a/cores/esp8266/Delegate.h +++ b/cores/esp8266/Delegate.h @@ -44,9 +44,10 @@ namespace detail class DelegatePImpl { public: using target_type = R(P...); - private: + protected: using FunPtr = target_type*; using FunAPtr = R(*)(A, P...); + using FunVPPtr = R(*)(void*, P...); using FunctionType = std::function; public: DelegatePImpl() @@ -289,6 +290,54 @@ namespace detail } } + operator FunVPPtr() const + { + if (FP == kind) + { + return [](void* self, P... args) -> R + { + return static_cast(self)->fn(std::forward(args...)); + }; + } + else if (FPA == kind) + { + return [](void* self, P... args) -> R + { + return static_cast(self)->fnA( + static_cast(self)->obj, + std::forward(args...)); + }; + } + else + { + return [](void* self, P... args) -> R + { + return static_cast(self)->functional(std::forward(args...)); + }; + } + } + + void* arg() const + { + return const_cast(this); + } + + operator FunctionType() const + { + if (FP == kind) + { + return fn; + } + else if (FPA == kind) + { + return std::bind(fnA, obj); + } + else + { + return functional; + } + } + R IRAM_ATTR operator()(P... args) const { if (FP == kind) @@ -305,7 +354,7 @@ namespace detail } } - private: + protected: enum { FUNC, FP, FPA } kind = FP; union { FunctionType functional; @@ -321,9 +370,10 @@ namespace detail class DelegatePImpl { public: using target_type = R(P...); - private: + protected: using FunPtr = target_type*; using FunAPtr = R(*)(A, P...); + using FunVPPtr = R(*)(void*, P...); public: DelegatePImpl() { @@ -463,6 +513,31 @@ namespace detail } } + operator FunVPPtr() const + { + if (FP == kind) + { + return [](void* self, P... args) -> R + { + return static_cast(self)->fn(std::forward(args...)); + }; + } + else + { + return [](void* self, P... args) -> R + { + return static_cast(self)->fnA( + static_cast(self)->obj, + std::forward(args...)); + }; + } + } + + void* arg() const + { + return const_cast(this); + } + R IRAM_ATTR operator()(P... args) const { if (FP == kind) @@ -475,7 +550,7 @@ namespace detail } } - private: + protected: enum { FP, FPA } kind = FP; union { FunPtr fn; @@ -490,9 +565,10 @@ namespace detail class DelegatePImpl { public: using target_type = R(P...); - private: + protected: using FunPtr = target_type*; using FunctionType = std::function; + using FunVPPtr = R(*)(void*, P...); public: DelegatePImpl() { @@ -656,6 +732,41 @@ namespace detail } } + operator FunVPPtr() const + { + if (FP == kind) + { + return [](void* self, P... args) -> R + { + return static_cast(self)->fn(std::forward(args...)); + }; + } + else + { + return [](void* self, P... args) -> R + { + return static_cast(self)->functional(std::forward(args...)); + }; + } + } + + void* arg() const + { + return const_cast(this); + } + + operator FunctionType() const + { + if (FP == kind) + { + return fn; + } + else + { + return functional; + } + } + R IRAM_ATTR operator()(P... args) const { if (FP == kind) @@ -668,7 +779,7 @@ namespace detail } } - private: + protected: enum { FUNC, FP } kind = FP; union { FunctionType functional; @@ -680,8 +791,9 @@ namespace detail class DelegatePImpl { public: using target_type = R(P...); - private: + protected: using FunPtr = target_type*; + using FunVPPtr = R(*)(void*, P...); public: DelegatePImpl() { @@ -739,12 +851,25 @@ namespace detail return fn; } + operator FunVPPtr() const + { + return [](void* self, P... args) -> R + { + return static_cast(self)->fn(std::forward(args...)); + }; + } + + void* arg() const + { + return const_cast(this); + } + R IRAM_ATTR operator()(P... args) const { return fn(std::forward(args...)); } - private: + protected: FunPtr fn; }; #endif @@ -754,10 +879,11 @@ namespace detail class DelegateImpl { public: using target_type = R(); - private: + protected: using FunPtr = target_type*; using FunAPtr = R(*)(A); using FunctionType = std::function; + using FunVPPtr = R(*)(void*); public: DelegateImpl() { @@ -999,6 +1125,53 @@ namespace detail } } + operator FunVPPtr() const + { + if (FP == kind) + { + return [](void* self) -> R + { + return static_cast(self)->fn(); + }; + } + else if (FPA == kind) + { + return [](void* self) -> R + { + return static_cast(self)->fnA( + static_cast(self)->obj); + }; + } + else + { + return [](void* self) -> R + { + return static_cast(self)->functional(); + }; + } + } + + void* arg() const + { + return const_cast(this); + } + + operator FunctionType() const + { + if (FP == kind) + { + return fn; + } + else if (FPA == kind) + { + return std::bind(fnA, obj); + } + else + { + return functional; + } + } + R IRAM_ATTR operator()() const { if (FP == kind) @@ -1015,7 +1188,7 @@ namespace detail } } - private: + protected: enum { FUNC, FP, FPA } kind = FP; union { FunctionType functional; @@ -1031,9 +1204,10 @@ namespace detail class DelegateImpl { public: using target_type = R(); - private: + protected: using FunPtr = target_type*; using FunAPtr = R(*)(A); + using FunVPPtr = R(*)(void*); public: DelegateImpl() { @@ -1173,6 +1347,30 @@ namespace detail } } + operator FunVPPtr() const + { + if (FP == kind) + { + return [](void* self) -> R + { + return static_cast(self)->fn(); + }; + } + else + { + return [](void* self) -> R + { + return static_cast(self)->fnA( + static_cast(self)->obj); + }; + } + } + + void* arg() const + { + return const_cast(this); + } + R IRAM_ATTR operator()() const { if (FP == kind) @@ -1185,7 +1383,7 @@ namespace detail } } - private: + protected: enum { FP, FPA } kind = FP; union { FunPtr fn; @@ -1200,9 +1398,10 @@ namespace detail class DelegateImpl { public: using target_type = R(); - private: + protected: using FunPtr = target_type*; using FunctionType = std::function; + using FunVPPtr = R(*)(void*); public: DelegateImpl() { @@ -1366,6 +1565,41 @@ namespace detail } } + operator FunVPPtr() const + { + if (FP == kind) + { + return [](void* self) -> R + { + return static_cast(self)->fn(); + }; + } + else + { + return [](void* self) -> R + { + return static_cast(self)->functional(); + }; + } + } + + void* arg() const + { + return const_cast(this); + } + + operator FunctionType() const + { + if (FP == kind) + { + return fn; + } + else + { + return functional; + } + } + R IRAM_ATTR operator()() const { if (FP == kind) @@ -1378,7 +1612,7 @@ namespace detail } } - private: + protected: enum { FUNC, FP } kind = FP; union { FunctionType functional; @@ -1390,8 +1624,9 @@ namespace detail class DelegateImpl { public: using target_type = R(); - private: + protected: using FunPtr = target_type*; + using FunVPPtr = R(*)(void*); public: DelegateImpl() { @@ -1449,28 +1684,151 @@ namespace detail return fn; } + operator FunVPPtr() const + { + return [](void* self) -> R + { + return static_cast(self)->fn(); + }; + } + + void* arg() const + { + return const_cast(this); + } + R IRAM_ATTR operator()() const { return fn(); } - private: + protected: FunPtr fn; }; #endif template - class Delegate : public detail::DelegatePImpl + class Delegate : private detail::DelegatePImpl { + private: + using typename detail::DelegatePImpl::FunVPPtr; +#if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) + using typename detail::DelegatePImpl::FunctionType; +#endif public: + using detail::DelegatePImpl::target_type; using detail::DelegatePImpl::DelegatePImpl; + using detail::DelegatePImpl::operator=; + using detail::DelegatePImpl::operator bool; + using detail::DelegatePImpl::operator FunVPPtr; + using detail::DelegatePImpl::arg; +#if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) + using detail::DelegatePImpl::operator FunctionType; +#endif + using detail::DelegatePImpl::operator(); + }; + + template + class Delegate : private detail::DelegatePImpl + { + private: + using typename detail::DelegatePImpl::FunVPPtr; +#if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) + using typename detail::DelegatePImpl::FunctionType; +#endif + public: + using detail::DelegatePImpl::target_type; + using detail::DelegatePImpl::DelegatePImpl; + using detail::DelegatePImpl::operator=; + using detail::DelegatePImpl::operator bool; +#if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) + using detail::DelegatePImpl::operator FunctionType; +#endif + using detail::DelegatePImpl::operator(); + operator FunVPPtr() const + { + if (detail::DelegatePImpl::FPA == detail::DelegatePImpl::kind) + { + return reinterpret_cast(detail::DelegatePImpl::fnA); + } + else + { + return detail::DelegatePImpl::operator FunVPPtr(); + } + } + void* arg() const + { + if (detail::DelegatePImpl::FPA == detail::DelegatePImpl::kind) + { + return detail::DelegatePImpl::obj; + } + else + { + return detail::DelegatePImpl::arg(); + } + } }; template - class Delegate : public detail::DelegateImpl + class Delegate : private detail::DelegateImpl { + private: + using typename detail::DelegateImpl::FunVPPtr; +#if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) + using typename detail::DelegateImpl::FunctionType; +#endif public: + using detail::DelegateImpl::target_type; using detail::DelegateImpl::DelegateImpl; + using detail::DelegateImpl::operator=; + using detail::DelegateImpl::operator bool; + using detail::DelegateImpl::operator FunVPPtr; + using detail::DelegateImpl::arg; +#if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) + using detail::DelegateImpl::operator FunctionType; +#endif + using detail::DelegateImpl::operator(); + }; + + template + class Delegate : private detail::DelegateImpl + { + private: + using typename detail::DelegateImpl::FunVPPtr; +#if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) + using typename detail::DelegateImpl::FunctionType; +#endif + public: + using detail::DelegateImpl::target_type; + using detail::DelegateImpl::DelegateImpl; + using detail::DelegateImpl::operator=; + using detail::DelegateImpl::operator bool; +#if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) + using detail::DelegateImpl::operator FunctionType; +#endif + using detail::DelegateImpl::operator(); + operator FunVPPtr() const + { + if (detail::DelegateImpl::FPA == detail::DelegateImpl::kind) + { + return reinterpret_cast(detail::DelegateImpl::fnA); + } + else + { + return detail::DelegateImpl::operator FunVPPtr(); + } + } + void* arg() const + { + if (detail::DelegateImpl::FPA == detail::DelegateImpl::kind) + { + return detail::DelegateImpl::obj; + } + else + { + return detail::DelegateImpl::arg(); + } + } }; } From c5d738ca742f6f4b317b086fdbe81c1abb6d4ee2 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Mon, 16 Dec 2019 09:17:11 +0100 Subject: [PATCH 20/55] Optimize casting to fun ptr and argument for "attachInterruptArg"-like APIs. --- cores/esp8266/Delegate.h | 156 +++++++++++++++++++++++---------------- 1 file changed, 94 insertions(+), 62 deletions(-) diff --git a/cores/esp8266/Delegate.h b/cores/esp8266/Delegate.h index b1d325cc50..75714a34ac 100644 --- a/cores/esp8266/Delegate.h +++ b/cores/esp8266/Delegate.h @@ -38,6 +38,12 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA namespace detail { + template + static R vPtrToFunPtrExec(void* fn, P... args) + { + using target_type = R(P...); + return reinterpret_cast(fn)(std::forward(args...)); + } #if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) template @@ -290,23 +296,22 @@ namespace detail } } + static R vPtrToFunAPtrExec(void* self, P... args) + { + return static_cast(self)->fnA( + static_cast(self)->obj, + std::forward(args...)); + }; + operator FunVPPtr() const { if (FP == kind) { - return [](void* self, P... args) -> R - { - return static_cast(self)->fn(std::forward(args...)); - }; + return vPtrToFunPtrExec; } else if (FPA == kind) { - return [](void* self, P... args) -> R - { - return static_cast(self)->fnA( - static_cast(self)->obj, - std::forward(args...)); - }; + return vPtrToFunAPtrExec; } else { @@ -319,7 +324,14 @@ namespace detail void* arg() const { - return const_cast(this); + if (FP == kind) + { + return reinterpret_cast(fn); + } + else + { + return const_cast(this); + } } operator FunctionType() const @@ -513,29 +525,35 @@ namespace detail } } + static R vPtrToFunAPtrExec(void* self, P... args) + { + return static_cast(self)->fnA( + static_cast(self)->obj, + std::forward(args...)); + }; + operator FunVPPtr() const { if (FP == kind) { - return [](void* self, P... args) -> R - { - return static_cast(self)->fn(std::forward(args...)); - }; + return vPtrToFunPtrExec; } else { - return [](void* self, P... args) -> R - { - return static_cast(self)->fnA( - static_cast(self)->obj, - std::forward(args...)); - }; + return vPtrToFunAPtrExec; } } void* arg() const { - return const_cast(this); + if (FP == kind) + { + return reinterpret_cast(fn); + } + else + { + return const_cast(this); + } } R IRAM_ATTR operator()(P... args) const @@ -736,10 +754,7 @@ namespace detail { if (FP == kind) { - return [](void* self, P... args) -> R - { - return static_cast(self)->fn(std::forward(args...)); - }; + return vPtrToFunPtrExec; } else { @@ -752,7 +767,14 @@ namespace detail void* arg() const { - return const_cast(this); + if (FP == kind) + { + return reinterpret_cast(fn); + } + else + { + return const_cast(this); + } } operator FunctionType() const @@ -853,15 +875,12 @@ namespace detail operator FunVPPtr() const { - return [](void* self, P... args) -> R - { - return static_cast(self)->fn(std::forward(args...)); - }; + return vPtrToFunPtrExec; } void* arg() const { - return const_cast(this); + return reinterpret_cast(fn); } R IRAM_ATTR operator()(P... args) const @@ -1125,22 +1144,21 @@ namespace detail } } + static R vPtrToFunAPtrExec(void* self) + { + return static_cast(self)->fnA( + static_cast(self)->obj); + }; + operator FunVPPtr() const { if (FP == kind) { - return [](void* self) -> R - { - return static_cast(self)->fn(); - }; + return fn; } else if (FPA == kind) { - return [](void* self) -> R - { - return static_cast(self)->fnA( - static_cast(self)->obj); - }; + return vPtrToFunAPtrExec; } else { @@ -1153,7 +1171,14 @@ namespace detail void* arg() const { - return const_cast(this); + if (FP == kind) + { + return nullptr; + } + else + { + return const_cast(this); + } } operator FunctionType() const @@ -1347,28 +1372,34 @@ namespace detail } } + static R vPtrToFunAPtrExec(void* self) + { + return static_cast(self)->fnA( + static_cast(self)->obj); + }; + operator FunVPPtr() const { if (FP == kind) { - return [](void* self) -> R - { - return static_cast(self)->fn(); - }; + return fn; } else { - return [](void* self) -> R - { - return static_cast(self)->fnA( - static_cast(self)->obj); - }; + return vPtrToFunAPtrExec; } } void* arg() const { - return const_cast(this); + if (FP == kind) + { + return nullptr; + } + else + { + return const_cast(this); + } } R IRAM_ATTR operator()() const @@ -1569,10 +1600,7 @@ namespace detail { if (FP == kind) { - return [](void* self) -> R - { - return static_cast(self)->fn(); - }; + return fn; } else { @@ -1585,7 +1613,14 @@ namespace detail void* arg() const { - return const_cast(this); + if (FP == kind) + { + return nullptr; + } + else + { + return const_cast(this); + } } operator FunctionType() const @@ -1686,15 +1721,12 @@ namespace detail operator FunVPPtr() const { - return [](void* self) -> R - { - return static_cast(self)->fn(); - }; + return fn; } void* arg() const { - return const_cast(this); + return nullptr; } R IRAM_ATTR operator()() const From 18f497e223b44692922469ea23b44d97d2ecc740 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Mon, 16 Dec 2019 18:51:54 +0100 Subject: [PATCH 21/55] Bug fix: must reinterpret_cast for R() as R(void*) cast (extra argument is harmless in C calling convention). --- cores/esp8266/Delegate.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cores/esp8266/Delegate.h b/cores/esp8266/Delegate.h index 75714a34ac..e07f8e997a 100644 --- a/cores/esp8266/Delegate.h +++ b/cores/esp8266/Delegate.h @@ -1154,7 +1154,7 @@ namespace detail { if (FP == kind) { - return fn; + return reinterpret_cast(fn); } else if (FPA == kind) { @@ -1382,7 +1382,7 @@ namespace detail { if (FP == kind) { - return fn; + return reinterpret_cast(fn); } else { @@ -1600,7 +1600,7 @@ namespace detail { if (FP == kind) { - return fn; + return reinterpret_cast(fn); } else { @@ -1721,7 +1721,7 @@ namespace detail operator FunVPPtr() const { - return fn; + return reinterpret_cast(fn); } void* arg() const From e6e60e72415d4ab88e56ba741bbf5847d6d016cb Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Tue, 17 Dec 2019 14:35:18 +0100 Subject: [PATCH 22/55] using operator= is required to suppress auto generation. --- cores/esp8266/Delegate.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cores/esp8266/Delegate.h b/cores/esp8266/Delegate.h index e07f8e997a..99ca801f0c 100644 --- a/cores/esp8266/Delegate.h +++ b/cores/esp8266/Delegate.h @@ -1870,11 +1870,13 @@ template class Delegate : pub { public: using detail::Delegate::Delegate; + using detail::Delegate::operator=; }; template class Delegate : public detail::Delegate { public: using detail::Delegate::Delegate; + using detail::Delegate::operator=; }; #endif // __Delegate_h From d855cbd3489f39757249c3e66840022608700c9a Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Tue, 17 Dec 2019 16:45:06 +0100 Subject: [PATCH 23/55] Delegate to fptr helpers must be in IRAM --- cores/esp8266/Delegate.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cores/esp8266/Delegate.h b/cores/esp8266/Delegate.h index 99ca801f0c..39ce735a45 100644 --- a/cores/esp8266/Delegate.h +++ b/cores/esp8266/Delegate.h @@ -39,7 +39,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA namespace detail { template - static R vPtrToFunPtrExec(void* fn, P... args) + static R IRAM_ATTR vPtrToFunPtrExec(void* fn, P... args) { using target_type = R(P...); return reinterpret_cast(fn)(std::forward(args...)); @@ -296,7 +296,7 @@ namespace detail } } - static R vPtrToFunAPtrExec(void* self, P... args) + static R IRAM_ATTR vPtrToFunAPtrExec(void* self, P... args) { return static_cast(self)->fnA( static_cast(self)->obj, @@ -525,7 +525,7 @@ namespace detail } } - static R vPtrToFunAPtrExec(void* self, P... args) + static R IRAM_ATTR vPtrToFunAPtrExec(void* self, P... args) { return static_cast(self)->fnA( static_cast(self)->obj, @@ -1144,7 +1144,7 @@ namespace detail } } - static R vPtrToFunAPtrExec(void* self) + static R IRAM_ATTR vPtrToFunAPtrExec(void* self) { return static_cast(self)->fnA( static_cast(self)->obj); @@ -1372,7 +1372,7 @@ namespace detail } } - static R vPtrToFunAPtrExec(void* self) + static R IRAM_ATTR vPtrToFunAPtrExec(void* self) { return static_cast(self)->fnA( static_cast(self)->obj); From 6b3e87bec2f14328923e073c2782f921a292bb59 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Fri, 20 Dec 2019 21:35:48 +0100 Subject: [PATCH 24/55] Delegate refactoring for same ordering of member functions between specializations. Portability fix for Non-ESP Arduino. --- cores/esp8266/Delegate.h | 100 ++++++++++++++++++++++++++++++--------- 1 file changed, 78 insertions(+), 22 deletions(-) diff --git a/cores/esp8266/Delegate.h b/cores/esp8266/Delegate.h index 39ce735a45..cf3868d2cf 100644 --- a/cores/esp8266/Delegate.h +++ b/cores/esp8266/Delegate.h @@ -445,6 +445,12 @@ namespace detail DelegatePImpl::fn = fn; } + template DelegatePImpl(const F& fn) + { + kind = FP; + DelegatePImpl::fn = fn; + } + DelegatePImpl& operator=(const DelegatePImpl& del) { if (this == &del) return *this; @@ -502,6 +508,17 @@ namespace detail return *this; } + template DelegatePImpl& operator=(const F& fn) + { + if (FPA == kind) + { + obj = {}; + } + kind = FP; + this->fn = fn; + return *this; + } + DelegatePImpl& IRAM_ATTR operator=(std::nullptr_t) { if (FPA == kind) @@ -694,6 +711,17 @@ namespace detail return *this; } + DelegatePImpl& operator=(FunPtr fn) + { + if (FUNC == kind) + { + functional.~FunctionType(); + kind = FP; + } + DelegatePImpl::fn = fn; + return *this; + } + template DelegatePImpl& operator=(const F& functional) { if (FUNC != kind) @@ -716,17 +744,6 @@ namespace detail return *this; } - DelegatePImpl& operator=(FunPtr fn) - { - if (FUNC == kind) - { - functional.~FunctionType(); - kind = FP; - } - DelegatePImpl::fn = fn; - return *this; - } - DelegatePImpl& IRAM_ATTR operator=(std::nullptr_t) { if (FUNC == kind) @@ -842,6 +859,11 @@ namespace detail DelegatePImpl::fn = fn; } + template DelegatePImpl(const F& fn) + { + DelegatePImpl::fn = fn; + } + DelegatePImpl& operator=(const DelegatePImpl& del) { if (this == &del) return *this; @@ -862,6 +884,12 @@ namespace detail return *this; } + template DelegatePImpl& operator=(const F& fn) + { + DelegatePImpl::fn = fn; + return *this; + } + DelegatePImpl& IRAM_ATTR operator=(std::nullptr_t) { fn = nullptr; @@ -1292,6 +1320,12 @@ namespace detail DelegateImpl::fn = fn; } + template DelegateImpl(const F& fn) + { + kind = FP; + DelegateImpl::fn = fn; + } + DelegateImpl& operator=(const DelegateImpl& del) { if (this == &del) return *this; @@ -1349,6 +1383,17 @@ namespace detail return *this; } + template DelegateImpl& operator=(const F& fn) + { + if (FPA == kind) + { + obj = {}; + } + kind = FP; + this->fn = fn; + return *this; + } + DelegateImpl& IRAM_ATTR operator=(std::nullptr_t) { if (FPA == kind) @@ -1540,6 +1585,17 @@ namespace detail return *this; } + DelegateImpl& operator=(FunPtr fn) + { + if (FUNC == kind) + { + functional.~FunctionType(); + kind = FP; + } + DelegateImpl::fn = fn; + return *this; + } + template DelegateImpl& operator=(const F& functional) { if (FUNC != kind) @@ -1562,17 +1618,6 @@ namespace detail return *this; } - DelegateImpl& operator=(FunPtr fn) - { - if (FUNC == kind) - { - functional.~FunctionType(); - kind = FP; - } - DelegateImpl::fn = fn; - return *this; - } - DelegateImpl& IRAM_ATTR operator=(std::nullptr_t) { if (FUNC == kind) @@ -1688,6 +1733,11 @@ namespace detail DelegateImpl::fn = fn; } + template DelegateImpl(const F& fn) + { + DelegateImpl::fn = fn; + } + DelegateImpl& operator=(const DelegateImpl& del) { if (this == &del) return *this; @@ -1708,6 +1758,12 @@ namespace detail return *this; } + template DelegateImpl& operator=(const F& fn) + { + DelegateImpl::fn = fn; + return *this; + } + DelegateImpl& IRAM_ATTR operator=(std::nullptr_t) { fn = nullptr; From af76e5f393f7c81594cfd1e9f6084704a465635a Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Sun, 22 Dec 2019 19:13:15 +0100 Subject: [PATCH 25/55] Bug fix Delegate, custom type converter. --- cores/esp8266/Delegate.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cores/esp8266/Delegate.h b/cores/esp8266/Delegate.h index cf3868d2cf..6693de6f3e 100644 --- a/cores/esp8266/Delegate.h +++ b/cores/esp8266/Delegate.h @@ -342,7 +342,7 @@ namespace detail } else if (FPA == kind) { - return std::bind(fnA, obj); + return [this](P... args) { return fnA(obj, std::forward(args...)); }; } else { @@ -1217,7 +1217,7 @@ namespace detail } else if (FPA == kind) { - return std::bind(fnA, obj); + return [this]() { return fnA(obj); }; } else { From 2b4a08de168c63f08334dfe7136b1cdc1716cefd Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Mon, 23 Dec 2019 14:48:10 +0100 Subject: [PATCH 26/55] Use explicit initialization in ctor for kind member. --- cores/esp8266/Delegate.h | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/cores/esp8266/Delegate.h b/cores/esp8266/Delegate.h index 6693de6f3e..3a341b515c 100644 --- a/cores/esp8266/Delegate.h +++ b/cores/esp8266/Delegate.h @@ -58,11 +58,13 @@ namespace detail public: DelegatePImpl() { + kind = FP; fn = nullptr; } DelegatePImpl(std::nullptr_t) { + kind = FP; fn = nullptr; } @@ -367,7 +369,7 @@ namespace detail } protected: - enum { FUNC, FP, FPA } kind = FP; + enum { FUNC, FP, FPA } kind; union { FunctionType functional; FunPtr fn; @@ -389,11 +391,13 @@ namespace detail public: DelegatePImpl() { + kind = FP; fn = nullptr; } DelegatePImpl(std::nullptr_t) { + kind = FP; fn = nullptr; } @@ -586,7 +590,7 @@ namespace detail } protected: - enum { FP, FPA } kind = FP; + enum { FP, FPA } kind; union { FunPtr fn; FunAPtr fnA; @@ -607,11 +611,13 @@ namespace detail public: DelegatePImpl() { + kind = FP; fn = nullptr; } DelegatePImpl(std::nullptr_t) { + kind = FP; fn = nullptr; } @@ -819,7 +825,7 @@ namespace detail } protected: - enum { FUNC, FP } kind = FP; + enum { FUNC, FP } kind; union { FunctionType functional; FunPtr fn; @@ -934,11 +940,13 @@ namespace detail public: DelegateImpl() { + kind = FP; fn = nullptr; } DelegateImpl(std::nullptr_t) { + kind = FP; fn = nullptr; } @@ -1242,7 +1250,7 @@ namespace detail } protected: - enum { FUNC, FP, FPA } kind = FP; + enum { FUNC, FP, FPA } kind; union { FunctionType functional; FunPtr fn; @@ -1264,11 +1272,13 @@ namespace detail public: DelegateImpl() { + kind = FP; fn = nullptr; } DelegateImpl(std::nullptr_t) { + kind = FP; fn = nullptr; } @@ -1460,7 +1470,7 @@ namespace detail } protected: - enum { FP, FPA } kind = FP; + enum { FP, FPA } kind; union { FunPtr fn; FunAPtr fnA; @@ -1481,11 +1491,13 @@ namespace detail public: DelegateImpl() { + kind = FP; fn = nullptr; } DelegateImpl(std::nullptr_t) { + kind = FP; fn = nullptr; } @@ -1693,7 +1705,7 @@ namespace detail } protected: - enum { FUNC, FP } kind = FP; + enum { FUNC, FP } kind; union { FunctionType functional; FunPtr fn; From c19456c0d410a4381f2f388ef6289ddf8a66113e Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Tue, 24 Dec 2019 00:35:53 +0100 Subject: [PATCH 27/55] Fix ctor overloads competing with ctor templates. --- cores/esp8266/Delegate.h | 204 ++++++++++++--------------------------- 1 file changed, 64 insertions(+), 140 deletions(-) diff --git a/cores/esp8266/Delegate.h b/cores/esp8266/Delegate.h index 3a341b515c..000202b00b 100644 --- a/cores/esp8266/Delegate.h +++ b/cores/esp8266/Delegate.h @@ -76,7 +76,7 @@ namespace detail obj.~A(); } - DelegatePImpl(const DelegatePImpl& del) + DelegatePImpl(const DelegatePImpl& del) { kind = del.kind; if (FUNC == del.kind) @@ -94,7 +94,7 @@ namespace detail } } - DelegatePImpl(DelegatePImpl&& del) + DelegatePImpl(DelegatePImpl&& del) { kind = del.kind; if (FUNC == del.kind) @@ -132,19 +132,13 @@ namespace detail DelegatePImpl::fn = fn; } - template DelegatePImpl(const F& functional) + template DelegatePImpl(F functional) { kind = FUNC; - new (&this->functional) FunctionType(functional); + new (&this->functional) FunctionType(std::forward(functional)); } - template DelegatePImpl(F&& functional) - { - kind = FUNC; - new (&this->functional) FunctionType(std::move(functional)); - } - - DelegatePImpl& operator=(const DelegatePImpl& del) + DelegatePImpl& operator=(const DelegatePImpl& del) { if (this == &del) return *this; if (kind != del.kind) @@ -183,7 +177,7 @@ namespace detail return *this; } - DelegatePImpl& operator=(DelegatePImpl&& del) + DelegatePImpl& operator=(DelegatePImpl&& del) { if (this == &del) return *this; if (kind != del.kind) @@ -237,22 +231,7 @@ namespace detail return *this; } - template DelegatePImpl& operator=(const F& functional) - { - if (FUNC != kind) - { - if (FPA == kind) - { - obj.~A(); - } - new (&this->functional) FunctionType(); - kind = FUNC; - } - this->functional = functional; - return *this; - } - - template DelegatePImpl& operator=(F&& functional) + template DelegatePImpl& operator=(F functional) { if (FUNC != kind) { @@ -263,7 +242,7 @@ namespace detail new (&this->functional) FunctionType(); kind = FUNC; } - this->functional = std::move(functional); + this->functional = std::forward(functional); return *this; } @@ -401,7 +380,7 @@ namespace detail fn = nullptr; } - DelegatePImpl(const DelegatePImpl& del) + DelegatePImpl(const DelegatePImpl& del) { kind = del.kind; if (FPA == del.kind) @@ -415,7 +394,7 @@ namespace detail } } - DelegatePImpl(DelegatePImpl&& del) + DelegatePImpl(DelegatePImpl&& del) { kind = del.kind; if (FPA == del.kind) @@ -449,13 +428,13 @@ namespace detail DelegatePImpl::fn = fn; } - template DelegatePImpl(const F& fn) + template DelegatePImpl(F fn) { kind = FP; - DelegatePImpl::fn = fn; + DelegatePImpl::fn = std::forward(fn); } - DelegatePImpl& operator=(const DelegatePImpl& del) + DelegatePImpl& operator=(const DelegatePImpl& del) { if (this == &del) return *this; if (kind != del.kind) @@ -478,7 +457,7 @@ namespace detail return *this; } - DelegatePImpl& operator=(DelegatePImpl&& del) + DelegatePImpl& operator=(DelegatePImpl&& del) { if (this == &del) return *this; if (kind != del.kind) @@ -512,14 +491,14 @@ namespace detail return *this; } - template DelegatePImpl& operator=(const F& fn) + template DelegatePImpl& operator=(F fn) { if (FPA == kind) { obj = {}; } kind = FP; - this->fn = fn; + this->fn = std::forward(fn); return *this; } @@ -627,7 +606,7 @@ namespace detail functional.~FunctionType(); } - DelegatePImpl(const DelegatePImpl& del) + DelegatePImpl(const DelegatePImpl& del) { kind = del.kind; if (FUNC == del.kind) @@ -640,7 +619,7 @@ namespace detail } } - DelegatePImpl(DelegatePImpl&& del) + DelegatePImpl(DelegatePImpl&& del) { kind = del.kind; if (FUNC == del.kind) @@ -659,19 +638,13 @@ namespace detail DelegatePImpl::fn = fn; } - template DelegatePImpl(const F& functional) + template DelegatePImpl(F functional) { kind = FUNC; - new (&this->functional) FunctionType(functional); + new (&this->functional) FunctionType(std::forward(functional)); } - template DelegatePImpl(F&& functional) - { - kind = FUNC; - new (&this->functional) FunctionType(std::move(functional)); - } - - DelegatePImpl& operator=(const DelegatePImpl& del) + DelegatePImpl& operator=(const DelegatePImpl& del) { if (this == &del) return *this; if (FUNC == kind && FUNC != del.kind) @@ -694,7 +667,7 @@ namespace detail return *this; } - DelegatePImpl& operator=(DelegatePImpl&& del) + DelegatePImpl& operator=(DelegatePImpl&& del) { if (this == &del) return *this; if (FUNC == kind && FUNC != del.kind) @@ -728,25 +701,14 @@ namespace detail return *this; } - template DelegatePImpl& operator=(const F& functional) + template DelegatePImpl& operator=(F functional) { if (FUNC != kind) { new (&this->functional) FunctionType(); kind = FUNC; } - this->functional = functional; - return *this; - } - - template DelegatePImpl& operator=(F&& functional) - { - if (FUNC != kind) - { - new (&this->functional) FunctionType(); - kind = FUNC; - } - this->functional = std::move(functional); + this->functional = std::forward(functional); return *this; } @@ -850,12 +812,12 @@ namespace detail fn = nullptr; } - DelegatePImpl(const DelegatePImpl& del) + DelegatePImpl(const DelegatePImpl& del) { fn = del.fn; } - DelegatePImpl(DelegatePImpl&& del) + DelegatePImpl(DelegatePImpl&& del) { fn = std::move(del.fn); } @@ -865,19 +827,19 @@ namespace detail DelegatePImpl::fn = fn; } - template DelegatePImpl(const F& fn) + template DelegatePImpl(F fn) { - DelegatePImpl::fn = fn; + DelegatePImpl::fn = std::forward(fn); } - DelegatePImpl& operator=(const DelegatePImpl& del) + DelegatePImpl& operator=(const DelegatePImpl& del) { if (this == &del) return *this; fn = del.fn; return *this; } - DelegatePImpl& operator=(DelegatePImpl&& del) + DelegatePImpl& operator=(DelegatePImpl&& del) { if (this == &del) return *this; fn = std::move(del.fn); @@ -890,9 +852,9 @@ namespace detail return *this; } - template DelegatePImpl& operator=(const F& fn) + template DelegatePImpl& operator=(F fn) { - DelegatePImpl::fn = fn; + DelegatePImpl::fn = std::forward(fn); return *this; } @@ -958,7 +920,7 @@ namespace detail obj.~A(); } - DelegateImpl(const DelegateImpl& del) + DelegateImpl(const DelegateImpl& del) { kind = del.kind; if (FUNC == del.kind) @@ -976,7 +938,7 @@ namespace detail } } - DelegateImpl(DelegateImpl&& del) + DelegateImpl(DelegateImpl&& del) { kind = del.kind; if (FUNC == del.kind) @@ -1014,19 +976,13 @@ namespace detail DelegateImpl::fn = fn; } - template DelegateImpl(const F& functional) + template DelegateImpl(F functional) { kind = FUNC; - new (&this->functional) FunctionType(functional); + new (&this->functional) FunctionType(std::forward(functional)); } - template DelegateImpl(F&& functional) - { - kind = FUNC; - new (&this->functional) FunctionType(std::move(functional)); - } - - DelegateImpl& operator=(const DelegateImpl& del) + DelegateImpl& operator=(const DelegateImpl& del) { if (this == &del) return *this; if (kind != del.kind) @@ -1065,7 +1021,7 @@ namespace detail return *this; } - DelegateImpl& operator=(DelegateImpl&& del) + DelegateImpl& operator=(DelegateImpl&& del) { if (this == &del) return *this; if (kind != del.kind) @@ -1119,22 +1075,7 @@ namespace detail return *this; } - template DelegateImpl& operator=(const F& functional) - { - if (FUNC != kind) - { - if (FPA == kind) - { - obj.~A(); - } - new (&this->functional) FunctionType(); - kind = FUNC; - } - this->functional = functional; - return *this; - } - - template DelegateImpl& operator=(F&& functional) + template DelegateImpl& operator=(F functional) { if (FUNC != kind) { @@ -1145,7 +1086,7 @@ namespace detail new (&this->functional) FunctionType(); kind = FUNC; } - this->functional = std::move(functional); + this->functional = std::forward(functional); return *this; } @@ -1282,7 +1223,7 @@ namespace detail fn = nullptr; } - DelegateImpl(const DelegateImpl& del) + DelegateImpl(const DelegateImpl& del) { kind = del.kind; if (FPA == del.kind) @@ -1296,7 +1237,7 @@ namespace detail } } - DelegateImpl(DelegateImpl&& del) + DelegateImpl(DelegateImpl&& del) { kind = del.kind; if (FPA == del.kind) @@ -1330,13 +1271,13 @@ namespace detail DelegateImpl::fn = fn; } - template DelegateImpl(const F& fn) + template DelegateImpl(F fn) { kind = FP; - DelegateImpl::fn = fn; + DelegateImpl::fn = std::forward(fn); } - DelegateImpl& operator=(const DelegateImpl& del) + DelegateImpl& operator=(const DelegateImpl& del) { if (this == &del) return *this; if (kind != del.kind) @@ -1359,7 +1300,7 @@ namespace detail return *this; } - DelegateImpl& operator=(DelegateImpl&& del) + DelegateImpl& operator=(DelegateImpl&& del) { if (this == &del) return *this; if (kind != del.kind) @@ -1393,14 +1334,14 @@ namespace detail return *this; } - template DelegateImpl& operator=(const F& fn) + template DelegateImpl& operator=(F fn) { if (FPA == kind) { obj = {}; } kind = FP; - this->fn = fn; + this->fn = std::forward(fn); return *this; } @@ -1507,7 +1448,7 @@ namespace detail functional.~FunctionType(); } - DelegateImpl(const DelegateImpl& del) + DelegateImpl(const DelegateImpl& del) { kind = del.kind; if (FUNC == del.kind) @@ -1520,7 +1461,7 @@ namespace detail } } - DelegateImpl(DelegateImpl&& del) + DelegateImpl(DelegateImpl&& del) { kind = del.kind; if (FUNC == del.kind) @@ -1539,19 +1480,13 @@ namespace detail DelegateImpl::fn = fn; } - template DelegateImpl(const F& functional) + template DelegateImpl(F functional) { kind = FUNC; - new (&this->functional) FunctionType(functional); + new (&this->functional) FunctionType(std::forward(functional)); } - template DelegateImpl(F&& functional) - { - kind = FUNC; - new (&this->functional) FunctionType(std::move(functional)); - } - - DelegateImpl& operator=(const DelegateImpl& del) + DelegateImpl& operator=(const DelegateImpl& del) { if (this == &del) return *this; if (FUNC == kind && FUNC != del.kind) @@ -1574,7 +1509,7 @@ namespace detail return *this; } - DelegateImpl& operator=(DelegateImpl&& del) + DelegateImpl& operator=(DelegateImpl&& del) { if (this == &del) return *this; if (FUNC == kind && FUNC != del.kind) @@ -1608,25 +1543,14 @@ namespace detail return *this; } - template DelegateImpl& operator=(const F& functional) + template DelegateImpl& operator=(F functional) { if (FUNC != kind) { new (&this->functional) FunctionType(); kind = FUNC; } - this->functional = functional; - return *this; - } - - template DelegateImpl& operator=(F&& functional) - { - if (FUNC != kind) - { - new (&this->functional) FunctionType(); - kind = FUNC; - } - this->functional = std::move(functional); + this->functional = std::forward(functional); return *this; } @@ -1730,12 +1654,12 @@ namespace detail fn = nullptr; } - DelegateImpl(const DelegateImpl& del) + DelegateImpl(const DelegateImpl& del) { fn = del.fn; } - DelegateImpl(DelegateImpl&& del) + DelegateImpl(DelegateImpl&& del) { fn = std::move(del.fn); } @@ -1745,19 +1669,19 @@ namespace detail DelegateImpl::fn = fn; } - template DelegateImpl(const F& fn) + template DelegateImpl(F fn) { - DelegateImpl::fn = fn; + DelegateImpl::fn = std::forward(fn); } - DelegateImpl& operator=(const DelegateImpl& del) + DelegateImpl& operator=(const DelegateImpl& del) { if (this == &del) return *this; fn = del.fn; return *this; } - DelegateImpl& operator=(DelegateImpl&& del) + DelegateImpl& operator=(DelegateImpl&& del) { if (this == &del) return *this; fn = std::move(del.fn); @@ -1770,9 +1694,9 @@ namespace detail return *this; } - template DelegateImpl& operator=(const F& fn) + template DelegateImpl& operator=(F fn) { - DelegateImpl::fn = fn; + DelegateImpl::fn = std::forward(fn); return *this; } From 6bac522a8a4975e5a295585e19998ad8271273ce Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Wed, 25 Dec 2019 00:24:37 +0100 Subject: [PATCH 28/55] Assignment operator template caused ambiguity error in MSVC build - drop it, it's strictly not necessary. --- cores/esp8266/Delegate.h | 86 ---------------------------------------- 1 file changed, 86 deletions(-) diff --git a/cores/esp8266/Delegate.h b/cores/esp8266/Delegate.h index 000202b00b..7ff2c10c86 100644 --- a/cores/esp8266/Delegate.h +++ b/cores/esp8266/Delegate.h @@ -231,21 +231,6 @@ namespace detail return *this; } - template DelegatePImpl& operator=(F functional) - { - if (FUNC != kind) - { - if (FPA == kind) - { - obj.~A(); - } - new (&this->functional) FunctionType(); - kind = FUNC; - } - this->functional = std::forward(functional); - return *this; - } - DelegatePImpl& IRAM_ATTR operator=(std::nullptr_t) { if (FUNC == kind) @@ -491,17 +476,6 @@ namespace detail return *this; } - template DelegatePImpl& operator=(F fn) - { - if (FPA == kind) - { - obj = {}; - } - kind = FP; - this->fn = std::forward(fn); - return *this; - } - DelegatePImpl& IRAM_ATTR operator=(std::nullptr_t) { if (FPA == kind) @@ -701,17 +675,6 @@ namespace detail return *this; } - template DelegatePImpl& operator=(F functional) - { - if (FUNC != kind) - { - new (&this->functional) FunctionType(); - kind = FUNC; - } - this->functional = std::forward(functional); - return *this; - } - DelegatePImpl& IRAM_ATTR operator=(std::nullptr_t) { if (FUNC == kind) @@ -852,12 +815,6 @@ namespace detail return *this; } - template DelegatePImpl& operator=(F fn) - { - DelegatePImpl::fn = std::forward(fn); - return *this; - } - DelegatePImpl& IRAM_ATTR operator=(std::nullptr_t) { fn = nullptr; @@ -1075,21 +1032,6 @@ namespace detail return *this; } - template DelegateImpl& operator=(F functional) - { - if (FUNC != kind) - { - if (FPA == kind) - { - obj.~A(); - } - new (&this->functional) FunctionType(); - kind = FUNC; - } - this->functional = std::forward(functional); - return *this; - } - DelegateImpl& IRAM_ATTR operator=(std::nullptr_t) { if (FUNC == kind) @@ -1334,17 +1276,6 @@ namespace detail return *this; } - template DelegateImpl& operator=(F fn) - { - if (FPA == kind) - { - obj = {}; - } - kind = FP; - this->fn = std::forward(fn); - return *this; - } - DelegateImpl& IRAM_ATTR operator=(std::nullptr_t) { if (FPA == kind) @@ -1543,17 +1474,6 @@ namespace detail return *this; } - template DelegateImpl& operator=(F functional) - { - if (FUNC != kind) - { - new (&this->functional) FunctionType(); - kind = FUNC; - } - this->functional = std::forward(functional); - return *this; - } - DelegateImpl& IRAM_ATTR operator=(std::nullptr_t) { if (FUNC == kind) @@ -1694,12 +1614,6 @@ namespace detail return *this; } - template DelegateImpl& operator=(F fn) - { - DelegateImpl::fn = std::forward(fn); - return *this; - } - DelegateImpl& IRAM_ATTR operator=(std::nullptr_t) { fn = nullptr; From ae7b4f69e982e5538b89bdfc41b944eedb83940c Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Sat, 18 Jan 2020 15:41:17 +0100 Subject: [PATCH 29/55] Delegate template programming for > 3 platforms is interesting. --- cores/esp8266/Delegate.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/cores/esp8266/Delegate.h b/cores/esp8266/Delegate.h index 7ff2c10c86..bd19c66eaf 100644 --- a/cores/esp8266/Delegate.h +++ b/cores/esp8266/Delegate.h @@ -1776,13 +1776,11 @@ template class Delegate : pub { public: using detail::Delegate::Delegate; - using detail::Delegate::operator=; }; template class Delegate : public detail::Delegate { public: using detail::Delegate::Delegate; - using detail::Delegate::operator=; }; #endif // __Delegate_h From c25965da2c9ed8d1241bdb815a50160e48195c7a Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Fri, 17 Jan 2020 15:54:50 +0100 Subject: [PATCH 30/55] unsigned/int instead of (u)int32_t gives lower memory footprint on 8bit devices. --- cores/esp8266/MultiDelegate.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cores/esp8266/MultiDelegate.h b/cores/esp8266/MultiDelegate.h index 1fd4188d69..d84c4c3714 100644 --- a/cores/esp8266/MultiDelegate.h +++ b/cores/esp8266/MultiDelegate.h @@ -87,7 +87,7 @@ namespace detail }; }; - template< typename Delegate, typename R = void, bool ISQUEUE = false, uint32_t QUEUE_CAPACITY = 32, typename... P> + template< typename Delegate, typename R = void, bool ISQUEUE = false, unsigned QUEUE_CAPACITY = 32, typename... P> class MultiDelegatePImpl { public: @@ -176,7 +176,7 @@ namespace detail Node_t* first = nullptr; Node_t* last = nullptr; Node_t* unused = nullptr; - uint32_t nodeCount = 0; + unsigned nodeCount = 0; // Returns a pointer to an unused Node_t, // or if none are available allocates a new one, @@ -370,7 +370,7 @@ namespace detail } }; - template< typename Delegate, typename R = void, bool ISQUEUE = false, uint32_t QUEUE_CAPACITY = 32> + template< typename Delegate, typename R = void, bool ISQUEUE = false, unsigned QUEUE_CAPACITY = 32> class MultiDelegateImpl : public MultiDelegatePImpl { protected: @@ -456,16 +456,16 @@ namespace detail } }; - template< typename Delegate, typename R, bool ISQUEUE, uint32_t QUEUE_CAPACITY, typename... P> class MultiDelegate; + template< typename Delegate, typename R, bool ISQUEUE, unsigned QUEUE_CAPACITY, typename... P> class MultiDelegate; - template< typename Delegate, typename R, bool ISQUEUE, uint32_t QUEUE_CAPACITY, typename... P> + template< typename Delegate, typename R, bool ISQUEUE, unsigned QUEUE_CAPACITY, typename... P> class MultiDelegate : public MultiDelegatePImpl { public: using MultiDelegatePImpl::MultiDelegatePImpl; }; - template< typename Delegate, typename R, bool ISQUEUE, uint32_t QUEUE_CAPACITY> + template< typename Delegate, typename R, bool ISQUEUE, unsigned QUEUE_CAPACITY> class MultiDelegate : public MultiDelegateImpl { public: @@ -493,7 +493,7 @@ It is designed to be used with Delegate, the efficient runtime wrapper for C fun allocates from the heap. Unused items are not returned to the heap, but are managed by the MultiDelegate instance during its own lifetime for efficiency. */ -template< typename Delegate, bool ISQUEUE = false, uint32_t QUEUE_CAPACITY = 32> +template< typename Delegate, bool ISQUEUE = false, unsigned QUEUE_CAPACITY = 32> class MultiDelegate : public detail::MultiDelegate { public: From 188c3f02600db0f3da3899daf660422e079356a7 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Sun, 19 Jan 2020 10:14:01 +0100 Subject: [PATCH 31/55] Refactor uses of unsigned for buffer sizes and item counts to size_t. --- cores/esp8266/MultiDelegate.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cores/esp8266/MultiDelegate.h b/cores/esp8266/MultiDelegate.h index d84c4c3714..58af232937 100644 --- a/cores/esp8266/MultiDelegate.h +++ b/cores/esp8266/MultiDelegate.h @@ -87,7 +87,7 @@ namespace detail }; }; - template< typename Delegate, typename R = void, bool ISQUEUE = false, unsigned QUEUE_CAPACITY = 32, typename... P> + template< typename Delegate, typename R = void, bool ISQUEUE = false, size_t QUEUE_CAPACITY = 32, typename... P> class MultiDelegatePImpl { public: @@ -176,7 +176,7 @@ namespace detail Node_t* first = nullptr; Node_t* last = nullptr; Node_t* unused = nullptr; - unsigned nodeCount = 0; + size_t nodeCount = 0; // Returns a pointer to an unused Node_t, // or if none are available allocates a new one, @@ -370,7 +370,7 @@ namespace detail } }; - template< typename Delegate, typename R = void, bool ISQUEUE = false, unsigned QUEUE_CAPACITY = 32> + template< typename Delegate, typename R = void, bool ISQUEUE = false, size_t QUEUE_CAPACITY = 32> class MultiDelegateImpl : public MultiDelegatePImpl { protected: @@ -456,16 +456,16 @@ namespace detail } }; - template< typename Delegate, typename R, bool ISQUEUE, unsigned QUEUE_CAPACITY, typename... P> class MultiDelegate; + template< typename Delegate, typename R, bool ISQUEUE, size_t QUEUE_CAPACITY, typename... P> class MultiDelegate; - template< typename Delegate, typename R, bool ISQUEUE, unsigned QUEUE_CAPACITY, typename... P> + template< typename Delegate, typename R, bool ISQUEUE, size_t QUEUE_CAPACITY, typename... P> class MultiDelegate : public MultiDelegatePImpl { public: using MultiDelegatePImpl::MultiDelegatePImpl; }; - template< typename Delegate, typename R, bool ISQUEUE, unsigned QUEUE_CAPACITY> + template< typename Delegate, typename R, bool ISQUEUE, size_t QUEUE_CAPACITY> class MultiDelegate : public MultiDelegateImpl { public: @@ -493,7 +493,7 @@ It is designed to be used with Delegate, the efficient runtime wrapper for C fun allocates from the heap. Unused items are not returned to the heap, but are managed by the MultiDelegate instance during its own lifetime for efficiency. */ -template< typename Delegate, bool ISQUEUE = false, unsigned QUEUE_CAPACITY = 32> +template< typename Delegate, bool ISQUEUE = false, size_t QUEUE_CAPACITY = 32> class MultiDelegate : public detail::MultiDelegate { public: From 07e52a1ab2b438c31866423e37b8047e8e5f0b61 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Tue, 21 Jan 2020 23:42:56 +0100 Subject: [PATCH 32/55] It was found that internal linkage suppresses the effect of the IRAM_ATTR attribute. This affects the unnamed namespace or static non-member functions. --- cores/esp8266/Delegate.h | 2634 +++++++++++++++++---------------- cores/esp8266/MultiDelegate.h | 649 ++++---- 2 files changed, 1647 insertions(+), 1636 deletions(-) diff --git a/cores/esp8266/Delegate.h b/cores/esp8266/Delegate.h index bd19c66eaf..3789c67a01 100644 --- a/cores/esp8266/Delegate.h +++ b/cores/esp8266/Delegate.h @@ -36,151 +36,205 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "circular_queue/ghostl.h" #endif -namespace detail +namespace delegate { - template - static R IRAM_ATTR vPtrToFunPtrExec(void* fn, P... args) + namespace detail { - using target_type = R(P...); - return reinterpret_cast(fn)(std::forward(args...)); - } - -#if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) - template - class DelegatePImpl { - public: - using target_type = R(P...); - protected: - using FunPtr = target_type*; - using FunAPtr = R(*)(A, P...); - using FunVPPtr = R(*)(void*, P...); - using FunctionType = std::function; - public: - DelegatePImpl() - { - kind = FP; - fn = nullptr; - } - - DelegatePImpl(std::nullptr_t) - { - kind = FP; - fn = nullptr; - } - ~DelegatePImpl() + template + R IRAM_ATTR vPtrToFunPtrExec(void* fn, P... args) { - if (FUNC == kind) - functional.~FunctionType(); - else if (FPA == kind) - obj.~A(); + using target_type = R(P...); + return reinterpret_cast(fn)(std::forward(args...)); } - DelegatePImpl(const DelegatePImpl& del) - { - kind = del.kind; - if (FUNC == del.kind) +#if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) + template + class DelegatePImpl { + public: + using target_type = R(P...); + protected: + using FunPtr = target_type*; + using FunAPtr = R(*)(A, P...); + using FunVPPtr = R(*)(void*, P...); + using FunctionType = std::function; + public: + DelegatePImpl() { - new (&functional) FunctionType(del.functional); + kind = FP; + fn = nullptr; } - else if (FPA == del.kind) + + DelegatePImpl(std::nullptr_t) { - fnA = del.fnA; - new (&obj) A(del.obj); + kind = FP; + fn = nullptr; } - else + + ~DelegatePImpl() { - fn = del.fn; + if (FUNC == kind) + functional.~FunctionType(); + else if (FPA == kind) + obj.~A(); } - } - DelegatePImpl(DelegatePImpl&& del) - { - kind = del.kind; - if (FUNC == del.kind) + DelegatePImpl(const DelegatePImpl& del) { - new (&functional) FunctionType(std::move(del.functional)); + kind = del.kind; + if (FUNC == del.kind) + { + new (&functional) FunctionType(del.functional); + } + else if (FPA == del.kind) + { + fnA = del.fnA; + new (&obj) A(del.obj); + } + else + { + fn = del.fn; + } } - else if (FPA == del.kind) + + DelegatePImpl(DelegatePImpl&& del) { - fnA = del.fnA; - new (&obj) A(std::move(del.obj)); + kind = del.kind; + if (FUNC == del.kind) + { + new (&functional) FunctionType(std::move(del.functional)); + } + else if (FPA == del.kind) + { + fnA = del.fnA; + new (&obj) A(std::move(del.obj)); + } + else + { + fn = del.fn; + } } - else + + DelegatePImpl(FunAPtr fnA, const A& obj) { - fn = del.fn; + kind = FPA; + DelegatePImpl::fnA = fnA; + new (&this->obj) A(obj); } - } - - DelegatePImpl(FunAPtr fnA, const A& obj) - { - kind = FPA; - DelegatePImpl::fnA = fnA; - new (&this->obj) A(obj); - } - DelegatePImpl(FunAPtr fnA, A&& obj) - { - kind = FPA; - DelegatePImpl::fnA = fnA; - new (&this->obj) A(std::move(obj)); - } + DelegatePImpl(FunAPtr fnA, A&& obj) + { + kind = FPA; + DelegatePImpl::fnA = fnA; + new (&this->obj) A(std::move(obj)); + } - DelegatePImpl(FunPtr fn) - { - kind = FP; - DelegatePImpl::fn = fn; - } + DelegatePImpl(FunPtr fn) + { + kind = FP; + DelegatePImpl::fn = fn; + } - template DelegatePImpl(F functional) - { - kind = FUNC; - new (&this->functional) FunctionType(std::forward(functional)); - } + template DelegatePImpl(F functional) + { + kind = FUNC; + new (&this->functional) FunctionType(std::forward(functional)); + } - DelegatePImpl& operator=(const DelegatePImpl& del) - { - if (this == &del) return *this; - if (kind != del.kind) + DelegatePImpl& operator=(const DelegatePImpl& del) { - if (FUNC == kind) - { - functional.~FunctionType(); - } - else if (FPA == kind) + if (this == &del) return *this; + if (kind != del.kind) { - obj.~A(); + if (FUNC == kind) + { + functional.~FunctionType(); + } + else if (FPA == kind) + { + obj.~A(); + } + if (FUNC == del.kind) + { + new (&this->functional) FunctionType(); + } + else if (FPA == del.kind) + { + new (&obj) A; + } + kind = del.kind; } if (FUNC == del.kind) { - new (&this->functional) FunctionType(); + functional = del.functional; } else if (FPA == del.kind) { - new (&obj) A; + fnA = del.fnA; + obj = del.obj; } - kind = del.kind; - } - if (FUNC == del.kind) - { - functional = del.functional; + else + { + fn = del.fn; + } + return *this; } - else if (FPA == del.kind) + + DelegatePImpl& operator=(DelegatePImpl&& del) { - fnA = del.fnA; - obj = del.obj; + if (this == &del) return *this; + if (kind != del.kind) + { + if (FUNC == kind) + { + functional.~FunctionType(); + } + else if (FPA == kind) + { + obj.~A(); + } + if (FUNC == del.kind) + { + new (&this->functional) FunctionType(); + } + else if (FPA == del.kind) + { + new (&obj) A; + } + kind = del.kind; + } + if (FUNC == del.kind) + { + functional = std::move(del.functional); + } + else if (FPA == del.kind) + { + fnA = del.fnA; + obj = std::move(del.obj); + } + else + { + fn = del.fn; + } + return *this; } - else + + DelegatePImpl& operator=(FunPtr fn) { - fn = del.fn; + if (FUNC == kind) + { + functional.~FunctionType(); + } + else if (FPA == kind) + { + obj.~A(); + } + kind = FP; + this->fn = fn; + return *this; } - return *this; - } - DelegatePImpl& operator=(DelegatePImpl&& del) - { - if (this == &del) return *this; - if (kind != del.kind) + DelegatePImpl& IRAM_ATTR operator=(std::nullptr_t) { if (FUNC == kind) { @@ -190,798 +244,783 @@ namespace detail { obj.~A(); } - if (FUNC == del.kind) + kind = FP; + fn = nullptr; + return *this; + } + + operator bool() const + { + if (FP == kind) { - new (&this->functional) FunctionType(); + return fn; } - else if (FPA == del.kind) + else if (FPA == kind) { - new (&obj) A; + return fnA; + } + else + { + return functional ? true : false; } - kind = del.kind; } - if (FUNC == del.kind) + + static R IRAM_ATTR vPtrToFunAPtrExec(void* self, P... args) { - functional = std::move(del.functional); - } - else if (FPA == del.kind) + return static_cast(self)->fnA( + static_cast(self)->obj, + std::forward(args...)); + }; + + operator FunVPPtr() const { - fnA = del.fnA; - obj = std::move(del.obj); + if (FP == kind) + { + return vPtrToFunPtrExec; + } + else if (FPA == kind) + { + return vPtrToFunAPtrExec; + } + else + { + return [](void* self, P... args) -> R + { + return static_cast(self)->functional(std::forward(args...)); + }; + } } - else + + void* arg() const { - fn = del.fn; + if (FP == kind) + { + return reinterpret_cast(fn); + } + else + { + return const_cast(this); + } } - return *this; - } - DelegatePImpl& operator=(FunPtr fn) - { - if (FUNC == kind) + operator FunctionType() const { - functional.~FunctionType(); + if (FP == kind) + { + return fn; + } + else if (FPA == kind) + { + return [this](P... args) { return fnA(obj, std::forward(args...)); }; + } + else + { + return functional; + } } - else if (FPA == kind) + + R IRAM_ATTR operator()(P... args) const { - obj.~A(); + if (FP == kind) + { + return fn(std::forward(args...)); + } + else if (FPA == kind) + { + return fnA(obj, std::forward(args...)); + } + else + { + return functional(std::forward(args...)); + } } - kind = FP; - this->fn = fn; - return *this; - } - DelegatePImpl& IRAM_ATTR operator=(std::nullptr_t) - { - if (FUNC == kind) + protected: + enum { FUNC, FP, FPA } kind; + union { + FunctionType functional; + FunPtr fn; + struct { + FunAPtr fnA; + A obj; + }; + }; + }; +#else + template + class DelegatePImpl { + public: + using target_type = R(P...); + protected: + using FunPtr = target_type*; + using FunAPtr = R(*)(A, P...); + using FunVPPtr = R(*)(void*, P...); + public: + DelegatePImpl() { - functional.~FunctionType(); + kind = FP; + fn = nullptr; } - else if (FPA == kind) + + DelegatePImpl(std::nullptr_t) { - obj.~A(); + kind = FP; + fn = nullptr; } - kind = FP; - fn = nullptr; - return *this; - } - operator bool() const - { - if (FP == kind) + DelegatePImpl(const DelegatePImpl& del) { - return fn; + kind = del.kind; + if (FPA == del.kind) + { + fnA = del.fnA; + obj = del.obj; + } + else + { + fn = del.fn; + } } - else if (FPA == kind) + + DelegatePImpl(DelegatePImpl&& del) { - return fnA; + kind = del.kind; + if (FPA == del.kind) + { + fnA = del.fnA; + obj = std::move(del.obj); + } + else + { + fn = del.fn; + } } - else + + DelegatePImpl(FunAPtr fnA, const A& obj) { - return functional ? true : false; + kind = FPA; + DelegatePImpl::fnA = fnA; + this->obj = obj; } - } - static R IRAM_ATTR vPtrToFunAPtrExec(void* self, P... args) - { - return static_cast(self)->fnA( - static_cast(self)->obj, - std::forward(args...)); - }; + DelegatePImpl(FunAPtr fnA, A&& obj) + { + kind = FPA; + DelegatePImpl::fnA = fnA; + this->obj = std::move(obj); + } - operator FunVPPtr() const - { - if (FP == kind) + DelegatePImpl(FunPtr fn) { - return vPtrToFunPtrExec; + kind = FP; + DelegatePImpl::fn = fn; } - else if (FPA == kind) + + template DelegatePImpl(F fn) { - return vPtrToFunAPtrExec; + kind = FP; + DelegatePImpl::fn = std::forward(fn); } - else + + DelegatePImpl& operator=(const DelegatePImpl& del) { - return [](void* self, P... args) -> R + if (this == &del) return *this; + if (kind != del.kind) { - return static_cast(self)->functional(std::forward(args...)); - }; + if (FPA == kind) + { + obj = {}; + } + kind = del.kind; + } + if (FPA == del.kind) + { + fnA = del.fnA; + obj = del.obj; + } + else + { + fn = del.fn; + } + return *this; } - } - void* arg() const - { - if (FP == kind) + DelegatePImpl& operator=(DelegatePImpl&& del) { - return reinterpret_cast(fn); + if (this == &del) return *this; + if (kind != del.kind) + { + if (FPA == kind) + { + obj = {}; + } + kind = del.kind; + } + if (FPA == del.kind) + { + fnA = del.fnA; + obj = std::move(del.obj); + } + else + { + fn = del.fn; + } + return *this; } - else + + DelegatePImpl& operator=(FunPtr fn) { - return const_cast(this); + if (FPA == kind) + { + obj = {}; + } + kind = FP; + this->fn = fn; + return *this; } - } - operator FunctionType() const - { - if (FP == kind) + DelegatePImpl& IRAM_ATTR operator=(std::nullptr_t) { - return fn; + if (FPA == kind) + { + obj = {}; + } + kind = FP; + fn = nullptr; + return *this; } - else if (FPA == kind) + + operator bool() const { - return [this](P... args) { return fnA(obj, std::forward(args...)); }; + if (FP == kind) + { + return fn; + } + else + { + return fnA; + } } - else + + static R IRAM_ATTR vPtrToFunAPtrExec(void* self, P... args) { - return functional; - } - } + return static_cast(self)->fnA( + static_cast(self)->obj, + std::forward(args...)); + }; - R IRAM_ATTR operator()(P... args) const - { - if (FP == kind) + operator FunVPPtr() const { - return fn(std::forward(args...)); + if (FP == kind) + { + return vPtrToFunPtrExec; + } + else + { + return vPtrToFunAPtrExec; + } } - else if (FPA == kind) + + void* arg() const { - return fnA(obj, std::forward(args...)); + if (FP == kind) + { + return reinterpret_cast(fn); + } + else + { + return const_cast(this); + } } - else + + R IRAM_ATTR operator()(P... args) const { - return functional(std::forward(args...)); + if (FP == kind) + { + return fn(std::forward(args...)); + } + else + { + return fnA(obj, std::forward(args...)); + } } - } - protected: - enum { FUNC, FP, FPA } kind; - union { - FunctionType functional; - FunPtr fn; - struct { + protected: + enum { FP, FPA } kind; + union { + FunPtr fn; FunAPtr fnA; - A obj; }; + A obj; }; - }; -#else - template - class DelegatePImpl { - public: - using target_type = R(P...); - protected: - using FunPtr = target_type*; - using FunAPtr = R(*)(A, P...); - using FunVPPtr = R(*)(void*, P...); - public: - DelegatePImpl() - { - kind = FP; - fn = nullptr; - } - - DelegatePImpl(std::nullptr_t) - { - kind = FP; - fn = nullptr; - } +#endif - DelegatePImpl(const DelegatePImpl& del) - { - kind = del.kind; - if (FPA == del.kind) - { - fnA = del.fnA; - obj = del.obj; - } - else +#if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) + template + class DelegatePImpl { + public: + using target_type = R(P...); + protected: + using FunPtr = target_type*; + using FunctionType = std::function; + using FunVPPtr = R(*)(void*, P...); + public: + DelegatePImpl() { - fn = del.fn; + kind = FP; + fn = nullptr; } - } - DelegatePImpl(DelegatePImpl&& del) - { - kind = del.kind; - if (FPA == del.kind) + DelegatePImpl(std::nullptr_t) { - fnA = del.fnA; - obj = std::move(del.obj); + kind = FP; + fn = nullptr; } - else + + ~DelegatePImpl() { - fn = del.fn; + if (FUNC == kind) + functional.~FunctionType(); } - } - - DelegatePImpl(FunAPtr fnA, const A& obj) - { - kind = FPA; - DelegatePImpl::fnA = fnA; - this->obj = obj; - } - DelegatePImpl(FunAPtr fnA, A&& obj) - { - kind = FPA; - DelegatePImpl::fnA = fnA; - this->obj = std::move(obj); - } - - DelegatePImpl(FunPtr fn) - { - kind = FP; - DelegatePImpl::fn = fn; - } - - template DelegatePImpl(F fn) - { - kind = FP; - DelegatePImpl::fn = std::forward(fn); - } - - DelegatePImpl& operator=(const DelegatePImpl& del) - { - if (this == &del) return *this; - if (kind != del.kind) + DelegatePImpl(const DelegatePImpl& del) { - if (FPA == kind) + kind = del.kind; + if (FUNC == del.kind) { - obj = {}; + new (&functional) FunctionType(del.functional); + } + else + { + fn = del.fn; } - kind = del.kind; - } - if (FPA == del.kind) - { - fnA = del.fnA; - obj = del.obj; - } - else - { - fn = del.fn; } - return *this; - } - DelegatePImpl& operator=(DelegatePImpl&& del) - { - if (this == &del) return *this; - if (kind != del.kind) + DelegatePImpl(DelegatePImpl&& del) { - if (FPA == kind) + kind = del.kind; + if (FUNC == del.kind) { - obj = {}; + new (&functional) FunctionType(std::move(del.functional)); + } + else + { + fn = del.fn; } - kind = del.kind; - } - if (FPA == del.kind) - { - fnA = del.fnA; - obj = std::move(del.obj); } - else + + DelegatePImpl(FunPtr fn) { - fn = del.fn; + kind = FP; + DelegatePImpl::fn = fn; } - return *this; - } - DelegatePImpl& operator=(FunPtr fn) - { - if (FPA == kind) + template DelegatePImpl(F functional) { - obj = {}; + kind = FUNC; + new (&this->functional) FunctionType(std::forward(functional)); } - kind = FP; - this->fn = fn; - return *this; - } - DelegatePImpl& IRAM_ATTR operator=(std::nullptr_t) - { - if (FPA == kind) + DelegatePImpl& operator=(const DelegatePImpl& del) { - obj = {}; + if (this == &del) return *this; + if (FUNC == kind && FUNC != del.kind) + { + functional.~FunctionType(); + } + else if (FUNC != kind && FUNC == del.kind) + { + new (&this->functional) FunctionType(); + } + kind = del.kind; + if (FUNC == del.kind) + { + functional = del.functional; + } + else + { + fn = del.fn; + } + return *this; } - kind = FP; - fn = nullptr; - return *this; - } - operator bool() const - { - if (FP == kind) + DelegatePImpl& operator=(DelegatePImpl&& del) { - return fn; + if (this == &del) return *this; + if (FUNC == kind && FUNC != del.kind) + { + functional.~FunctionType(); + } + else if (FUNC != kind && FUNC == del.kind) + { + new (&this->functional) FunctionType(); + } + kind = del.kind; + if (FUNC == del.kind) + { + functional = std::move(del.functional); + } + else + { + fn = del.fn; + } + return *this; } - else + + DelegatePImpl& operator=(FunPtr fn) { - return fnA; + if (FUNC == kind) + { + functional.~FunctionType(); + kind = FP; + } + DelegatePImpl::fn = fn; + return *this; } - } - - static R IRAM_ATTR vPtrToFunAPtrExec(void* self, P... args) - { - return static_cast(self)->fnA( - static_cast(self)->obj, - std::forward(args...)); - }; - operator FunVPPtr() const - { - if (FP == kind) + DelegatePImpl& IRAM_ATTR operator=(std::nullptr_t) { - return vPtrToFunPtrExec; + if (FUNC == kind) + { + functional.~FunctionType(); + } + kind = FP; + fn = nullptr; + return *this; } - else + + operator bool() const { - return vPtrToFunAPtrExec; + if (FP == kind) + { + return fn; + } + else + { + return functional ? true : false; + } } - } - void* arg() const - { - if (FP == kind) + operator FunVPPtr() const { - return reinterpret_cast(fn); + if (FP == kind) + { + return vPtrToFunPtrExec; + } + else + { + return [](void* self, P... args) -> R + { + return static_cast(self)->functional(std::forward(args...)); + }; + } } - else + + void* arg() const { - return const_cast(this); + if (FP == kind) + { + return reinterpret_cast(fn); + } + else + { + return const_cast(this); + } } - } - R IRAM_ATTR operator()(P... args) const - { - if (FP == kind) + operator FunctionType() const { - return fn(std::forward(args...)); + if (FP == kind) + { + return fn; + } + else + { + return functional; + } } - else + + R IRAM_ATTR operator()(P... args) const { - return fnA(obj, std::forward(args...)); + if (FP == kind) + { + return fn(std::forward(args...)); + } + else + { + return functional(std::forward(args...)); + } } - } - protected: - enum { FP, FPA } kind; - union { - FunPtr fn; - FunAPtr fnA; + protected: + enum { FUNC, FP } kind; + union { + FunctionType functional; + FunPtr fn; + }; }; - A obj; - }; -#endif - -#if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) - template - class DelegatePImpl { - public: - using target_type = R(P...); - protected: - using FunPtr = target_type*; - using FunctionType = std::function; - using FunVPPtr = R(*)(void*, P...); - public: - DelegatePImpl() - { - kind = FP; - fn = nullptr; - } - - DelegatePImpl(std::nullptr_t) - { - kind = FP; - fn = nullptr; - } - - ~DelegatePImpl() - { - if (FUNC == kind) - functional.~FunctionType(); - } - - DelegatePImpl(const DelegatePImpl& del) - { - kind = del.kind; - if (FUNC == del.kind) - { - new (&functional) FunctionType(del.functional); - } - else +#else + template + class DelegatePImpl { + public: + using target_type = R(P...); + protected: + using FunPtr = target_type*; + using FunVPPtr = R(*)(void*, P...); + public: + DelegatePImpl() { - fn = del.fn; + fn = nullptr; } - } - DelegatePImpl(DelegatePImpl&& del) - { - kind = del.kind; - if (FUNC == del.kind) + DelegatePImpl(std::nullptr_t) { - new (&functional) FunctionType(std::move(del.functional)); + fn = nullptr; } - else + + DelegatePImpl(const DelegatePImpl& del) { fn = del.fn; } - } - DelegatePImpl(FunPtr fn) - { - kind = FP; - DelegatePImpl::fn = fn; - } - - template DelegatePImpl(F functional) - { - kind = FUNC; - new (&this->functional) FunctionType(std::forward(functional)); - } - - DelegatePImpl& operator=(const DelegatePImpl& del) - { - if (this == &del) return *this; - if (FUNC == kind && FUNC != del.kind) + DelegatePImpl(DelegatePImpl&& del) { - functional.~FunctionType(); + fn = std::move(del.fn); } - else if (FUNC != kind && FUNC == del.kind) + + DelegatePImpl(FunPtr fn) { - new (&this->functional) FunctionType(); + DelegatePImpl::fn = fn; } - kind = del.kind; - if (FUNC == del.kind) + + template DelegatePImpl(F fn) { - functional = del.functional; + DelegatePImpl::fn = std::forward(fn); } - else + + DelegatePImpl& operator=(const DelegatePImpl& del) { + if (this == &del) return *this; fn = del.fn; + return *this; } - return *this; - } - DelegatePImpl& operator=(DelegatePImpl&& del) - { - if (this == &del) return *this; - if (FUNC == kind && FUNC != del.kind) - { - functional.~FunctionType(); - } - else if (FUNC != kind && FUNC == del.kind) - { - new (&this->functional) FunctionType(); - } - kind = del.kind; - if (FUNC == del.kind) + DelegatePImpl& operator=(DelegatePImpl&& del) { - functional = std::move(del.functional); + if (this == &del) return *this; + fn = std::move(del.fn); + return *this; } - else - { - fn = del.fn; - } - return *this; - } - DelegatePImpl& operator=(FunPtr fn) - { - if (FUNC == kind) + DelegatePImpl& operator=(FunPtr fn) { - functional.~FunctionType(); - kind = FP; + DelegatePImpl::fn = fn; + return *this; } - DelegatePImpl::fn = fn; - return *this; - } - DelegatePImpl& IRAM_ATTR operator=(std::nullptr_t) - { - if (FUNC == kind) + DelegatePImpl& IRAM_ATTR operator=(std::nullptr_t) { - functional.~FunctionType(); + fn = nullptr; + return *this; } - kind = FP; - fn = nullptr; - return *this; - } - operator bool() const - { - if (FP == kind) + operator bool() const { return fn; } - else - { - return functional ? true : false; - } - } - operator FunVPPtr() const - { - if (FP == kind) + operator FunVPPtr() const { return vPtrToFunPtrExec; } - else - { - return [](void* self, P... args) -> R - { - return static_cast(self)->functional(std::forward(args...)); - }; - } - } - void* arg() const - { - if (FP == kind) + void* arg() const { return reinterpret_cast(fn); } - else - { - return const_cast(this); - } - } - - operator FunctionType() const - { - if (FP == kind) - { - return fn; - } - else - { - return functional; - } - } - R IRAM_ATTR operator()(P... args) const - { - if (FP == kind) + R IRAM_ATTR operator()(P... args) const { return fn(std::forward(args...)); } - else - { - return functional(std::forward(args...)); - } - } - protected: - enum { FUNC, FP } kind; - union { - FunctionType functional; + protected: FunPtr fn; }; - }; -#else - template - class DelegatePImpl { - public: - using target_type = R(P...); - protected: - using FunPtr = target_type*; - using FunVPPtr = R(*)(void*, P...); - public: - DelegatePImpl() - { - fn = nullptr; - } - - DelegatePImpl(std::nullptr_t) - { - fn = nullptr; - } - - DelegatePImpl(const DelegatePImpl& del) - { - fn = del.fn; - } - - DelegatePImpl(DelegatePImpl&& del) - { - fn = std::move(del.fn); - } - - DelegatePImpl(FunPtr fn) - { - DelegatePImpl::fn = fn; - } - - template DelegatePImpl(F fn) - { - DelegatePImpl::fn = std::forward(fn); - } - - DelegatePImpl& operator=(const DelegatePImpl& del) - { - if (this == &del) return *this; - fn = del.fn; - return *this; - } - - DelegatePImpl& operator=(DelegatePImpl&& del) - { - if (this == &del) return *this; - fn = std::move(del.fn); - return *this; - } - - DelegatePImpl& operator=(FunPtr fn) - { - DelegatePImpl::fn = fn; - return *this; - } - - DelegatePImpl& IRAM_ATTR operator=(std::nullptr_t) - { - fn = nullptr; - return *this; - } - - operator bool() const - { - return fn; - } - - operator FunVPPtr() const - { - return vPtrToFunPtrExec; - } - - void* arg() const - { - return reinterpret_cast(fn); - } - - R IRAM_ATTR operator()(P... args) const - { - return fn(std::forward(args...)); - } - - protected: - FunPtr fn; - }; #endif #if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) - template - class DelegateImpl { - public: - using target_type = R(); - protected: - using FunPtr = target_type*; - using FunAPtr = R(*)(A); - using FunctionType = std::function; - using FunVPPtr = R(*)(void*); - public: - DelegateImpl() - { - kind = FP; - fn = nullptr; - } - - DelegateImpl(std::nullptr_t) - { - kind = FP; - fn = nullptr; - } - - ~DelegateImpl() - { - if (FUNC == kind) - functional.~FunctionType(); - else if (FPA == kind) - obj.~A(); - } - - DelegateImpl(const DelegateImpl& del) - { - kind = del.kind; - if (FUNC == del.kind) + template + class DelegateImpl { + public: + using target_type = R(); + protected: + using FunPtr = target_type*; + using FunAPtr = R(*)(A); + using FunctionType = std::function; + using FunVPPtr = R(*)(void*); + public: + DelegateImpl() { - new (&functional) FunctionType(del.functional); + kind = FP; + fn = nullptr; } - else if (FPA == del.kind) + + DelegateImpl(std::nullptr_t) { - fnA = del.fnA; - new (&obj) A(del.obj); + kind = FP; + fn = nullptr; } - else + + ~DelegateImpl() { - fn = del.fn; + if (FUNC == kind) + functional.~FunctionType(); + else if (FPA == kind) + obj.~A(); } - } - DelegateImpl(DelegateImpl&& del) - { - kind = del.kind; - if (FUNC == del.kind) + DelegateImpl(const DelegateImpl& del) { - new (&functional) FunctionType(std::move(del.functional)); + kind = del.kind; + if (FUNC == del.kind) + { + new (&functional) FunctionType(del.functional); + } + else if (FPA == del.kind) + { + fnA = del.fnA; + new (&obj) A(del.obj); + } + else + { + fn = del.fn; + } } - else if (FPA == del.kind) + + DelegateImpl(DelegateImpl&& del) { - fnA = del.fnA; - new (&obj) A(std::move(del.obj)); + kind = del.kind; + if (FUNC == del.kind) + { + new (&functional) FunctionType(std::move(del.functional)); + } + else if (FPA == del.kind) + { + fnA = del.fnA; + new (&obj) A(std::move(del.obj)); + } + else + { + fn = del.fn; + } } - else + + DelegateImpl(FunAPtr fnA, const A& obj) { - fn = del.fn; + kind = FPA; + DelegateImpl::fnA = fnA; + new (&this->obj) A(obj); } - } - - DelegateImpl(FunAPtr fnA, const A& obj) - { - kind = FPA; - DelegateImpl::fnA = fnA; - new (&this->obj) A(obj); - } - DelegateImpl(FunAPtr fnA, A&& obj) - { - kind = FPA; - DelegateImpl::fnA = fnA; - new (&this->obj) A(std::move(obj)); - } + DelegateImpl(FunAPtr fnA, A&& obj) + { + kind = FPA; + DelegateImpl::fnA = fnA; + new (&this->obj) A(std::move(obj)); + } - DelegateImpl(FunPtr fn) - { - kind = FP; - DelegateImpl::fn = fn; - } + DelegateImpl(FunPtr fn) + { + kind = FP; + DelegateImpl::fn = fn; + } - template DelegateImpl(F functional) - { - kind = FUNC; - new (&this->functional) FunctionType(std::forward(functional)); - } + template DelegateImpl(F functional) + { + kind = FUNC; + new (&this->functional) FunctionType(std::forward(functional)); + } - DelegateImpl& operator=(const DelegateImpl& del) - { - if (this == &del) return *this; - if (kind != del.kind) + DelegateImpl& operator=(const DelegateImpl& del) { - if (FUNC == kind) - { - functional.~FunctionType(); - } - else if (FPA == kind) + if (this == &del) return *this; + if (kind != del.kind) { - obj.~A(); + if (FUNC == kind) + { + functional.~FunctionType(); + } + else if (FPA == kind) + { + obj.~A(); + } + if (FUNC == del.kind) + { + new (&this->functional) FunctionType(); + } + else if (FPA == del.kind) + { + new (&obj) A; + } + kind = del.kind; } if (FUNC == del.kind) { - new (&this->functional) FunctionType(); + functional = del.functional; } else if (FPA == del.kind) { - new (&obj) A; + fnA = del.fnA; + obj = del.obj; } - kind = del.kind; - } - if (FUNC == del.kind) - { - functional = del.functional; - } - else if (FPA == del.kind) - { - fnA = del.fnA; - obj = del.obj; + else + { + fn = del.fn; + } + return *this; } - else + + DelegateImpl& operator=(DelegateImpl&& del) { - fn = del.fn; + if (this == &del) return *this; + if (kind != del.kind) + { + if (FUNC == kind) + { + functional.~FunctionType(); + } + else if (FPA == kind) + { + obj.~A(); + } + if (FUNC == del.kind) + { + new (&this->functional) FunctionType(); + } + else if (FPA == del.kind) + { + new (&obj) A; + } + kind = del.kind; + } + if (FUNC == del.kind) + { + functional = std::move(del.functional); + } + else if (FPA == del.kind) + { + fnA = del.fnA; + obj = std::move(del.obj); + } + else + { + fn = del.fn; + } + return *this; } - return *this; - } - DelegateImpl& operator=(DelegateImpl&& del) - { - if (this == &del) return *this; - if (kind != del.kind) + DelegateImpl& operator=(FunPtr fn) { if (FUNC == kind) { @@ -991,796 +1030,761 @@ namespace detail { obj.~A(); } - if (FUNC == del.kind) + kind = FP; + this->fn = fn; + return *this; + } + + DelegateImpl& IRAM_ATTR operator=(std::nullptr_t) + { + if (FUNC == kind) { - new (&this->functional) FunctionType(); + functional.~FunctionType(); } - else if (FPA == del.kind) + else if (FPA == kind) { - new (&obj) A; + obj.~A(); } - kind = del.kind; - } - if (FUNC == del.kind) - { - functional = std::move(del.functional); - } - else if (FPA == del.kind) - { - fnA = del.fnA; - obj = std::move(del.obj); - } - else - { - fn = del.fn; + kind = FP; + fn = nullptr; + return *this; } - return *this; - } - DelegateImpl& operator=(FunPtr fn) - { - if (FUNC == kind) + operator bool() const { - functional.~FunctionType(); - } - else if (FPA == kind) - { - obj.~A(); + if (FP == kind) + { + return fn; + } + else if (FPA == kind) + { + return fnA; + } + else + { + return functional ? true : false; + } } - kind = FP; - this->fn = fn; - return *this; - } - DelegateImpl& IRAM_ATTR operator=(std::nullptr_t) - { - if (FUNC == kind) + static R IRAM_ATTR vPtrToFunAPtrExec(void* self) { - functional.~FunctionType(); - } - else if (FPA == kind) + return static_cast(self)->fnA( + static_cast(self)->obj); + }; + + operator FunVPPtr() const { - obj.~A(); + if (FP == kind) + { + return reinterpret_cast(fn); + } + else if (FPA == kind) + { + return vPtrToFunAPtrExec; + } + else + { + return [](void* self) -> R + { + return static_cast(self)->functional(); + }; + } } - kind = FP; - fn = nullptr; - return *this; - } - operator bool() const - { - if (FP == kind) + void* arg() const { - return fn; + if (FP == kind) + { + return nullptr; + } + else + { + return const_cast(this); + } } - else if (FPA == kind) + + operator FunctionType() const { - return fnA; + if (FP == kind) + { + return fn; + } + else if (FPA == kind) + { + return [this]() { return fnA(obj); }; + } + else + { + return functional; + } } - else + + R IRAM_ATTR operator()() const { - return functional ? true : false; + if (FP == kind) + { + return fn(); + } + else if (FPA == kind) + { + return fnA(obj); + } + else + { + return functional(); + } } - } - static R IRAM_ATTR vPtrToFunAPtrExec(void* self) - { - return static_cast(self)->fnA( - static_cast(self)->obj); + protected: + enum { FUNC, FP, FPA } kind; + union { + FunctionType functional; + FunPtr fn; + struct { + FunAPtr fnA; + A obj; + }; + }; }; - - operator FunVPPtr() const - { - if (FP == kind) +#else + template + class DelegateImpl { + public: + using target_type = R(); + protected: + using FunPtr = target_type*; + using FunAPtr = R(*)(A); + using FunVPPtr = R(*)(void*); + public: + DelegateImpl() { - return reinterpret_cast(fn); + kind = FP; + fn = nullptr; } - else if (FPA == kind) + + DelegateImpl(std::nullptr_t) { - return vPtrToFunAPtrExec; + kind = FP; + fn = nullptr; } - else + + DelegateImpl(const DelegateImpl& del) { - return [](void* self) -> R + kind = del.kind; + if (FPA == del.kind) { - return static_cast(self)->functional(); - }; + fnA = del.fnA; + obj = del.obj; + } + else + { + fn = del.fn; + } } - } - void* arg() const - { - if (FP == kind) - { - return nullptr; - } - else + DelegateImpl(DelegateImpl&& del) { - return const_cast(this); + kind = del.kind; + if (FPA == del.kind) + { + fnA = del.fnA; + obj = std::move(del.obj); + } + else + { + fn = del.fn; + } } - } - operator FunctionType() const - { - if (FP == kind) - { - return fn; - } - else if (FPA == kind) + DelegateImpl(FunAPtr fnA, const A& obj) { - return [this]() { return fnA(obj); }; + kind = FPA; + DelegateImpl::fnA = fnA; + this->obj = obj; } - else - { - return functional; - } - } - R IRAM_ATTR operator()() const - { - if (FP == kind) + DelegateImpl(FunAPtr fnA, A&& obj) { - return fn(); - } - else if (FPA == kind) - { - return fnA(obj); + kind = FPA; + DelegateImpl::fnA = fnA; + this->obj = std::move(obj); } - else + + DelegateImpl(FunPtr fn) { - return functional(); + kind = FP; + DelegateImpl::fn = fn; } - } - - protected: - enum { FUNC, FP, FPA } kind; - union { - FunctionType functional; - FunPtr fn; - struct { - FunAPtr fnA; - A obj; - }; - }; - }; -#else - template - class DelegateImpl { - public: - using target_type = R(); - protected: - using FunPtr = target_type*; - using FunAPtr = R(*)(A); - using FunVPPtr = R(*)(void*); - public: - DelegateImpl() - { - kind = FP; - fn = nullptr; - } - - DelegateImpl(std::nullptr_t) - { - kind = FP; - fn = nullptr; - } - DelegateImpl(const DelegateImpl& del) - { - kind = del.kind; - if (FPA == del.kind) + template DelegateImpl(F fn) { - fnA = del.fnA; - obj = del.obj; + kind = FP; + DelegateImpl::fn = std::forward(fn); } - else + + DelegateImpl& operator=(const DelegateImpl& del) { - fn = del.fn; + if (this == &del) return *this; + if (kind != del.kind) + { + if (FPA == kind) + { + obj = {}; + } + kind = del.kind; + } + if (FPA == del.kind) + { + fnA = del.fnA; + obj = del.obj; + } + else + { + fn = del.fn; + } + return *this; } - } - DelegateImpl(DelegateImpl&& del) - { - kind = del.kind; - if (FPA == del.kind) + DelegateImpl& operator=(DelegateImpl&& del) { - fnA = del.fnA; - obj = std::move(del.obj); + if (this == &del) return *this; + if (kind != del.kind) + { + if (FPA == kind) + { + obj = {}; + } + kind = del.kind; + } + if (FPA == del.kind) + { + fnA = del.fnA; + obj = std::move(del.obj); + } + else + { + fn = del.fn; + } + return *this; } - else + + DelegateImpl& operator=(FunPtr fn) { - fn = del.fn; + if (FPA == kind) + { + obj = {}; + } + kind = FP; + this->fn = fn; + return *this; } - } - - DelegateImpl(FunAPtr fnA, const A& obj) - { - kind = FPA; - DelegateImpl::fnA = fnA; - this->obj = obj; - } - - DelegateImpl(FunAPtr fnA, A&& obj) - { - kind = FPA; - DelegateImpl::fnA = fnA; - this->obj = std::move(obj); - } - - DelegateImpl(FunPtr fn) - { - kind = FP; - DelegateImpl::fn = fn; - } - template DelegateImpl(F fn) - { - kind = FP; - DelegateImpl::fn = std::forward(fn); - } - - DelegateImpl& operator=(const DelegateImpl& del) - { - if (this == &del) return *this; - if (kind != del.kind) + DelegateImpl& IRAM_ATTR operator=(std::nullptr_t) { if (FPA == kind) { obj = {}; } - kind = del.kind; + kind = FP; + fn = nullptr; + return *this; } - if (FPA == del.kind) + + operator bool() const { - fnA = del.fnA; - obj = del.obj; + if (FP == kind) + { + return fn; + } + else + { + return fnA; + } } - else + + static R IRAM_ATTR vPtrToFunAPtrExec(void* self) { - fn = del.fn; + return static_cast(self)->fnA( + static_cast(self)->obj); + }; + + operator FunVPPtr() const + { + if (FP == kind) + { + return reinterpret_cast(fn); + } + else + { + return vPtrToFunAPtrExec; + } } - return *this; - } - DelegateImpl& operator=(DelegateImpl&& del) - { - if (this == &del) return *this; - if (kind != del.kind) + void* arg() const { - if (FPA == kind) + if (FP == kind) { - obj = {}; + return nullptr; + } + else + { + return const_cast(this); } - kind = del.kind; } - if (FPA == del.kind) + + R IRAM_ATTR operator()() const { - fnA = del.fnA; - obj = std::move(del.obj); + if (FP == kind) + { + return fn(); + } + else + { + return fnA(obj); + } } - else + + protected: + enum { FP, FPA } kind; + union { + FunPtr fn; + FunAPtr fnA; + }; + A obj; + }; +#endif + +#if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) + template + class DelegateImpl { + public: + using target_type = R(); + protected: + using FunPtr = target_type*; + using FunctionType = std::function; + using FunVPPtr = R(*)(void*); + public: + DelegateImpl() { - fn = del.fn; + kind = FP; + fn = nullptr; } - return *this; - } - DelegateImpl& operator=(FunPtr fn) - { - if (FPA == kind) + DelegateImpl(std::nullptr_t) { - obj = {}; + kind = FP; + fn = nullptr; } - kind = FP; - this->fn = fn; - return *this; - } - DelegateImpl& IRAM_ATTR operator=(std::nullptr_t) - { - if (FPA == kind) + ~DelegateImpl() { - obj = {}; + if (FUNC == kind) + functional.~FunctionType(); } - kind = FP; - fn = nullptr; - return *this; - } - operator bool() const - { - if (FP == kind) + DelegateImpl(const DelegateImpl& del) { - return fn; + kind = del.kind; + if (FUNC == del.kind) + { + new (&functional) FunctionType(del.functional); + } + else + { + fn = del.fn; + } } - else + + DelegateImpl(DelegateImpl&& del) { - return fnA; + kind = del.kind; + if (FUNC == del.kind) + { + new (&functional) FunctionType(std::move(del.functional)); + } + else + { + fn = del.fn; + } } - } - - static R IRAM_ATTR vPtrToFunAPtrExec(void* self) - { - return static_cast(self)->fnA( - static_cast(self)->obj); - }; - operator FunVPPtr() const - { - if (FP == kind) + DelegateImpl(FunPtr fn) { - return reinterpret_cast(fn); + kind = FP; + DelegateImpl::fn = fn; } - else + + template DelegateImpl(F functional) { - return vPtrToFunAPtrExec; + kind = FUNC; + new (&this->functional) FunctionType(std::forward(functional)); } - } - void* arg() const - { - if (FP == kind) + DelegateImpl& operator=(const DelegateImpl& del) { - return nullptr; + if (this == &del) return *this; + if (FUNC == kind && FUNC != del.kind) + { + functional.~FunctionType(); + } + else if (FUNC != kind && FUNC == del.kind) + { + new (&this->functional) FunctionType(); + } + kind = del.kind; + if (FUNC == del.kind) + { + functional = del.functional; + } + else + { + fn = del.fn; + } + return *this; } - else + + DelegateImpl& operator=(DelegateImpl&& del) { - return const_cast(this); + if (this == &del) return *this; + if (FUNC == kind && FUNC != del.kind) + { + functional.~FunctionType(); + } + else if (FUNC != kind && FUNC == del.kind) + { + new (&this->functional) FunctionType(); + } + kind = del.kind; + if (FUNC == del.kind) + { + functional = std::move(del.functional); + } + else + { + fn = del.fn; + } + return *this; } - } - R IRAM_ATTR operator()() const - { - if (FP == kind) + DelegateImpl& operator=(FunPtr fn) { - return fn(); + if (FUNC == kind) + { + functional.~FunctionType(); + kind = FP; + } + DelegateImpl::fn = fn; + return *this; } - else + + DelegateImpl& IRAM_ATTR operator=(std::nullptr_t) { - return fnA(obj); + if (FUNC == kind) + { + functional.~FunctionType(); + } + kind = FP; + fn = nullptr; + return *this; } - } - - protected: - enum { FP, FPA } kind; - union { - FunPtr fn; - FunAPtr fnA; - }; - A obj; - }; -#endif - -#if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) - template - class DelegateImpl { - public: - using target_type = R(); - protected: - using FunPtr = target_type*; - using FunctionType = std::function; - using FunVPPtr = R(*)(void*); - public: - DelegateImpl() - { - kind = FP; - fn = nullptr; - } - - DelegateImpl(std::nullptr_t) - { - kind = FP; - fn = nullptr; - } - - ~DelegateImpl() - { - if (FUNC == kind) - functional.~FunctionType(); - } - DelegateImpl(const DelegateImpl& del) - { - kind = del.kind; - if (FUNC == del.kind) + operator bool() const { - new (&functional) FunctionType(del.functional); + if (FP == kind) + { + return fn; + } + else + { + return functional ? true : false; + } } - else + + operator FunVPPtr() const { - fn = del.fn; + if (FP == kind) + { + return reinterpret_cast(fn); + } + else + { + return [](void* self) -> R + { + return static_cast(self)->functional(); + }; + } } - } - DelegateImpl(DelegateImpl&& del) - { - kind = del.kind; - if (FUNC == del.kind) + void* arg() const { - new (&functional) FunctionType(std::move(del.functional)); + if (FP == kind) + { + return nullptr; + } + else + { + return const_cast(this); + } } - else + + operator FunctionType() const { - fn = del.fn; + if (FP == kind) + { + return fn; + } + else + { + return functional; + } } - } - - DelegateImpl(FunPtr fn) - { - kind = FP; - DelegateImpl::fn = fn; - } - template DelegateImpl(F functional) - { - kind = FUNC; - new (&this->functional) FunctionType(std::forward(functional)); - } - - DelegateImpl& operator=(const DelegateImpl& del) - { - if (this == &del) return *this; - if (FUNC == kind && FUNC != del.kind) + R IRAM_ATTR operator()() const { - functional.~FunctionType(); + if (FP == kind) + { + return fn(); + } + else + { + return functional(); + } } - else if (FUNC != kind && FUNC == del.kind) + + protected: + enum { FUNC, FP } kind; + union { + FunctionType functional; + FunPtr fn; + }; + }; +#else + template + class DelegateImpl { + public: + using target_type = R(); + protected: + using FunPtr = target_type*; + using FunVPPtr = R(*)(void*); + public: + DelegateImpl() { - new (&this->functional) FunctionType(); + fn = nullptr; } - kind = del.kind; - if (FUNC == del.kind) + + DelegateImpl(std::nullptr_t) { - functional = del.functional; + fn = nullptr; } - else + + DelegateImpl(const DelegateImpl& del) { fn = del.fn; } - return *this; - } - DelegateImpl& operator=(DelegateImpl&& del) - { - if (this == &del) return *this; - if (FUNC == kind && FUNC != del.kind) + DelegateImpl(DelegateImpl&& del) { - functional.~FunctionType(); + fn = std::move(del.fn); } - else if (FUNC != kind && FUNC == del.kind) + + DelegateImpl(FunPtr fn) { - new (&this->functional) FunctionType(); + DelegateImpl::fn = fn; } - kind = del.kind; - if (FUNC == del.kind) + + template DelegateImpl(F fn) { - functional = std::move(del.functional); + DelegateImpl::fn = std::forward(fn); } - else + + DelegateImpl& operator=(const DelegateImpl& del) { + if (this == &del) return *this; fn = del.fn; + return *this; } - return *this; - } - DelegateImpl& operator=(FunPtr fn) - { - if (FUNC == kind) + DelegateImpl& operator=(DelegateImpl&& del) { - functional.~FunctionType(); - kind = FP; + if (this == &del) return *this; + fn = std::move(del.fn); + return *this; } - DelegateImpl::fn = fn; - return *this; - } - DelegateImpl& IRAM_ATTR operator=(std::nullptr_t) - { - if (FUNC == kind) + DelegateImpl& operator=(FunPtr fn) { - functional.~FunctionType(); + DelegateImpl::fn = fn; + return *this; } - kind = FP; - fn = nullptr; - return *this; - } - operator bool() const - { - if (FP == kind) + DelegateImpl& IRAM_ATTR operator=(std::nullptr_t) { - return fn; + fn = nullptr; + return *this; } - else + + operator bool() const { - return functional ? true : false; + return fn; } - } - operator FunVPPtr() const - { - if (FP == kind) + operator FunVPPtr() const { return reinterpret_cast(fn); } - else - { - return [](void* self) -> R - { - return static_cast(self)->functional(); - }; - } - } - void* arg() const - { - if (FP == kind) + void* arg() const { return nullptr; } - else - { - return const_cast(this); - } - } - - operator FunctionType() const - { - if (FP == kind) - { - return fn; - } - else - { - return functional; - } - } - R IRAM_ATTR operator()() const - { - if (FP == kind) + R IRAM_ATTR operator()() const { return fn(); } - else - { - return functional(); - } - } - protected: - enum { FUNC, FP } kind; - union { - FunctionType functional; + protected: FunPtr fn; }; - }; -#else - template - class DelegateImpl { - public: - using target_type = R(); - protected: - using FunPtr = target_type*; - using FunVPPtr = R(*)(void*); - public: - DelegateImpl() - { - fn = nullptr; - } - - DelegateImpl(std::nullptr_t) - { - fn = nullptr; - } - - DelegateImpl(const DelegateImpl& del) - { - fn = del.fn; - } - - DelegateImpl(DelegateImpl&& del) - { - fn = std::move(del.fn); - } - - DelegateImpl(FunPtr fn) - { - DelegateImpl::fn = fn; - } - - template DelegateImpl(F fn) - { - DelegateImpl::fn = std::forward(fn); - } - - DelegateImpl& operator=(const DelegateImpl& del) - { - if (this == &del) return *this; - fn = del.fn; - return *this; - } - - DelegateImpl& operator=(DelegateImpl&& del) - { - if (this == &del) return *this; - fn = std::move(del.fn); - return *this; - } - - DelegateImpl& operator=(FunPtr fn) - { - DelegateImpl::fn = fn; - return *this; - } - - DelegateImpl& IRAM_ATTR operator=(std::nullptr_t) - { - fn = nullptr; - return *this; - } - - operator bool() const - { - return fn; - } - - operator FunVPPtr() const - { - return reinterpret_cast(fn); - } - - void* arg() const - { - return nullptr; - } - - R IRAM_ATTR operator()() const - { - return fn(); - } - - protected: - FunPtr fn; - }; #endif - template - class Delegate : private detail::DelegatePImpl - { - private: - using typename detail::DelegatePImpl::FunVPPtr; + template + class Delegate : private detail::DelegatePImpl + { + private: + using typename detail::DelegatePImpl::FunVPPtr; #if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) - using typename detail::DelegatePImpl::FunctionType; + using typename detail::DelegatePImpl::FunctionType; #endif - public: - using detail::DelegatePImpl::target_type; - using detail::DelegatePImpl::DelegatePImpl; - using detail::DelegatePImpl::operator=; - using detail::DelegatePImpl::operator bool; - using detail::DelegatePImpl::operator FunVPPtr; - using detail::DelegatePImpl::arg; + public: + using detail::DelegatePImpl::target_type; + using detail::DelegatePImpl::DelegatePImpl; + using detail::DelegatePImpl::operator=; + using detail::DelegatePImpl::operator bool; + using detail::DelegatePImpl::operator FunVPPtr; + using detail::DelegatePImpl::arg; #if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) - using detail::DelegatePImpl::operator FunctionType; + using detail::DelegatePImpl::operator FunctionType; #endif - using detail::DelegatePImpl::operator(); - }; + using detail::DelegatePImpl::operator(); + }; - template - class Delegate : private detail::DelegatePImpl - { - private: - using typename detail::DelegatePImpl::FunVPPtr; + template + class Delegate : private detail::DelegatePImpl + { + private: + using typename detail::DelegatePImpl::FunVPPtr; #if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) - using typename detail::DelegatePImpl::FunctionType; + using typename detail::DelegatePImpl::FunctionType; #endif - public: - using detail::DelegatePImpl::target_type; - using detail::DelegatePImpl::DelegatePImpl; - using detail::DelegatePImpl::operator=; - using detail::DelegatePImpl::operator bool; + public: + using detail::DelegatePImpl::target_type; + using detail::DelegatePImpl::DelegatePImpl; + using detail::DelegatePImpl::operator=; + using detail::DelegatePImpl::operator bool; #if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) - using detail::DelegatePImpl::operator FunctionType; + using detail::DelegatePImpl::operator FunctionType; #endif - using detail::DelegatePImpl::operator(); - operator FunVPPtr() const - { - if (detail::DelegatePImpl::FPA == detail::DelegatePImpl::kind) - { - return reinterpret_cast(detail::DelegatePImpl::fnA); - } - else - { - return detail::DelegatePImpl::operator FunVPPtr(); - } - } - void* arg() const - { - if (detail::DelegatePImpl::FPA == detail::DelegatePImpl::kind) + using detail::DelegatePImpl::operator(); + operator FunVPPtr() const { - return detail::DelegatePImpl::obj; + if (detail::DelegatePImpl::FPA == detail::DelegatePImpl::kind) + { + return reinterpret_cast(detail::DelegatePImpl::fnA); + } + else + { + return detail::DelegatePImpl::operator FunVPPtr(); + } } - else + void* arg() const { - return detail::DelegatePImpl::arg(); + if (detail::DelegatePImpl::FPA == detail::DelegatePImpl::kind) + { + return detail::DelegatePImpl::obj; + } + else + { + return detail::DelegatePImpl::arg(); + } } - } - }; + }; - template - class Delegate : private detail::DelegateImpl - { - private: - using typename detail::DelegateImpl::FunVPPtr; + template + class Delegate : private detail::DelegateImpl + { + private: + using typename detail::DelegateImpl::FunVPPtr; #if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) - using typename detail::DelegateImpl::FunctionType; + using typename detail::DelegateImpl::FunctionType; #endif - public: - using detail::DelegateImpl::target_type; - using detail::DelegateImpl::DelegateImpl; - using detail::DelegateImpl::operator=; - using detail::DelegateImpl::operator bool; - using detail::DelegateImpl::operator FunVPPtr; - using detail::DelegateImpl::arg; + public: + using detail::DelegateImpl::target_type; + using detail::DelegateImpl::DelegateImpl; + using detail::DelegateImpl::operator=; + using detail::DelegateImpl::operator bool; + using detail::DelegateImpl::operator FunVPPtr; + using detail::DelegateImpl::arg; #if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) - using detail::DelegateImpl::operator FunctionType; + using detail::DelegateImpl::operator FunctionType; #endif - using detail::DelegateImpl::operator(); - }; + using detail::DelegateImpl::operator(); + }; - template - class Delegate : private detail::DelegateImpl - { - private: - using typename detail::DelegateImpl::FunVPPtr; + template + class Delegate : private detail::DelegateImpl + { + private: + using typename detail::DelegateImpl::FunVPPtr; #if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) - using typename detail::DelegateImpl::FunctionType; + using typename detail::DelegateImpl::FunctionType; #endif - public: - using detail::DelegateImpl::target_type; - using detail::DelegateImpl::DelegateImpl; - using detail::DelegateImpl::operator=; - using detail::DelegateImpl::operator bool; + public: + using detail::DelegateImpl::target_type; + using detail::DelegateImpl::DelegateImpl; + using detail::DelegateImpl::operator=; + using detail::DelegateImpl::operator bool; #if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) - using detail::DelegateImpl::operator FunctionType; + using detail::DelegateImpl::operator FunctionType; #endif - using detail::DelegateImpl::operator(); - operator FunVPPtr() const - { - if (detail::DelegateImpl::FPA == detail::DelegateImpl::kind) - { - return reinterpret_cast(detail::DelegateImpl::fnA); - } - else - { - return detail::DelegateImpl::operator FunVPPtr(); - } - } - void* arg() const - { - if (detail::DelegateImpl::FPA == detail::DelegateImpl::kind) + using detail::DelegateImpl::operator(); + operator FunVPPtr() const { - return detail::DelegateImpl::obj; + if (detail::DelegateImpl::FPA == detail::DelegateImpl::kind) + { + return reinterpret_cast(detail::DelegateImpl::fnA); + } + else + { + return detail::DelegateImpl::operator FunVPPtr(); + } } - else + void* arg() const { - return detail::DelegateImpl::arg(); + if (detail::DelegateImpl::FPA == detail::DelegateImpl::kind) + { + return detail::DelegateImpl::obj; + } + else + { + return detail::DelegateImpl::arg(); + } } - } - }; + }; + } } template class Delegate; -template class Delegate : public detail::Delegate +template class Delegate : public delegate::detail::Delegate { public: - using detail::Delegate::Delegate; + using delegate::detail::Delegate::Delegate; }; -template class Delegate : public detail::Delegate +template class Delegate : public delegate::detail::Delegate { public: - using detail::Delegate::Delegate; + using delegate::detail::Delegate::Delegate; }; #endif // __Delegate_h diff --git a/cores/esp8266/MultiDelegate.h b/cores/esp8266/MultiDelegate.h index 58af232937..055078e216 100644 --- a/cores/esp8266/MultiDelegate.h +++ b/cores/esp8266/MultiDelegate.h @@ -44,434 +44,441 @@ class InterruptLock { #include #endif -namespace detail +namespace { - namespace - { - template< typename Delegate, typename R, bool ISQUEUE = false, typename... P> - struct CallP - { - static R execute(Delegate& del, P... args) - { - return del(std::forward(args...)) ? !ISQUEUE : ISQUEUE; - } - }; - template< typename Delegate, bool ISQUEUE, typename... P> - struct CallP + template< typename Delegate, typename R, bool ISQUEUE = false, typename... P> + struct CallP + { + static R execute(Delegate& del, P... args) { - static bool execute(Delegate& del, P... args) - { - del(std::forward(args...)); - return !ISQUEUE; - } - }; + return del(std::forward(args...)) ? !ISQUEUE : ISQUEUE; + } + }; - template< typename Delegate, typename R, bool ISQUEUE = false> - struct Call + template< typename Delegate, bool ISQUEUE, typename... P> + struct CallP + { + static bool execute(Delegate& del, P... args) { - static R execute(Delegate& del) - { - return del() ? !ISQUEUE : ISQUEUE; - } - }; + del(std::forward(args...)); + return !ISQUEUE; + } + }; - template< typename Delegate, bool ISQUEUE> - struct Call + template< typename Delegate, typename R, bool ISQUEUE = false> + struct Call + { + static R execute(Delegate& del) { - static bool execute(Delegate& del) - { - del(); - return !ISQUEUE; - } - }; + return del() ? !ISQUEUE : ISQUEUE; + } }; - template< typename Delegate, typename R = void, bool ISQUEUE = false, size_t QUEUE_CAPACITY = 32, typename... P> - class MultiDelegatePImpl + template< typename Delegate, bool ISQUEUE> + struct Call { - public: - MultiDelegatePImpl() = default; - ~MultiDelegatePImpl() + static bool execute(Delegate& del) { - *this = nullptr; + del(); + return !ISQUEUE; } + }; - MultiDelegatePImpl(const MultiDelegatePImpl&) = delete; - MultiDelegatePImpl& operator=(const MultiDelegatePImpl&) = delete; +} - MultiDelegatePImpl(MultiDelegatePImpl&& md) - { - first = md.first; - last = md.last; - unused = md.unused; - nodeCount = md.nodeCount; - md.first = nullptr; - md.last = nullptr; - md.unused = nullptr; - md.nodeCount = 0; - } +namespace delegate +{ + namespace detail + { - MultiDelegatePImpl(const Delegate& del) + template< typename Delegate, typename R = void, bool ISQUEUE = false, size_t QUEUE_CAPACITY = 32, typename... P> + class MultiDelegatePImpl { - add(del); - } + public: + MultiDelegatePImpl() = default; + ~MultiDelegatePImpl() + { + *this = nullptr; + } - MultiDelegatePImpl(Delegate&& del) - { - add(std::move(del)); - } + MultiDelegatePImpl(const MultiDelegatePImpl&) = delete; + MultiDelegatePImpl& operator=(const MultiDelegatePImpl&) = delete; - MultiDelegatePImpl& operator=(MultiDelegatePImpl&& md) - { - first = md.first; - last = md.last; - unused = md.unused; - nodeCount = md.nodeCount; - md.first = nullptr; - md.last = nullptr; - md.unused = nullptr; - md.nodeCount = 0; - return *this; - } + MultiDelegatePImpl(MultiDelegatePImpl&& md) + { + first = md.first; + last = md.last; + unused = md.unused; + nodeCount = md.nodeCount; + md.first = nullptr; + md.last = nullptr; + md.unused = nullptr; + md.nodeCount = 0; + } - MultiDelegatePImpl& operator=(std::nullptr_t) - { - if (last) - last->mNext = unused; - if (first) - unused = first; - while (unused) + MultiDelegatePImpl(const Delegate& del) { - auto to_delete = unused; - unused = unused->mNext; - delete(to_delete); + add(del); } - return *this; - } - MultiDelegatePImpl& operator+=(const Delegate& del) - { - add(del); - return *this; - } + MultiDelegatePImpl(Delegate&& del) + { + add(std::move(del)); + } - MultiDelegatePImpl& operator+=(Delegate&& del) - { - add(std::move(del)); - return *this; - } + MultiDelegatePImpl& operator=(MultiDelegatePImpl&& md) + { + first = md.first; + last = md.last; + unused = md.unused; + nodeCount = md.nodeCount; + md.first = nullptr; + md.last = nullptr; + md.unused = nullptr; + md.nodeCount = 0; + return *this; + } - protected: - struct Node_t - { - ~Node_t() + MultiDelegatePImpl& operator=(std::nullptr_t) { - mDelegate = nullptr; // special overload in Delegate + if (last) + last->mNext = unused; + if (first) + unused = first; + while (unused) + { + auto to_delete = unused; + unused = unused->mNext; + delete(to_delete); + } + return *this; } - Node_t* mNext = nullptr; - Delegate mDelegate; - }; - Node_t* first = nullptr; - Node_t* last = nullptr; - Node_t* unused = nullptr; - size_t nodeCount = 0; + MultiDelegatePImpl& operator+=(const Delegate& del) + { + add(del); + return *this; + } - // Returns a pointer to an unused Node_t, - // or if none are available allocates a new one, - // or nullptr if limit is reached - Node_t* IRAM_ATTR get_node_unsafe() - { - Node_t* result = nullptr; - // try to get an item from unused items list - if (unused) + MultiDelegatePImpl& operator+=(Delegate&& del) { - result = unused; - unused = unused->mNext; + add(std::move(del)); + return *this; } - // if no unused items, and count not too high, allocate a new one - else if (nodeCount < QUEUE_CAPACITY) + + protected: + struct Node_t { + ~Node_t() + { + mDelegate = nullptr; // special overload in Delegate + } + Node_t* mNext = nullptr; + Delegate mDelegate; + }; + + Node_t* first = nullptr; + Node_t* last = nullptr; + Node_t* unused = nullptr; + size_t nodeCount = 0; + + // Returns a pointer to an unused Node_t, + // or if none are available allocates a new one, + // or nullptr if limit is reached + Node_t* IRAM_ATTR get_node_unsafe() + { + Node_t* result = nullptr; + // try to get an item from unused items list + if (unused) + { + result = unused; + unused = unused->mNext; + } + // if no unused items, and count not too high, allocate a new one + else if (nodeCount < QUEUE_CAPACITY) + { #if defined(ESP8266) || defined(ESP32) - result = new (std::nothrow) Node_t; + result = new (std::nothrow) Node_t; #else - result = new Node_t; + result = new Node_t; #endif - if (result) - ++nodeCount; + if (result) + ++nodeCount; + } + return result; } - return result; - } - void recycle_node_unsafe(Node_t* node) - { - node->mDelegate = nullptr; // special overload in Delegate - node->mNext = unused; - unused = node; - } + void recycle_node_unsafe(Node_t* node) + { + node->mDelegate = nullptr; // special overload in Delegate + node->mNext = unused; + unused = node; + } #ifndef ARDUINO - std::mutex mutex_unused; + std::mutex mutex_unused; #endif - public: - const Delegate* IRAM_ATTR add(const Delegate& del) - { - return add(Delegate(del)); - } + public: + const Delegate* IRAM_ATTR add(const Delegate& del) + { + return add(Delegate(del)); + } - const Delegate* IRAM_ATTR add(Delegate&& del) - { - if (!del) - return nullptr; + const Delegate* IRAM_ATTR add(Delegate&& del) + { + if (!del) + return nullptr; #ifdef ARDUINO - InterruptLock lockAllInterruptsInThisScope; + InterruptLock lockAllInterruptsInThisScope; #else - std::lock_guard lock(mutex_unused); + std::lock_guard lock(mutex_unused); #endif - Node_t* item = ISQUEUE ? get_node_unsafe() : + Node_t* item = ISQUEUE ? get_node_unsafe() : #if defined(ESP8266) || defined(ESP32) - new (std::nothrow) Node_t; + new (std::nothrow) Node_t; #else - new Node_t; + new Node_t; #endif - if (!item) - return nullptr; - - item->mDelegate = std::move(del); - item->mNext = nullptr; + if (!item) + return nullptr; - if (last) - last->mNext = item; - else - first = item; - last = item; + item->mDelegate = std::move(del); + item->mNext = nullptr; - return &item->mDelegate; - } + if (last) + last->mNext = item; + else + first = item; + last = item; - bool remove(const Delegate* del) - { - auto current = first; - if (!current) - return false; + return &item->mDelegate; + } - Node_t* prev = nullptr; - do + bool remove(const Delegate* del) { - if (del == ¤t->mDelegate) + auto current = first; + if (!current) + return false; + + Node_t* prev = nullptr; + do { - // remove callback from stack + if (del == ¤t->mDelegate) + { + // remove callback from stack #ifdef ARDUINO - InterruptLock lockAllInterruptsInThisScope; + InterruptLock lockAllInterruptsInThisScope; #else - std::lock_guard lock(mutex_unused); + std::lock_guard lock(mutex_unused); #endif - auto to_recycle = current; - - // removing rLast - if (last == current) - last = prev; - - current = current->mNext; - if (prev) - { - prev->mNext = current; + auto to_recycle = current; + + // removing rLast + if (last == current) + last = prev; + + current = current->mNext; + if (prev) + { + prev->mNext = current; + } + else + { + first = current; + } + + if (ISQUEUE) + recycle_node_unsafe(to_recycle); + else + delete to_recycle; + return true; } else { - first = current; + prev = current; + current = current->mNext; } + } while (current); + return false; + } - if (ISQUEUE) - recycle_node_unsafe(to_recycle); - else - delete to_recycle; - return true; - } - else - { - prev = current; - current = current->mNext; - } - } while (current); - return false; - } - - void operator()(P... args) - { - auto current = first; - if (!current) - return; + void operator()(P... args) + { + auto current = first; + if (!current) + return; - static std::atomic fence(false); - // prevent recursive calls + static std::atomic fence(false); + // prevent recursive calls #if defined(ARDUINO) && !defined(ESP32) - if (fence.load()) return; - fence.store(true); + if (fence.load()) return; + fence.store(true); #else - if (fence.exchange(true)) return; + if (fence.exchange(true)) return; #endif - Node_t* prev = nullptr; - // prevent execution of new callbacks during this run - auto stop = last; + Node_t* prev = nullptr; + // prevent execution of new callbacks during this run + auto stop = last; - bool done; - do - { - done = current == stop; - if (!CallP::execute(current->mDelegate, args...)) + bool done; + do { - // remove callback from stack + done = current == stop; + if (!CallP::execute(current->mDelegate, args...)) + { + // remove callback from stack #ifdef ARDUINO - InterruptLock lockAllInterruptsInThisScope; + InterruptLock lockAllInterruptsInThisScope; #else - std::lock_guard lock(mutex_unused); + std::lock_guard lock(mutex_unused); #endif - auto to_recycle = current; - - // removing rLast - if (last == current) - last = prev; - - current = current->mNext; - if (prev) - { - prev->mNext = current; + auto to_recycle = current; + + // removing rLast + if (last == current) + last = prev; + + current = current->mNext; + if (prev) + { + prev->mNext = current; + } + else + { + first = current; + } + + if (ISQUEUE) + recycle_node_unsafe(to_recycle); + else + delete to_recycle; } else { - first = current; + prev = current; + current = current->mNext; } - if (ISQUEUE) - recycle_node_unsafe(to_recycle); - else - delete to_recycle; - } - else - { - prev = current; - current = current->mNext; - } - #if defined(ESP8266) || defined(ESP32) - // running callbacks might last too long for watchdog etc. - optimistic_yield(10000); + // running callbacks might last too long for watchdog etc. + optimistic_yield(10000); #endif - } while (current && !done); + } while (current && !done); - fence.store(false); - } - }; + fence.store(false); + } + }; - template< typename Delegate, typename R = void, bool ISQUEUE = false, size_t QUEUE_CAPACITY = 32> - class MultiDelegateImpl : public MultiDelegatePImpl - { - protected: - using typename MultiDelegatePImpl::Node_t; - using MultiDelegatePImpl::first; - using MultiDelegatePImpl::last; - using MultiDelegatePImpl::unused; - using MultiDelegatePImpl::nodeCount; - using MultiDelegatePImpl::recycle_node_unsafe; + template< typename Delegate, typename R = void, bool ISQUEUE = false, size_t QUEUE_CAPACITY = 32> + class MultiDelegateImpl : public MultiDelegatePImpl + { + protected: + using typename MultiDelegatePImpl::Node_t; + using MultiDelegatePImpl::first; + using MultiDelegatePImpl::last; + using MultiDelegatePImpl::unused; + using MultiDelegatePImpl::nodeCount; + using MultiDelegatePImpl::recycle_node_unsafe; #ifndef ARDUINO - using MultiDelegatePImpl::mutex_unused; + using MultiDelegatePImpl::mutex_unused; #endif - public: - using MultiDelegatePImpl::MultiDelegatePImpl; + public: + using MultiDelegatePImpl::MultiDelegatePImpl; - void operator()() - { - auto current = first; - if (!current) - return; + void operator()() + { + auto current = first; + if (!current) + return; - static std::atomic fence(false); - // prevent recursive calls + static std::atomic fence(false); + // prevent recursive calls #if defined(ARDUINO) && !defined(ESP32) - if (fence.load()) return; - fence.store(true); + if (fence.load()) return; + fence.store(true); #else - if (fence.exchange(true)) return; + if (fence.exchange(true)) return; #endif - Node_t* prev = nullptr; - // prevent execution of new callbacks during this run - auto stop = last; + Node_t* prev = nullptr; + // prevent execution of new callbacks during this run + auto stop = last; - bool done; - do - { - done = current == stop; - if (!Call::execute(current->mDelegate)) + bool done; + do { - // remove callback from stack + done = current == stop; + if (!Call::execute(current->mDelegate)) + { + // remove callback from stack #ifdef ARDUINO - InterruptLock lockAllInterruptsInThisScope; + InterruptLock lockAllInterruptsInThisScope; #else - std::lock_guard lock(mutex_unused); + std::lock_guard lock(mutex_unused); #endif - auto to_recycle = current; - - // removing rLast - if (last == current) - last = prev; - - current = current->mNext; - if (prev) - { - prev->mNext = current; + auto to_recycle = current; + + // removing rLast + if (last == current) + last = prev; + + current = current->mNext; + if (prev) + { + prev->mNext = current; + } + else + { + first = current; + } + + if (ISQUEUE) + recycle_node_unsafe(to_recycle); + else + delete to_recycle; } else { - first = current; + prev = current; + current = current->mNext; } - if (ISQUEUE) - recycle_node_unsafe(to_recycle); - else - delete to_recycle; - } - else - { - prev = current; - current = current->mNext; - } - #if defined(ESP8266) || defined(ESP32) - // running callbacks might last too long for watchdog etc. - optimistic_yield(10000); + // running callbacks might last too long for watchdog etc. + optimistic_yield(10000); #endif - } while (current && !done); + } while (current && !done); - fence.store(false); - } - }; + fence.store(false); + } + }; - template< typename Delegate, typename R, bool ISQUEUE, size_t QUEUE_CAPACITY, typename... P> class MultiDelegate; + template< typename Delegate, typename R, bool ISQUEUE, size_t QUEUE_CAPACITY, typename... P> class MultiDelegate; - template< typename Delegate, typename R, bool ISQUEUE, size_t QUEUE_CAPACITY, typename... P> - class MultiDelegate : public MultiDelegatePImpl - { - public: - using MultiDelegatePImpl::MultiDelegatePImpl; - }; + template< typename Delegate, typename R, bool ISQUEUE, size_t QUEUE_CAPACITY, typename... P> + class MultiDelegate : public MultiDelegatePImpl + { + public: + using MultiDelegatePImpl::MultiDelegatePImpl; + }; - template< typename Delegate, typename R, bool ISQUEUE, size_t QUEUE_CAPACITY> - class MultiDelegate : public MultiDelegateImpl - { - public: - using MultiDelegateImpl::MultiDelegateImpl; - }; -}; + template< typename Delegate, typename R, bool ISQUEUE, size_t QUEUE_CAPACITY> + class MultiDelegate : public MultiDelegateImpl + { + public: + using MultiDelegateImpl::MultiDelegateImpl; + }; + + } +} /** The MultiDelegate class template can be specialized to either a queue or an event multiplexer. @@ -494,10 +501,10 @@ It is designed to be used with Delegate, the efficient runtime wrapper for C fun instance during its own lifetime for efficiency. */ template< typename Delegate, bool ISQUEUE = false, size_t QUEUE_CAPACITY = 32> -class MultiDelegate : public detail::MultiDelegate +class MultiDelegate : public delegate::detail::MultiDelegate { public: - using detail::MultiDelegate::MultiDelegate; + using delegate::detail::MultiDelegate::MultiDelegate; }; #endif // __MULTIDELEGATE_H From e78885c503e1d65351d7558f4e3658772bfd59c0 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Wed, 22 Jan 2020 09:05:34 +0100 Subject: [PATCH 33/55] std::bind is IRAM cache save, lambda is not. --- cores/esp8266/Delegate.h | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/cores/esp8266/Delegate.h b/cores/esp8266/Delegate.h index 3789c67a01..d4b6a19dc8 100644 --- a/cores/esp8266/Delegate.h +++ b/cores/esp8266/Delegate.h @@ -36,18 +36,23 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "circular_queue/ghostl.h" #endif +namespace +{ + + template + R IRAM_ATTR vPtrToFunPtrExec(void* fn, P... args) + { + using target_type = R(P...); + return reinterpret_cast(fn)(std::forward(args...)); + } + +} + namespace delegate { namespace detail { - template - R IRAM_ATTR vPtrToFunPtrExec(void* fn, P... args) - { - using target_type = R(P...); - return reinterpret_cast(fn)(std::forward(args...)); - } - #if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) template class DelegatePImpl { From e3888ca345b5db64be410cc770e284a1b7ac782e Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Wed, 12 Feb 2020 20:34:27 +0100 Subject: [PATCH 34/55] Enhancements to MultiDelegate: event multiplexer mode no longer has auto-remove. Invoke returns result of last Delegate call. Caveat: breaks use of event multiplexer with auto-remove; WIP: add iterators. --- cores/esp8266/MultiDelegate.h | 248 +++++++++++++++++++++------------- 1 file changed, 157 insertions(+), 91 deletions(-) diff --git a/cores/esp8266/MultiDelegate.h b/cores/esp8266/MultiDelegate.h index 055078e216..bba8255972 100644 --- a/cores/esp8266/MultiDelegate.h +++ b/cores/esp8266/MultiDelegate.h @@ -1,7 +1,7 @@ /* MultiDelegate.h - A queue or event multiplexer based on the efficient Delegate class -Copyright (c) 2019 Dirk O. Kaar. All rights reserved. +Copyright (c) 2019-2020 Dirk O. Kaar. All rights reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -52,7 +52,7 @@ namespace { static R execute(Delegate& del, P... args) { - return del(std::forward(args...)) ? !ISQUEUE : ISQUEUE; + return del(std::forward(args...)); } }; @@ -62,7 +62,7 @@ namespace static bool execute(Delegate& del, P... args) { del(std::forward(args...)); - return !ISQUEUE; + return true; } }; @@ -71,7 +71,7 @@ namespace { static R execute(Delegate& del) { - return del() ? !ISQUEUE : ISQUEUE; + return del(); } }; @@ -81,7 +81,7 @@ namespace static bool execute(Delegate& del) { del(); - return !ISQUEUE; + return true; } }; @@ -92,7 +92,7 @@ namespace delegate namespace detail { - template< typename Delegate, typename R = void, bool ISQUEUE = false, size_t QUEUE_CAPACITY = 32, typename... P> + template< typename Delegate, typename R, bool ISQUEUE = false, size_t QUEUE_CAPACITY = 32, typename... P> class MultiDelegatePImpl { public: @@ -216,6 +216,42 @@ namespace delegate unused = node; } + void traverse(Node_t*& prev, Node_t*& current, bool remove = true) + { + if (remove && ISQUEUE) + { + // remove callback from stack +#ifdef ARDUINO + InterruptLock lockAllInterruptsInThisScope; +#else + std::lock_guard lock(mutex_unused); +#endif + + auto to_recycle = current; + + // removing last + if (last == current) + last = prev; + + current = current->mNext; + if (prev) + { + prev->mNext = current; + } + else + { + first = current; + } + + recycle_node_unsafe(to_recycle); + } + else + { + prev = current; + current = current->mNext; + } + } + #ifndef ARDUINO std::mutex mutex_unused; #endif @@ -277,7 +313,7 @@ namespace delegate auto to_recycle = current; - // removing rLast + // removing last if (last == current) last = prev; @@ -306,65 +342,37 @@ namespace delegate return false; } - void operator()(P... args) + operator bool() const + { + return first; + } + + R operator()(P... args) { auto current = first; if (!current) - return; + return {}; static std::atomic fence(false); // prevent recursive calls #if defined(ARDUINO) && !defined(ESP32) - if (fence.load()) return; + if (fence.load()) return {}; fence.store(true); #else - if (fence.exchange(true)) return; + if (fence.exchange(true)) return {}; #endif Node_t* prev = nullptr; // prevent execution of new callbacks during this run auto stop = last; + R result; bool done; do { done = current == stop; - if (!CallP::execute(current->mDelegate, args...)) - { - // remove callback from stack -#ifdef ARDUINO - InterruptLock lockAllInterruptsInThisScope; -#else - std::lock_guard lock(mutex_unused); -#endif - - auto to_recycle = current; - - // removing rLast - if (last == current) - last = prev; - - current = current->mNext; - if (prev) - { - prev->mNext = current; - } - else - { - first = current; - } - - if (ISQUEUE) - recycle_node_unsafe(to_recycle); - else - delete to_recycle; - } - else - { - prev = current; - current = current->mNext; - } - + result = CallP::execute(current->mDelegate, args...); + traverse(prev, current, result); #if defined(ESP8266) || defined(ESP32) // running callbacks might last too long for watchdog etc. optimistic_yield(10000); @@ -372,6 +380,7 @@ namespace delegate } while (current && !done); fence.store(false); + return result; } }; @@ -392,65 +401,32 @@ namespace delegate public: using MultiDelegatePImpl::MultiDelegatePImpl; - void operator()() + R operator()() { auto current = first; if (!current) - return; + return {}; static std::atomic fence(false); // prevent recursive calls #if defined(ARDUINO) && !defined(ESP32) - if (fence.load()) return; + if (fence.load()) return {}; fence.store(true); #else - if (fence.exchange(true)) return; + if (fence.exchange(true)) return {}; #endif Node_t* prev = nullptr; // prevent execution of new callbacks during this run auto stop = last; + R result; bool done; do { done = current == stop; - if (!Call::execute(current->mDelegate)) - { - // remove callback from stack -#ifdef ARDUINO - InterruptLock lockAllInterruptsInThisScope; -#else - std::lock_guard lock(mutex_unused); -#endif - - auto to_recycle = current; - - // removing rLast - if (last == current) - last = prev; - - current = current->mNext; - if (prev) - { - prev->mNext = current; - } - else - { - first = current; - } - - if (ISQUEUE) - recycle_node_unsafe(to_recycle); - else - delete to_recycle; - } - else - { - prev = current; - current = current->mNext; - } - + result = Call::execute(current->mDelegate); + this->traverse(prev, current, result); #if defined(ESP8266) || defined(ESP32) // running callbacks might last too long for watchdog etc. optimistic_yield(10000); @@ -458,6 +434,7 @@ namespace delegate } while (current && !done); fence.store(false); + return result; } }; @@ -477,7 +454,96 @@ namespace delegate using MultiDelegateImpl::MultiDelegateImpl; }; + template< typename Delegate, bool ISQUEUE, size_t QUEUE_CAPACITY, typename... P> + class MultiDelegate : public MultiDelegatePImpl + { + public: + using MultiDelegatePImpl::MultiDelegatePImpl; + using typename MultiDelegatePImpl::Node_t; + using MultiDelegatePImpl::first; + using MultiDelegatePImpl::last; + + void operator()(P... args) + { + auto current = first; + if (!current) + return; + + static std::atomic fence(false); + // prevent recursive calls +#if defined(ARDUINO) && !defined(ESP32) + if (fence.load()) return; + fence.store(true); +#else + if (fence.exchange(true)) return; +#endif + + Node_t* prev = nullptr; + // prevent execution of new callbacks during this run + auto stop = last; + + bool done; + do + { + done = current == stop; + CallP::execute(current->mDelegate, args...); + this->traverse(prev, current); +#if defined(ESP8266) || defined(ESP32) + // running callbacks might last too long for watchdog etc. + optimistic_yield(10000); +#endif + } while (current && !done); + + fence.store(false); + } + }; + + template< typename Delegate, bool ISQUEUE, size_t QUEUE_CAPACITY> + class MultiDelegate : public MultiDelegateImpl + { + public: + using MultiDelegateImpl::MultiDelegateImpl; + using typename MultiDelegateImpl::Node_t; + using MultiDelegateImpl::first; + using MultiDelegateImpl::last; + + void operator()() + { + auto current = first; + if (!current) + return; + + static std::atomic fence(false); + // prevent recursive calls +#if defined(ARDUINO) && !defined(ESP32) + if (fence.load()) return; + fence.store(true); +#else + if (fence.exchange(true)) return; +#endif + + Node_t* prev = nullptr; + // prevent execution of new callbacks during this run + auto stop = last; + + bool done; + do + { + done = current == stop; + Call::execute(current->mDelegate); + this->traverse(prev, current); +#if defined(ESP8266) || defined(ESP32) + // running callbacks might last too long for watchdog etc. + optimistic_yield(10000); +#endif + } while (current && !done); + + fence.store(false); + } + }; + } + } /** @@ -492,10 +558,10 @@ It is designed to be used with Delegate, the efficient runtime wrapper for C fun If the result type of the function call operator of Delegate is void, calling a MultiDelegate queue removes each item after calling it; a Multidelegate event multiplexer keeps event handlers until explicitly removed. - If the result type of the function call operator of Delegate is non-void, the type-conversion to bool - of that result determines if the item is immediately removed or kept after each call: a Multidelegate - queue removes an item only if true is returned, but a Multidelegate event multiplexer removes event - handlers that return false. + If the result type of the function call operator of Delegate is non-void, in a MultiDelegate queue + the type-conversion to bool of that result determines if the item is immediately removed or kept + after each call: if true is returned, the item is removed. A Multidelegate event multiplexer keeps event + handlers until they are explicitly removed. @tparam QUEUE_CAPACITY is only used if ISQUEUE == true. Then, it sets the maximum capacity that the queue dynamically allocates from the heap. Unused items are not returned to the heap, but are managed by the MultiDelegate instance during its own lifetime for efficiency. From 680abe154f4c914c653b1418a92dcc5d8dcd5229 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Wed, 12 Feb 2020 23:08:05 +0100 Subject: [PATCH 35/55] Added forward iterator and begin() and end() functions to MultiDelegate. WIP: remove() during iteration. --- cores/esp8266/MultiDelegate.h | 77 ++++++++++++++++++++++++++++++++--- 1 file changed, 72 insertions(+), 5 deletions(-) diff --git a/cores/esp8266/MultiDelegate.h b/cores/esp8266/MultiDelegate.h index bba8255972..a76ce771d5 100644 --- a/cores/esp8266/MultiDelegate.h +++ b/cores/esp8266/MultiDelegate.h @@ -21,6 +21,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #ifndef __MULTIDELEGATE_H #define __MULTIDELEGATE_H +#include #if defined(ESP8266) || defined(ESP32) || !defined(ARDUINO) #include #else @@ -216,6 +217,10 @@ namespace delegate unused = node; } + void traverse(Node_t*& current) const + { + current = current->mNext; + } void traverse(Node_t*& prev, Node_t*& current, bool remove = true) { if (remove && ISQUEUE) @@ -248,7 +253,7 @@ namespace delegate else { prev = current; - current = current->mNext; + traverse(current); } } @@ -256,6 +261,56 @@ namespace delegate std::mutex mutex_unused; #endif public: + class iterator : public std::iterator + { + protected: + MultiDelegatePImpl& multiDel; + Node_t* current = nullptr; + Node_t* const stop = nullptr; + public: + iterator(MultiDelegatePImpl& md) : multiDel(md), current(md.first), stop(md.last) {} + iterator(MultiDelegatePImpl& md, nullptr_t) : multiDel(md) {} + iterator() = default; + iterator(const iterator&) = default; + iterator& operator=(const iterator&) = default; + bool operator==(const iterator& rhs) const + { + return &multiDel == &rhs.multiDel && current == rhs.current; + } + bool operator!=(const iterator& rhs) const { + return !operator==(rhs); + } + const Delegate& operator*() const + { + return current->mDelegate; + } + const Delegate* const operator->() const + { + return ¤t->mDelegate; + } + iterator& operator++() // prefix + { + if (current && stop != current) + multiDel.traverse(current); + else + current = nullptr; // end + return *this; + } + iterator& operator++(int) // postfix + { + iterator tmp(*this); + operator++(); + return tmp; + } + }; + + iterator begin() const { + return iterator(*this); + } + iterator end() const { + return iterator(*this, nullptr); + } + const Delegate* IRAM_ATTR add(const Delegate& del) { return add(Delegate(del)); @@ -372,7 +427,10 @@ namespace delegate { done = current == stop; result = CallP::execute(current->mDelegate, args...); - traverse(prev, current, result); + if (ISQUEUE) + traverse(prev, current, result); + else + traverse(current); #if defined(ESP8266) || defined(ESP32) // running callbacks might last too long for watchdog etc. optimistic_yield(10000); @@ -426,7 +484,10 @@ namespace delegate { done = current == stop; result = Call::execute(current->mDelegate); - this->traverse(prev, current, result); + if (ISQUEUE) + this->traverse(prev, current, result); + else + this->traverse(current); #if defined(ESP8266) || defined(ESP32) // running callbacks might last too long for watchdog etc. optimistic_yield(10000); @@ -487,7 +548,10 @@ namespace delegate { done = current == stop; CallP::execute(current->mDelegate, args...); - this->traverse(prev, current); + if (ISQUEUE) + this->traverse(prev, current); + else + traverse(current); #if defined(ESP8266) || defined(ESP32) // running callbacks might last too long for watchdog etc. optimistic_yield(10000); @@ -531,7 +595,10 @@ namespace delegate { done = current == stop; Call::execute(current->mDelegate); - this->traverse(prev, current); + if (ISQUEUE) + this->traverse(prev, current); + else + this->traverse(current); #if defined(ESP8266) || defined(ESP32) // running callbacks might last too long for watchdog etc. optimistic_yield(10000); From 1f193ab57c66a839c21a3e9a7981acaa75cd2047 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Thu, 13 Feb 2020 10:52:43 +0100 Subject: [PATCH 36/55] Change to make MultiDelegate invoke and erase work off iterators. --- cores/esp8266/MultiDelegate.h | 231 +++++++++++----------------------- 1 file changed, 76 insertions(+), 155 deletions(-) diff --git a/cores/esp8266/MultiDelegate.h b/cores/esp8266/MultiDelegate.h index a76ce771d5..d47710fcd4 100644 --- a/cores/esp8266/MultiDelegate.h +++ b/cores/esp8266/MultiDelegate.h @@ -217,65 +217,29 @@ namespace delegate unused = node; } - void traverse(Node_t*& current) const - { - current = current->mNext; - } - void traverse(Node_t*& prev, Node_t*& current, bool remove = true) - { - if (remove && ISQUEUE) - { - // remove callback from stack -#ifdef ARDUINO - InterruptLock lockAllInterruptsInThisScope; -#else - std::lock_guard lock(mutex_unused); -#endif - - auto to_recycle = current; - - // removing last - if (last == current) - last = prev; - - current = current->mNext; - if (prev) - { - prev->mNext = current; - } - else - { - first = current; - } - - recycle_node_unsafe(to_recycle); - } - else - { - prev = current; - traverse(current); - } - } - #ifndef ARDUINO std::mutex mutex_unused; #endif public: class iterator : public std::iterator { - protected: - MultiDelegatePImpl& multiDel; - Node_t* current = nullptr; - Node_t* const stop = nullptr; public: - iterator(MultiDelegatePImpl& md) : multiDel(md), current(md.first), stop(md.last) {} - iterator(MultiDelegatePImpl& md, nullptr_t) : multiDel(md) {} + Node_t* current = nullptr; + Node_t* prev = nullptr; + const Node_t* stop = nullptr; + + iterator(MultiDelegatePImpl& md) : current(md.first), stop(md.last) {} iterator() = default; iterator(const iterator&) = default; iterator& operator=(const iterator&) = default; + iterator& operator=(iterator&&) = default; + operator bool() const + { + return current && stop; + } bool operator==(const iterator& rhs) const { - return &multiDel == &rhs.multiDel && current == rhs.current; + return current == rhs.current; } bool operator!=(const iterator& rhs) const { return !operator==(rhs); @@ -291,7 +255,10 @@ namespace delegate iterator& operator++() // prefix { if (current && stop != current) - multiDel.traverse(current); + { + prev = current; + current = current->mNext; + } else current = nullptr; // end return *this; @@ -304,11 +271,11 @@ namespace delegate } }; - iterator begin() const { + iterator begin() { return iterator(*this); } iterator end() const { - return iterator(*this, nullptr); + return iterator(); } const Delegate* IRAM_ATTR add(const Delegate& del) @@ -348,52 +315,47 @@ namespace delegate return &item->mDelegate; } - bool remove(const Delegate* del) + iterator erase(iterator it) { - auto current = first; - if (!current) - return false; - - Node_t* prev = nullptr; - do - { - if (del == ¤t->mDelegate) - { - // remove callback from stack + if (!it) + return end(); #ifdef ARDUINO - InterruptLock lockAllInterruptsInThisScope; + InterruptLock lockAllInterruptsInThisScope; #else - std::lock_guard lock(mutex_unused); + std::lock_guard lock(mutex_unused); #endif + auto to_recycle = it.current; - auto to_recycle = current; - - // removing last - if (last == current) - last = prev; + if (last == it.current) + last = it.prev; + it.current = it.current->mNext; + if (it.prev) + { + it.prev->mNext = it.current; + } + else + { + first = it.current; + } + if (ISQUEUE) + recycle_node_unsafe(to_recycle); + else + delete to_recycle; + return it; + } - current = current->mNext; - if (prev) - { - prev->mNext = current; - } - else - { - first = current; - } - - if (ISQUEUE) - recycle_node_unsafe(to_recycle); - else - delete to_recycle; - return true; - } - else + bool erase(const Delegate* const del) + { + auto it = begin(); + while (it) + { + if (del == &it.current->mDelegate) { - prev = current; - current = current->mNext; + erase(it); + return true; } - } while (current); + ++it; + } return false; } @@ -404,8 +366,8 @@ namespace delegate R operator()(P... args) { - auto current = first; - if (!current) + auto it = begin(); + if (!it) return {}; static std::atomic fence(false); @@ -417,25 +379,19 @@ namespace delegate if (fence.exchange(true)) return {}; #endif - Node_t* prev = nullptr; - // prevent execution of new callbacks during this run - auto stop = last; - R result; - bool done; do { - done = current == stop; - result = CallP::execute(current->mDelegate, args...); - if (ISQUEUE) - traverse(prev, current, result); + result = CallP::execute(it.current->mDelegate, args...); + if (result && ISQUEUE) + it = erase(it); else - traverse(current); + ++it; #if defined(ESP8266) || defined(ESP32) // running callbacks might last too long for watchdog etc. optimistic_yield(10000); #endif - } while (current && !done); + } while (it); fence.store(false); return result; @@ -445,24 +401,13 @@ namespace delegate template< typename Delegate, typename R = void, bool ISQUEUE = false, size_t QUEUE_CAPACITY = 32> class MultiDelegateImpl : public MultiDelegatePImpl { - protected: - using typename MultiDelegatePImpl::Node_t; - using MultiDelegatePImpl::first; - using MultiDelegatePImpl::last; - using MultiDelegatePImpl::unused; - using MultiDelegatePImpl::nodeCount; - using MultiDelegatePImpl::recycle_node_unsafe; -#ifndef ARDUINO - using MultiDelegatePImpl::mutex_unused; -#endif - public: using MultiDelegatePImpl::MultiDelegatePImpl; R operator()() { - auto current = first; - if (!current) + auto it = this->begin(); + if (!it) return {}; static std::atomic fence(false); @@ -474,25 +419,19 @@ namespace delegate if (fence.exchange(true)) return {}; #endif - Node_t* prev = nullptr; - // prevent execution of new callbacks during this run - auto stop = last; - R result; - bool done; do { - done = current == stop; - result = Call::execute(current->mDelegate); - if (ISQUEUE) - this->traverse(prev, current, result); + result = Call::execute(it.current->mDelegate); + if (result && ISQUEUE) + it = this->erase(it); else - this->traverse(current); + ++it; #if defined(ESP8266) || defined(ESP32) // running callbacks might last too long for watchdog etc. optimistic_yield(10000); #endif - } while (current && !done); + } while (it); fence.store(false); return result; @@ -520,14 +459,11 @@ namespace delegate { public: using MultiDelegatePImpl::MultiDelegatePImpl; - using typename MultiDelegatePImpl::Node_t; - using MultiDelegatePImpl::first; - using MultiDelegatePImpl::last; void operator()(P... args) { - auto current = first; - if (!current) + auto it = this->begin(); + if (!it) return; static std::atomic fence(false); @@ -539,24 +475,18 @@ namespace delegate if (fence.exchange(true)) return; #endif - Node_t* prev = nullptr; - // prevent execution of new callbacks during this run - auto stop = last; - - bool done; do { - done = current == stop; - CallP::execute(current->mDelegate, args...); + CallP::execute(it.current->mDelegate, args...); if (ISQUEUE) - this->traverse(prev, current); + it = this->erase(it); else - traverse(current); + ++it; #if defined(ESP8266) || defined(ESP32) // running callbacks might last too long for watchdog etc. optimistic_yield(10000); #endif - } while (current && !done); + } while (it); fence.store(false); } @@ -567,14 +497,11 @@ namespace delegate { public: using MultiDelegateImpl::MultiDelegateImpl; - using typename MultiDelegateImpl::Node_t; - using MultiDelegateImpl::first; - using MultiDelegateImpl::last; void operator()() { - auto current = first; - if (!current) + auto it = this->begin(); + if (!it) return; static std::atomic fence(false); @@ -586,24 +513,18 @@ namespace delegate if (fence.exchange(true)) return; #endif - Node_t* prev = nullptr; - // prevent execution of new callbacks during this run - auto stop = last; - - bool done; do { - done = current == stop; - Call::execute(current->mDelegate); + Call::execute(it.current->mDelegate); if (ISQUEUE) - this->traverse(prev, current); + it = this->erase(it); else - this->traverse(current); + ++it; #if defined(ESP8266) || defined(ESP32) // running callbacks might last too long for watchdog etc. optimistic_yield(10000); #endif - } while (current && !done); + } while (it); fence.store(false); } From 57a87ca97f463b1b1e7f3d722636d3f8f44c8375 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Thu, 13 Feb 2020 12:38:01 +0100 Subject: [PATCH 37/55] Constness fix for iterator dereference --- cores/esp8266/MultiDelegate.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cores/esp8266/MultiDelegate.h b/cores/esp8266/MultiDelegate.h index d47710fcd4..918d59b8dd 100644 --- a/cores/esp8266/MultiDelegate.h +++ b/cores/esp8266/MultiDelegate.h @@ -244,11 +244,11 @@ namespace delegate bool operator!=(const iterator& rhs) const { return !operator==(rhs); } - const Delegate& operator*() const + Delegate& operator*() const { return current->mDelegate; } - const Delegate* const operator->() const + Delegate* const operator->() const { return ¤t->mDelegate; } @@ -349,7 +349,7 @@ namespace delegate auto it = begin(); while (it) { - if (del == &it.current->mDelegate) + if (del == &(*it)) { erase(it); return true; @@ -382,7 +382,7 @@ namespace delegate R result; do { - result = CallP::execute(it.current->mDelegate, args...); + result = CallP::execute(*it, args...); if (result && ISQUEUE) it = erase(it); else @@ -422,7 +422,7 @@ namespace delegate R result; do { - result = Call::execute(it.current->mDelegate); + result = Call::execute(*it); if (result && ISQUEUE) it = this->erase(it); else @@ -477,7 +477,7 @@ namespace delegate do { - CallP::execute(it.current->mDelegate, args...); + CallP::execute(*it, args...); if (ISQUEUE) it = this->erase(it); else @@ -515,7 +515,7 @@ namespace delegate do { - Call::execute(it.current->mDelegate); + Call::execute(*it); if (ISQUEUE) it = this->erase(it); else From 960c8f5784671e6a970f5ca4f45be0fcaa861915 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Thu, 13 Feb 2020 22:26:09 +0100 Subject: [PATCH 38/55] constness on return type warning fix. --- cores/esp8266/MultiDelegate.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/cores/esp8266/MultiDelegate.h b/cores/esp8266/MultiDelegate.h index 918d59b8dd..36cbd94b6d 100644 --- a/cores/esp8266/MultiDelegate.h +++ b/cores/esp8266/MultiDelegate.h @@ -241,14 +241,15 @@ namespace delegate { return current == rhs.current; } - bool operator!=(const iterator& rhs) const { + bool operator!=(const iterator& rhs) const + { return !operator==(rhs); } Delegate& operator*() const { return current->mDelegate; } - Delegate* const operator->() const + Delegate* operator->() const { return ¤t->mDelegate; } @@ -271,10 +272,12 @@ namespace delegate } }; - iterator begin() { + iterator begin() + { return iterator(*this); } - iterator end() const { + iterator end() const + { return iterator(); } From 3cd6b913cd8be75556531a8ebe9c70c615ad32e2 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Tue, 25 Feb 2020 15:33:47 +0100 Subject: [PATCH 39/55] Conform to C++ 17 and later. --- cores/esp8266/Delegate.h | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/cores/esp8266/Delegate.h b/cores/esp8266/Delegate.h index d4b6a19dc8..ed7da67747 100644 --- a/cores/esp8266/Delegate.h +++ b/cores/esp8266/Delegate.h @@ -1666,12 +1666,13 @@ namespace delegate using detail::DelegatePImpl::DelegatePImpl; using detail::DelegatePImpl::operator=; using detail::DelegatePImpl::operator bool; - using detail::DelegatePImpl::operator FunVPPtr; using detail::DelegatePImpl::arg; + using detail::DelegatePImpl::operator(); + + operator FunVPPtr() { return detail::DelegatePImpl::operator FunVPPtr(); } #if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) - using detail::DelegatePImpl::operator FunctionType; + operator FunctionType() { return detail::DelegatePImpl::operator FunctionType(); } #endif - using detail::DelegatePImpl::operator(); }; template @@ -1687,10 +1688,8 @@ namespace delegate using detail::DelegatePImpl::DelegatePImpl; using detail::DelegatePImpl::operator=; using detail::DelegatePImpl::operator bool; -#if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) - using detail::DelegatePImpl::operator FunctionType; -#endif using detail::DelegatePImpl::operator(); + operator FunVPPtr() const { if (detail::DelegatePImpl::FPA == detail::DelegatePImpl::kind) @@ -1702,6 +1701,9 @@ namespace delegate return detail::DelegatePImpl::operator FunVPPtr(); } } +#if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) + operator FunctionType() { return detail::DelegatePImpl::operator FunctionType(); } +#endif void* arg() const { if (detail::DelegatePImpl::FPA == detail::DelegatePImpl::kind) @@ -1728,12 +1730,13 @@ namespace delegate using detail::DelegateImpl::DelegateImpl; using detail::DelegateImpl::operator=; using detail::DelegateImpl::operator bool; - using detail::DelegateImpl::operator FunVPPtr; using detail::DelegateImpl::arg; + using detail::DelegateImpl::operator(); + + operator FunVPPtr() { return detail::DelegateImpl::operator FunVPPtr(); } #if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) - using detail::DelegateImpl::operator FunctionType; + operator FunctionType() { return detail::DelegateImpl::operator FunctionType(); } #endif - using detail::DelegateImpl::operator(); }; template @@ -1749,10 +1752,8 @@ namespace delegate using detail::DelegateImpl::DelegateImpl; using detail::DelegateImpl::operator=; using detail::DelegateImpl::operator bool; -#if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) - using detail::DelegateImpl::operator FunctionType; -#endif using detail::DelegateImpl::operator(); + operator FunVPPtr() const { if (detail::DelegateImpl::FPA == detail::DelegateImpl::kind) @@ -1764,6 +1765,9 @@ namespace delegate return detail::DelegateImpl::operator FunVPPtr(); } } +#if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) + operator FunctionType() { return detail::DelegateImpl::operator FunctionType(); } +#endif void* arg() const { if (detail::DelegateImpl::FPA == detail::DelegateImpl::kind) From 64b06ec7743fbd629ccba72895b7b44b72d72f7c Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Tue, 25 Feb 2020 19:03:57 +0100 Subject: [PATCH 40/55] Resolve g++ 9's c++17 deprecation warnings. --- cores/esp8266/Delegate.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cores/esp8266/Delegate.h b/cores/esp8266/Delegate.h index ed7da67747..9032c1a9c6 100644 --- a/cores/esp8266/Delegate.h +++ b/cores/esp8266/Delegate.h @@ -1789,11 +1789,13 @@ template class Delegate : pub { public: using delegate::detail::Delegate::Delegate; + using delegate::detail::Delegate::operator=; }; template class Delegate : public delegate::detail::Delegate { public: using delegate::detail::Delegate::Delegate; + using delegate::detail::Delegate::operator=; }; #endif // __Delegate_h From 3b7f2c7622bc40bcc0a57be6853ae800c112bf86 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Fri, 28 Feb 2020 17:54:12 +0100 Subject: [PATCH 41/55] gcc 9.2 is very strict about template inheritance of ctor and assignment operators, needing a lot of code duplication, this commit provides that. --- cores/esp8266/Delegate.h | 393 +++++++++++++++++++++++++++++++++++---- 1 file changed, 353 insertions(+), 40 deletions(-) diff --git a/cores/esp8266/Delegate.h b/cores/esp8266/Delegate.h index 9032c1a9c6..829a4ed58e 100644 --- a/cores/esp8266/Delegate.h +++ b/cores/esp8266/Delegate.h @@ -1653,18 +1653,19 @@ namespace delegate }; #endif - template + template class Delegate : private detail::DelegatePImpl { - private: - using typename detail::DelegatePImpl::FunVPPtr; + public: + using target_type = R(P...); + protected: + using FunPtr = target_type*; + using FunAPtr = R(*)(A, P...); + using FunVPPtr = R(*)(void*, P...); #if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) - using typename detail::DelegatePImpl::FunctionType; + using FunctionType = std::function; #endif public: - using detail::DelegatePImpl::target_type; - using detail::DelegatePImpl::DelegatePImpl; - using detail::DelegatePImpl::operator=; using detail::DelegatePImpl::operator bool; using detail::DelegatePImpl::arg; using detail::DelegatePImpl::operator(); @@ -1673,20 +1674,57 @@ namespace delegate #if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) operator FunctionType() { return detail::DelegatePImpl::operator FunctionType(); } #endif + + Delegate() : detail::DelegatePImpl::DelegatePImpl() {} + + Delegate(std::nullptr_t) : detail::DelegatePImpl::DelegatePImpl(nullptr) {} + + Delegate(const detail::DelegatePImpl& del) : detail::DelegatePImpl::DelegatePImpl(del) {} + + Delegate(detail::DelegatePImpl&& del) : detail::DelegatePImpl::DelegatePImpl(std::move(del)) {} + + Delegate(FunAPtr fnA, const A& obj) : detail::DelegatePImpl::DelegatePImpl(fnA, obj) {} + + Delegate(FunAPtr fnA, A&& obj) : detail::DelegatePImpl::DelegatePImpl(fnA, std::move(obj)) {} + + Delegate(FunPtr fn) : detail::DelegatePImpl::DelegatePImpl(fn) {} + + template Delegate(F functional) : detail::DelegatePImpl::DelegatePImpl(functional) {} + + Delegate& operator=(const detail::DelegatePImpl& del) { + detail::DelegatePImpl::operator=(del); + return *this; + } + + Delegate& operator=(detail::DelegatePImpl&& del) { + detail::DelegatePImpl::operator=(std::move(del)); + return *this; + } + + Delegate& operator=(FunPtr fn) { + detail::DelegatePImpl::operator=(fn); + return *this; + } + + Delegate& IRAM_ATTR operator=(std::nullptr_t) { + detail::DelegatePImpl::operator=(nullptr); + return *this; + } }; - template - class Delegate : private detail::DelegatePImpl + template + class Delegate : private detail::DelegatePImpl { - private: - using typename detail::DelegatePImpl::FunVPPtr; + public: + using target_type = R(P...); + protected: + using FunPtr = target_type*; + using FunAPtr = R(*)(A*, P...); + using FunVPPtr = R(*)(void*, P...); #if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) - using typename detail::DelegatePImpl::FunctionType; + using FunctionType = std::function; #endif public: - using detail::DelegatePImpl::target_type; - using detail::DelegatePImpl::DelegatePImpl; - using detail::DelegatePImpl::operator=; using detail::DelegatePImpl::operator bool; using detail::DelegatePImpl::operator(); @@ -1694,7 +1732,7 @@ namespace delegate { if (detail::DelegatePImpl::FPA == detail::DelegatePImpl::kind) { - return reinterpret_cast(detail::DelegatePImpl::fnA); + return reinterpret_cast(detail::DelegatePImpl::fnA); } else { @@ -1715,20 +1753,109 @@ namespace delegate return detail::DelegatePImpl::arg(); } } + + Delegate() : detail::DelegatePImpl::DelegatePImpl() {} + + Delegate(std::nullptr_t) : detail::DelegatePImpl::DelegatePImpl(nullptr) {} + + Delegate(const detail::DelegatePImpl& del) : detail::DelegatePImpl::DelegatePImpl(del) {} + + Delegate(detail::DelegatePImpl&& del) : detail::DelegatePImpl::DelegatePImpl(std::move(del)) {} + + Delegate(FunAPtr fnA, A* obj) : detail::DelegatePImpl::DelegatePImpl(fnA, obj) {} + + Delegate(FunPtr fn) : detail::DelegatePImpl::DelegatePImpl(fn) {} + + template Delegate(F functional) : detail::DelegatePImpl::DelegatePImpl(functional) {} + + Delegate& operator=(const detail::DelegatePImpl& del) { + detail::DelegatePImpl::operator=(del); + return *this; + } + + Delegate& operator=(detail::DelegatePImpl&& del) { + detail::DelegatePImpl::operator=(std::move(del)); + return *this; + } + + Delegate& operator=(FunPtr fn) { + detail::DelegatePImpl::operator=(fn); + return *this; + } + + Delegate& IRAM_ATTR operator=(std::nullptr_t) { + detail::DelegatePImpl::operator=(nullptr); + return *this; + } + }; + + template + class Delegate : private detail::DelegatePImpl + { + public: + using target_type = R(P...); + protected: + using FunPtr = target_type*; +#if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) + using FunctionType = std::function; +#endif + using FunVPPtr = R(*)(void*, P...); + public: + using detail::DelegatePImpl::operator bool; + using detail::DelegatePImpl::arg; + using detail::DelegatePImpl::operator(); + + operator FunVPPtr() const { return detail::DelegatePImpl::operator FunVPPtr(); } +#if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) + operator FunctionType() { return detail::DelegatePImpl::operator FunctionType(); } +#endif + + Delegate() : detail::DelegatePImpl::DelegatePImpl() {} + + Delegate(std::nullptr_t) : detail::DelegatePImpl::DelegatePImpl(nullptr) {} + + Delegate(detail::DelegatePImpl& del) : detail::DelegatePImpl::DelegatePImpl(del) {} + + Delegate(detail::DelegatePImpl&& del) : detail::DelegatePImpl::DelegatePImpl(std::move(del)) {} + + Delegate(FunPtr fn) : detail::DelegatePImpl::DelegatePImpl(fn) {} + + template Delegate(F functional) : detail::DelegatePImpl::DelegatePImpl(functional) {} + + Delegate& operator=(const detail::DelegatePImpl& del) { + detail::DelegatePImpl::operator=(del); + return *this; + } + + Delegate& operator=(detail::DelegatePImpl&& del) { + detail::DelegatePImpl::operator=(std::move(del)); + return *this; + } + + Delegate& operator=(FunPtr fn) { + detail::DelegatePImpl::operator=(fn); + return *this; + } + + Delegate& IRAM_ATTR operator=(std::nullptr_t) { + detail::DelegatePImpl::operator=(nullptr); + return *this; + } }; - template - class Delegate : private detail::DelegateImpl + template + class Delegate : private detail::DelegateImpl { - private: - using typename detail::DelegateImpl::FunVPPtr; + public: + using target_type = R(); + protected: + using FunPtr = target_type*; + using FunAPtr = R(*)(A); + using FunVPPtr = R(*)(void*); #if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) - using typename detail::DelegateImpl::FunctionType; + using FunctionType = std::function; #endif public: - using detail::DelegateImpl::target_type; - using detail::DelegateImpl::DelegateImpl; - using detail::DelegateImpl::operator=; using detail::DelegateImpl::operator bool; using detail::DelegateImpl::arg; using detail::DelegateImpl::operator(); @@ -1737,20 +1864,57 @@ namespace delegate #if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) operator FunctionType() { return detail::DelegateImpl::operator FunctionType(); } #endif + + Delegate() : detail::DelegateImpl::DelegateImpl() {} + + Delegate(std::nullptr_t) : detail::DelegateImpl::DelegateImpl(nullptr) {} + + Delegate(const detail::DelegateImpl& del) : detail::DelegateImpl::DelegateImpl(del) {} + + Delegate(detail::DelegateImpl&& del) : detail::DelegateImpl::DelegateImpl(std::move(del)) {} + + Delegate(FunAPtr fnA, const A& obj) : detail::DelegateImpl::DelegateImpl(fnA, obj) {} + + Delegate(FunAPtr fnA, A&& obj) : detail::DelegateImpl::DelegateImpl(fnA, std::move(obj)) {} + + Delegate(FunPtr fn) : detail::DelegateImpl::DelegateImpl(fn) {} + + template Delegate(F functional) : detail::DelegateImpl::DelegateImpl(functional) {} + + Delegate& operator=(const detail::DelegateImpl& del) { + detail::DelegateImpl::operator=(del); + return *this; + } + + Delegate& operator=(detail::DelegateImpl&& del) { + detail::DelegateImpl::operator=(std::move(del)); + return *this; + } + + Delegate& operator=(FunPtr fn) { + detail::DelegateImpl::operator=(fn); + return *this; + } + + Delegate& IRAM_ATTR operator=(std::nullptr_t) { + detail::DelegateImpl::operator=(nullptr); + return *this; + } }; - template - class Delegate : private detail::DelegateImpl + template + class Delegate : private detail::DelegateImpl { - private: - using typename detail::DelegateImpl::FunVPPtr; + public: + using target_type = R(); + protected: + using FunPtr = target_type*; + using FunAPtr = R(*)(A*); + using FunVPPtr = R(*)(void*); #if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) - using typename detail::DelegateImpl::FunctionType; + using FunctionType = std::function; #endif public: - using detail::DelegateImpl::target_type; - using detail::DelegateImpl::DelegateImpl; - using detail::DelegateImpl::operator=; using detail::DelegateImpl::operator bool; using detail::DelegateImpl::operator(); @@ -1758,7 +1922,7 @@ namespace delegate { if (detail::DelegateImpl::FPA == detail::DelegateImpl::kind) { - return reinterpret_cast(detail::DelegateImpl::fnA); + return reinterpret_cast(detail::DelegateImpl::fnA); } else { @@ -1779,23 +1943,172 @@ namespace delegate return detail::DelegateImpl::arg(); } } + + Delegate() : detail::DelegateImpl::DelegateImpl() {} + + Delegate(std::nullptr_t) : detail::DelegateImpl::DelegateImpl(nullptr) {} + + Delegate(const detail::DelegateImpl& del) : detail::DelegateImpl::DelegateImpl(del) {} + + Delegate(detail::DelegateImpl&& del) : detail::DelegateImpl::DelegateImpl(std::move(del)) {} + + Delegate(FunAPtr fnA, A* obj) : detail::DelegateImpl::DelegateImpl(fnA, obj) {} + + Delegate(FunPtr fn) : detail::DelegateImpl::DelegateImpl(fn) {} + + template Delegate(F functional) : detail::DelegateImpl::DelegateImpl(functional) {} + + Delegate& operator=(const detail::DelegateImpl& del) { + detail::DelegateImpl::operator=(del); + return *this; + } + + Delegate& operator=(detail::DelegateImpl&& del) { + detail::DelegateImpl::operator=(std::move(del)); + return *this; + } + + Delegate& operator=(FunPtr fn) { + detail::DelegateImpl::operator=(fn); + return *this; + } + + Delegate& IRAM_ATTR operator=(std::nullptr_t) { + detail::DelegateImpl::operator=(nullptr); + return *this; + } }; + template + class Delegate : private detail::DelegateImpl + { + public: + using target_type = R(); + protected: + using FunPtr = target_type*; +#if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) + using FunctionType = std::function; +#endif + using FunVPPtr = R(*)(void*); + public: + using detail::DelegateImpl::operator bool; + using detail::DelegateImpl::arg; + using detail::DelegateImpl::operator(); + + operator FunVPPtr() const { return detail::DelegateImpl::operator FunVPPtr(); } +#if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) + operator FunctionType() { return detail::DelegateImpl::operator FunctionType(); } +#endif + + Delegate() : detail::DelegateImpl::DelegateImpl() {} + + Delegate(std::nullptr_t) : detail::DelegateImpl::DelegateImpl(nullptr) {} + + Delegate(const detail::DelegateImpl& del) : detail::DelegateImpl::DelegateImpl(del) {} + + Delegate(detail::DelegateImpl&& del) : detail::DelegateImpl::DelegateImpl(std::move(del)) {} + + Delegate(FunPtr fn) : detail::DelegateImpl::DelegateImpl(fn) {} + + template Delegate(F functional) : detail::DelegateImpl::DelegateImpl(functional) {} + + Delegate& operator=(const detail::DelegateImpl& del) { + detail::DelegateImpl::operator=(del); + return *this; + } + + Delegate& operator=(detail::DelegateImpl&& del) { + detail::DelegateImpl::operator=(std::move(del)); + return *this; + } + + Delegate& operator=(FunPtr fn) { + detail::DelegateImpl::operator=(fn); + return *this; + } + + Delegate& IRAM_ATTR operator=(std::nullptr_t) { + detail::DelegateImpl::operator=(nullptr); + return *this; + } + }; } } -template class Delegate; -template class Delegate : public delegate::detail::Delegate +template class Delegate; +template class Delegate : public delegate::detail::Delegate { public: - using delegate::detail::Delegate::Delegate; - using delegate::detail::Delegate::operator=; + Delegate() : delegate::detail::Delegate::Delegate() {} + + Delegate(std::nullptr_t) : delegate::detail::Delegate::Delegate(nullptr) {} + + Delegate(const delegate::detail::Delegate& del) : delegate::detail::Delegate::Delegate(del) {} + + Delegate(delegate::detail::Delegate&& del) : delegate::detail::Delegate::Delegate(std::move(del)) {} + + Delegate(typename delegate::detail::Delegate::FunAPtr fnA, const A& obj) : delegate::detail::Delegate::Delegate(fnA, obj) {} + + Delegate(typename delegate::detail::Delegate::FunAPtr fnA, A&& obj) : delegate::detail::Delegate::Delegate(fnA, std::move(obj)) {} + + Delegate(typename delegate::detail::Delegate::FunPtr fn) : delegate::detail::Delegate::Delegate(fn) {} + + template Delegate(F functional) : delegate::detail::Delegate::Delegate(functional) {} + + Delegate& operator=(const delegate::detail::Delegate& del) { + delegate::detail::Delegate::operator=(del); + return *this; + } + + Delegate& operator=(delegate::detail::Delegate&& del) { + delegate::detail::Delegate::operator=(std::move(del)); + return *this; + } + + Delegate& operator=(typename delegate::detail::Delegate::FunPtr fn) { + delegate::detail::Delegate::operator=(fn); + return *this; + } + + Delegate& IRAM_ATTR operator=(std::nullptr_t) { + delegate::detail::Delegate::operator=(nullptr); + return *this; + } }; -template class Delegate : public delegate::detail::Delegate +template class Delegate : public delegate::detail::Delegate { public: - using delegate::detail::Delegate::Delegate; - using delegate::detail::Delegate::operator=; + Delegate() : delegate::detail::Delegate::Delegate() {} + + Delegate(std::nullptr_t) : delegate::detail::Delegate::Delegate(nullptr) {} + + Delegate(const delegate::detail::Delegate& del) : delegate::detail::Delegate::Delegate(del) {} + + Delegate(delegate::detail::Delegate&& del) : delegate::detail::Delegate::Delegate(std::move(del)) {} + + Delegate(typename delegate::detail::Delegate::FunPtr fn) : delegate::detail::Delegate::Delegate(fn) {} + + template Delegate(F functional) : delegate::detail::Delegate::Delegate(functional) {} + + Delegate& operator=(const delegate::detail::Delegate& del) { + delegate::detail::Delegate::operator=(del); + return *this; + } + + Delegate& operator=(delegate::detail::Delegate&& del) { + delegate::detail::Delegate::operator=(std::move(del)); + return *this; + } + + Delegate& operator=(typename delegate::detail::Delegate::FunPtr fn) { + delegate::detail::Delegate::operator=(fn); + return *this; + } + + Delegate& IRAM_ATTR operator=(std::nullptr_t) { + delegate::detail::Delegate::operator=(nullptr); + return *this; + } }; #endif // __Delegate_h From 6e17563aa098eb99033c6faaf5ac6d018439a425 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Sun, 1 Mar 2020 17:49:29 +0100 Subject: [PATCH 42/55] Fix both ambiguous operator= and infinite ctor recursion. --- cores/esp8266/Delegate.h | 144 ++++++++++++++++++++++----------------- 1 file changed, 80 insertions(+), 64 deletions(-) diff --git a/cores/esp8266/Delegate.h b/cores/esp8266/Delegate.h index 829a4ed58e..613b495d2a 100644 --- a/cores/esp8266/Delegate.h +++ b/cores/esp8266/Delegate.h @@ -84,7 +84,7 @@ namespace delegate obj.~A(); } - DelegatePImpl(const DelegatePImpl& del) + DelegatePImpl(const DelegatePImpl& del) { kind = del.kind; if (FUNC == del.kind) @@ -102,7 +102,7 @@ namespace delegate } } - DelegatePImpl(DelegatePImpl&& del) + DelegatePImpl(DelegatePImpl&& del) { kind = del.kind; if (FUNC == del.kind) @@ -146,7 +146,7 @@ namespace delegate new (&this->functional) FunctionType(std::forward(functional)); } - DelegatePImpl& operator=(const DelegatePImpl& del) + DelegatePImpl& operator=(const DelegatePImpl& del) { if (this == &del) return *this; if (kind != del.kind) @@ -185,7 +185,7 @@ namespace delegate return *this; } - DelegatePImpl& operator=(DelegatePImpl&& del) + DelegatePImpl& operator=(DelegatePImpl&& del) { if (this == &del) return *this; if (kind != del.kind) @@ -373,7 +373,7 @@ namespace delegate fn = nullptr; } - DelegatePImpl(const DelegatePImpl& del) + DelegatePImpl(const DelegatePImpl& del) { kind = del.kind; if (FPA == del.kind) @@ -387,7 +387,7 @@ namespace delegate } } - DelegatePImpl(DelegatePImpl&& del) + DelegatePImpl(DelegatePImpl&& del) { kind = del.kind; if (FPA == del.kind) @@ -427,7 +427,7 @@ namespace delegate DelegatePImpl::fn = std::forward(fn); } - DelegatePImpl& operator=(const DelegatePImpl& del) + DelegatePImpl& operator=(const DelegatePImpl& del) { if (this == &del) return *this; if (kind != del.kind) @@ -450,7 +450,7 @@ namespace delegate return *this; } - DelegatePImpl& operator=(DelegatePImpl&& del) + DelegatePImpl& operator=(DelegatePImpl&& del) { if (this == &del) return *this; if (kind != del.kind) @@ -588,7 +588,7 @@ namespace delegate functional.~FunctionType(); } - DelegatePImpl(const DelegatePImpl& del) + DelegatePImpl(const DelegatePImpl& del) { kind = del.kind; if (FUNC == del.kind) @@ -601,7 +601,7 @@ namespace delegate } } - DelegatePImpl(DelegatePImpl&& del) + DelegatePImpl(DelegatePImpl&& del) { kind = del.kind; if (FUNC == del.kind) @@ -626,7 +626,7 @@ namespace delegate new (&this->functional) FunctionType(std::forward(functional)); } - DelegatePImpl& operator=(const DelegatePImpl& del) + DelegatePImpl& operator=(const DelegatePImpl& del) { if (this == &del) return *this; if (FUNC == kind && FUNC != del.kind) @@ -649,7 +649,7 @@ namespace delegate return *this; } - DelegatePImpl& operator=(DelegatePImpl&& del) + DelegatePImpl& operator=(DelegatePImpl&& del) { if (this == &del) return *this; if (FUNC == kind && FUNC != del.kind) @@ -783,12 +783,12 @@ namespace delegate fn = nullptr; } - DelegatePImpl(const DelegatePImpl& del) + DelegatePImpl(const DelegatePImpl& del) { fn = del.fn; } - DelegatePImpl(DelegatePImpl&& del) + DelegatePImpl(DelegatePImpl&& del) { fn = std::move(del.fn); } @@ -803,14 +803,14 @@ namespace delegate DelegatePImpl::fn = std::forward(fn); } - DelegatePImpl& operator=(const DelegatePImpl& del) + DelegatePImpl& operator=(const DelegatePImpl& del) { if (this == &del) return *this; fn = del.fn; return *this; } - DelegatePImpl& operator=(DelegatePImpl&& del) + DelegatePImpl& operator=(DelegatePImpl&& del) { if (this == &del) return *this; fn = std::move(del.fn); @@ -885,7 +885,7 @@ namespace delegate obj.~A(); } - DelegateImpl(const DelegateImpl& del) + DelegateImpl(const DelegateImpl& del) { kind = del.kind; if (FUNC == del.kind) @@ -903,7 +903,7 @@ namespace delegate } } - DelegateImpl(DelegateImpl&& del) + DelegateImpl(DelegateImpl&& del) { kind = del.kind; if (FUNC == del.kind) @@ -947,7 +947,7 @@ namespace delegate new (&this->functional) FunctionType(std::forward(functional)); } - DelegateImpl& operator=(const DelegateImpl& del) + DelegateImpl& operator=(const DelegateImpl& del) { if (this == &del) return *this; if (kind != del.kind) @@ -986,7 +986,7 @@ namespace delegate return *this; } - DelegateImpl& operator=(DelegateImpl&& del) + DelegateImpl& operator=(DelegateImpl&& del) { if (this == &del) return *this; if (kind != del.kind) @@ -1173,7 +1173,7 @@ namespace delegate fn = nullptr; } - DelegateImpl(const DelegateImpl& del) + DelegateImpl(const DelegateImpl& del) { kind = del.kind; if (FPA == del.kind) @@ -1187,7 +1187,7 @@ namespace delegate } } - DelegateImpl(DelegateImpl&& del) + DelegateImpl(DelegateImpl&& del) { kind = del.kind; if (FPA == del.kind) @@ -1227,7 +1227,7 @@ namespace delegate DelegateImpl::fn = std::forward(fn); } - DelegateImpl& operator=(const DelegateImpl& del) + DelegateImpl& operator=(const DelegateImpl& del) { if (this == &del) return *this; if (kind != del.kind) @@ -1250,7 +1250,7 @@ namespace delegate return *this; } - DelegateImpl& operator=(DelegateImpl&& del) + DelegateImpl& operator=(DelegateImpl&& del) { if (this == &del) return *this; if (kind != del.kind) @@ -1387,7 +1387,7 @@ namespace delegate functional.~FunctionType(); } - DelegateImpl(const DelegateImpl& del) + DelegateImpl(const DelegateImpl& del) { kind = del.kind; if (FUNC == del.kind) @@ -1400,7 +1400,7 @@ namespace delegate } } - DelegateImpl(DelegateImpl&& del) + DelegateImpl(DelegateImpl&& del) { kind = del.kind; if (FUNC == del.kind) @@ -1425,7 +1425,7 @@ namespace delegate new (&this->functional) FunctionType(std::forward(functional)); } - DelegateImpl& operator=(const DelegateImpl& del) + DelegateImpl& operator=(const DelegateImpl& del) { if (this == &del) return *this; if (FUNC == kind && FUNC != del.kind) @@ -1448,7 +1448,7 @@ namespace delegate return *this; } - DelegateImpl& operator=(DelegateImpl&& del) + DelegateImpl& operator=(DelegateImpl&& del) { if (this == &del) return *this; if (FUNC == kind && FUNC != del.kind) @@ -1582,12 +1582,12 @@ namespace delegate fn = nullptr; } - DelegateImpl(const DelegateImpl& del) + DelegateImpl(const DelegateImpl& del) { fn = del.fn; } - DelegateImpl(DelegateImpl&& del) + DelegateImpl(DelegateImpl&& del) { fn = std::move(del.fn); } @@ -1602,14 +1602,14 @@ namespace delegate DelegateImpl::fn = std::forward(fn); } - DelegateImpl& operator=(const DelegateImpl& del) + DelegateImpl& operator=(const DelegateImpl& del) { if (this == &del) return *this; fn = del.fn; return *this; } - DelegateImpl& operator=(DelegateImpl&& del) + DelegateImpl& operator=(DelegateImpl&& del) { if (this == &del) return *this; fn = std::move(del.fn); @@ -1679,9 +1679,11 @@ namespace delegate Delegate(std::nullptr_t) : detail::DelegatePImpl::DelegatePImpl(nullptr) {} - Delegate(const detail::DelegatePImpl& del) : detail::DelegatePImpl::DelegatePImpl(del) {} + Delegate(const Delegate& del) : detail::DelegatePImpl::DelegatePImpl( + static_cast&>(del)) {} - Delegate(detail::DelegatePImpl&& del) : detail::DelegatePImpl::DelegatePImpl(std::move(del)) {} + Delegate(Delegate&& del) : detail::DelegatePImpl::DelegatePImpl( + std::move(static_cast&&>(del))) {} Delegate(FunAPtr fnA, const A& obj) : detail::DelegatePImpl::DelegatePImpl(fnA, obj) {} @@ -1691,12 +1693,12 @@ namespace delegate template Delegate(F functional) : detail::DelegatePImpl::DelegatePImpl(functional) {} - Delegate& operator=(const detail::DelegatePImpl& del) { + Delegate& operator=(const Delegate& del) { detail::DelegatePImpl::operator=(del); return *this; } - Delegate& operator=(detail::DelegatePImpl&& del) { + Delegate& operator=(Delegate&& del) { detail::DelegatePImpl::operator=(std::move(del)); return *this; } @@ -1758,9 +1760,11 @@ namespace delegate Delegate(std::nullptr_t) : detail::DelegatePImpl::DelegatePImpl(nullptr) {} - Delegate(const detail::DelegatePImpl& del) : detail::DelegatePImpl::DelegatePImpl(del) {} + Delegate(const Delegate& del) : detail::DelegatePImpl::DelegatePImpl( + static_cast&>(del)) {} - Delegate(detail::DelegatePImpl&& del) : detail::DelegatePImpl::DelegatePImpl(std::move(del)) {} + Delegate(Delegate&& del) : detail::DelegatePImpl::DelegatePImpl( + std::move(static_cast&&>(del))) {} Delegate(FunAPtr fnA, A* obj) : detail::DelegatePImpl::DelegatePImpl(fnA, obj) {} @@ -1768,12 +1772,12 @@ namespace delegate template Delegate(F functional) : detail::DelegatePImpl::DelegatePImpl(functional) {} - Delegate& operator=(const detail::DelegatePImpl& del) { + Delegate& operator=(const Delegate& del) { detail::DelegatePImpl::operator=(del); return *this; } - Delegate& operator=(detail::DelegatePImpl&& del) { + Delegate& operator=(Delegate&& del) { detail::DelegatePImpl::operator=(std::move(del)); return *this; } @@ -1814,20 +1818,22 @@ namespace delegate Delegate(std::nullptr_t) : detail::DelegatePImpl::DelegatePImpl(nullptr) {} - Delegate(detail::DelegatePImpl& del) : detail::DelegatePImpl::DelegatePImpl(del) {} + Delegate(const Delegate& del) : detail::DelegatePImpl::DelegatePImpl( + static_cast&>(del)) {} - Delegate(detail::DelegatePImpl&& del) : detail::DelegatePImpl::DelegatePImpl(std::move(del)) {} + Delegate(Delegate&& del) : detail::DelegatePImpl::DelegatePImpl( + std::move(static_cast&&>(del))) {} Delegate(FunPtr fn) : detail::DelegatePImpl::DelegatePImpl(fn) {} template Delegate(F functional) : detail::DelegatePImpl::DelegatePImpl(functional) {} - Delegate& operator=(const detail::DelegatePImpl& del) { + Delegate& operator=(const Delegate& del) { detail::DelegatePImpl::operator=(del); return *this; } - Delegate& operator=(detail::DelegatePImpl&& del) { + Delegate& operator=(Delegate&& del) { detail::DelegatePImpl::operator=(std::move(del)); return *this; } @@ -1869,9 +1875,11 @@ namespace delegate Delegate(std::nullptr_t) : detail::DelegateImpl::DelegateImpl(nullptr) {} - Delegate(const detail::DelegateImpl& del) : detail::DelegateImpl::DelegateImpl(del) {} + Delegate(const Delegate& del) : detail::DelegateImpl::DelegateImpl( + static_cast&>(del)) {} - Delegate(detail::DelegateImpl&& del) : detail::DelegateImpl::DelegateImpl(std::move(del)) {} + Delegate(Delegate&& del) : detail::DelegateImpl::DelegateImpl( + std::move(static_cast&&>(del))) {} Delegate(FunAPtr fnA, const A& obj) : detail::DelegateImpl::DelegateImpl(fnA, obj) {} @@ -1881,12 +1889,12 @@ namespace delegate template Delegate(F functional) : detail::DelegateImpl::DelegateImpl(functional) {} - Delegate& operator=(const detail::DelegateImpl& del) { + Delegate& operator=(const Delegate& del) { detail::DelegateImpl::operator=(del); return *this; } - Delegate& operator=(detail::DelegateImpl&& del) { + Delegate& operator=(Delegate&& del) { detail::DelegateImpl::operator=(std::move(del)); return *this; } @@ -1948,9 +1956,11 @@ namespace delegate Delegate(std::nullptr_t) : detail::DelegateImpl::DelegateImpl(nullptr) {} - Delegate(const detail::DelegateImpl& del) : detail::DelegateImpl::DelegateImpl(del) {} + Delegate(const Delegate& del) : detail::DelegateImpl::DelegateImpl( + static_cast&>(del)) {} - Delegate(detail::DelegateImpl&& del) : detail::DelegateImpl::DelegateImpl(std::move(del)) {} + Delegate(Delegate&& del) : detail::DelegateImpl::DelegateImpl( + std::move(static_cast&&>(del))) {} Delegate(FunAPtr fnA, A* obj) : detail::DelegateImpl::DelegateImpl(fnA, obj) {} @@ -1958,12 +1968,12 @@ namespace delegate template Delegate(F functional) : detail::DelegateImpl::DelegateImpl(functional) {} - Delegate& operator=(const detail::DelegateImpl& del) { + Delegate& operator=(const Delegate& del) { detail::DelegateImpl::operator=(del); return *this; } - Delegate& operator=(detail::DelegateImpl&& del) { + Delegate& operator=(Delegate&& del) { detail::DelegateImpl::operator=(std::move(del)); return *this; } @@ -2004,20 +2014,22 @@ namespace delegate Delegate(std::nullptr_t) : detail::DelegateImpl::DelegateImpl(nullptr) {} - Delegate(const detail::DelegateImpl& del) : detail::DelegateImpl::DelegateImpl(del) {} + Delegate(const Delegate& del) : detail::DelegateImpl::DelegateImpl( + static_cast&>(del)) {} - Delegate(detail::DelegateImpl&& del) : detail::DelegateImpl::DelegateImpl(std::move(del)) {} + Delegate(Delegate&& del) : detail::DelegateImpl::DelegateImpl( + std::move(static_cast&&>(del))) {} Delegate(FunPtr fn) : detail::DelegateImpl::DelegateImpl(fn) {} template Delegate(F functional) : detail::DelegateImpl::DelegateImpl(functional) {} - Delegate& operator=(const detail::DelegateImpl& del) { + Delegate& operator=(const Delegate& del) { detail::DelegateImpl::operator=(del); return *this; } - Delegate& operator=(detail::DelegateImpl&& del) { + Delegate& operator=(Delegate&& del) { detail::DelegateImpl::operator=(std::move(del)); return *this; } @@ -2043,9 +2055,11 @@ template class Delegate : pub Delegate(std::nullptr_t) : delegate::detail::Delegate::Delegate(nullptr) {} - Delegate(const delegate::detail::Delegate& del) : delegate::detail::Delegate::Delegate(del) {} + Delegate(const Delegate& del) : delegate::detail::Delegate::Delegate( + static_cast&>(del)) {} - Delegate(delegate::detail::Delegate&& del) : delegate::detail::Delegate::Delegate(std::move(del)) {} + Delegate(Delegate&& del) : delegate::detail::Delegate::Delegate( + std::move(static_cast&&>(del))) {} Delegate(typename delegate::detail::Delegate::FunAPtr fnA, const A& obj) : delegate::detail::Delegate::Delegate(fnA, obj) {} @@ -2055,12 +2069,12 @@ template class Delegate : pub template Delegate(F functional) : delegate::detail::Delegate::Delegate(functional) {} - Delegate& operator=(const delegate::detail::Delegate& del) { + Delegate& operator=(const Delegate& del) { delegate::detail::Delegate::operator=(del); return *this; } - Delegate& operator=(delegate::detail::Delegate&& del) { + Delegate& operator=(Delegate&& del) { delegate::detail::Delegate::operator=(std::move(del)); return *this; } @@ -2082,20 +2096,22 @@ template class Delegate : public delegate::d Delegate(std::nullptr_t) : delegate::detail::Delegate::Delegate(nullptr) {} - Delegate(const delegate::detail::Delegate& del) : delegate::detail::Delegate::Delegate(del) {} + Delegate(const Delegate& del) : delegate::detail::Delegate::Delegate( + static_cast&>(del)) {} - Delegate(delegate::detail::Delegate&& del) : delegate::detail::Delegate::Delegate(std::move(del)) {} + Delegate(Delegate&& del) : delegate::detail::Delegate::Delegate( + std::move(static_cast&&>(del))) {} Delegate(typename delegate::detail::Delegate::FunPtr fn) : delegate::detail::Delegate::Delegate(fn) {} template Delegate(F functional) : delegate::detail::Delegate::Delegate(functional) {} - Delegate& operator=(const delegate::detail::Delegate& del) { + Delegate& operator=(const Delegate& del) { delegate::detail::Delegate::operator=(del); return *this; } - Delegate& operator=(delegate::detail::Delegate&& del) { + Delegate& operator=(Delegate&& del) { delegate::detail::Delegate::operator=(std::move(del)); return *this; } From df02bac99ec6cf840265c8cf46028fa43ff456fc Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Mon, 23 Mar 2020 17:51:06 +0100 Subject: [PATCH 43/55] don't cast to rvalue ref if also move'ing --- cores/esp8266/Delegate.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/cores/esp8266/Delegate.h b/cores/esp8266/Delegate.h index 613b495d2a..4ec3616dd7 100644 --- a/cores/esp8266/Delegate.h +++ b/cores/esp8266/Delegate.h @@ -1683,7 +1683,7 @@ namespace delegate static_cast&>(del)) {} Delegate(Delegate&& del) : detail::DelegatePImpl::DelegatePImpl( - std::move(static_cast&&>(del))) {} + std::move(static_cast&>(del))) {} Delegate(FunAPtr fnA, const A& obj) : detail::DelegatePImpl::DelegatePImpl(fnA, obj) {} @@ -1764,7 +1764,7 @@ namespace delegate static_cast&>(del)) {} Delegate(Delegate&& del) : detail::DelegatePImpl::DelegatePImpl( - std::move(static_cast&&>(del))) {} + std::move(static_cast&>(del))) {} Delegate(FunAPtr fnA, A* obj) : detail::DelegatePImpl::DelegatePImpl(fnA, obj) {} @@ -1822,7 +1822,7 @@ namespace delegate static_cast&>(del)) {} Delegate(Delegate&& del) : detail::DelegatePImpl::DelegatePImpl( - std::move(static_cast&&>(del))) {} + std::move(static_cast&>(del))) {} Delegate(FunPtr fn) : detail::DelegatePImpl::DelegatePImpl(fn) {} @@ -1879,7 +1879,7 @@ namespace delegate static_cast&>(del)) {} Delegate(Delegate&& del) : detail::DelegateImpl::DelegateImpl( - std::move(static_cast&&>(del))) {} + std::move(static_cast&>(del))) {} Delegate(FunAPtr fnA, const A& obj) : detail::DelegateImpl::DelegateImpl(fnA, obj) {} @@ -1960,7 +1960,7 @@ namespace delegate static_cast&>(del)) {} Delegate(Delegate&& del) : detail::DelegateImpl::DelegateImpl( - std::move(static_cast&&>(del))) {} + std::move(static_cast&>(del))) {} Delegate(FunAPtr fnA, A* obj) : detail::DelegateImpl::DelegateImpl(fnA, obj) {} @@ -2018,7 +2018,7 @@ namespace delegate static_cast&>(del)) {} Delegate(Delegate&& del) : detail::DelegateImpl::DelegateImpl( - std::move(static_cast&&>(del))) {} + std::move(static_cast&>(del))) {} Delegate(FunPtr fn) : detail::DelegateImpl::DelegateImpl(fn) {} @@ -2059,7 +2059,7 @@ template class Delegate : pub static_cast&>(del)) {} Delegate(Delegate&& del) : delegate::detail::Delegate::Delegate( - std::move(static_cast&&>(del))) {} + std::move(static_cast&>(del))) {} Delegate(typename delegate::detail::Delegate::FunAPtr fnA, const A& obj) : delegate::detail::Delegate::Delegate(fnA, obj) {} @@ -2100,7 +2100,7 @@ template class Delegate : public delegate::d static_cast&>(del)) {} Delegate(Delegate&& del) : delegate::detail::Delegate::Delegate( - std::move(static_cast&&>(del))) {} + std::move(static_cast&>(del))) {} Delegate(typename delegate::detail::Delegate::FunPtr fn) : delegate::detail::Delegate::Delegate(fn) {} From 81ceebd45999f281045eb74e475618709d3d9bd4 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Mon, 4 Jan 2021 17:43:37 +0100 Subject: [PATCH 44/55] Add assignment operators. --- cores/esp8266/Delegate.h | 146 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 136 insertions(+), 10 deletions(-) diff --git a/cores/esp8266/Delegate.h b/cores/esp8266/Delegate.h index 4ec3616dd7..65844713ab 100644 --- a/cores/esp8266/Delegate.h +++ b/cores/esp8266/Delegate.h @@ -239,6 +239,21 @@ namespace delegate return *this; } + template DelegatePImpl& operator=(F functional) + { + if (FUNC == kind) + { + this->functional.~FunctionType(); + } + else if (FPA == kind) + { + obj.~A(); + } + kind = FUNC; + new (&this->functional) FunctionType(std::forward(functional)); + return *this; + } + DelegatePImpl& IRAM_ATTR operator=(std::nullptr_t) { if (FUNC == kind) @@ -421,10 +436,10 @@ namespace delegate DelegatePImpl::fn = fn; } - template DelegatePImpl(F fn) + template DelegatePImpl(F functional) { kind = FP; - DelegatePImpl::fn = std::forward(fn); + fn = std::forward(functional); } DelegatePImpl& operator=(const DelegatePImpl& del) @@ -484,6 +499,16 @@ namespace delegate return *this; } + template DelegatePImpl& operator=(F functional) + { + if (FPA == kind) + { + obj = {}; + } + kind = FP; + fn = std::forward(functional); + } + DelegatePImpl& IRAM_ATTR operator=(std::nullptr_t) { if (FPA == kind) @@ -683,6 +708,17 @@ namespace delegate return *this; } + template DelegatePImpl& operator=(F functional) + { + if (FUNC == kind) + { + this->functional.~FunctionType(); + } + kind = FUNC; + new (&this->functional) FunctionType(std::forward(functional)); + return *this; + } + DelegatePImpl& IRAM_ATTR operator=(std::nullptr_t) { if (FUNC == kind) @@ -823,6 +859,12 @@ namespace delegate return *this; } + template DelegatePImpl& operator=(F functional) + { + fn = std::forward(functional); + return *this; + } + DelegatePImpl& IRAM_ATTR operator=(std::nullptr_t) { fn = nullptr; @@ -1040,6 +1082,21 @@ namespace delegate return *this; } + template DelegateImpl& operator=(F functional) + { + if (FUNC == kind) + { + this->functional.~FunctionType(); + } + else if (FPA == kind) + { + obj.~A(); + } + kind = FUNC; + new (&this->functional) FunctionType(std::forward(functional)); + return *this; + } + DelegateImpl& IRAM_ATTR operator=(std::nullptr_t) { if (FUNC == kind) @@ -1284,6 +1341,17 @@ namespace delegate return *this; } + template DelegateImpl& operator=(F functional) + { + if (FPA == kind) + { + obj.~A(); + } + kind = FP; + fn = std::forward(functional); + return *this; + } + DelegateImpl& IRAM_ATTR operator=(std::nullptr_t) { if (FPA == kind) @@ -1482,6 +1550,17 @@ namespace delegate return *this; } + template DelegateImpl& operator=(F functional) + { + if (FUNC == kind) + { + this->functional.~FunctionType(); + } + kind = FUNC; + new (&this->functional) FunctionType(std::forward(functional)); + return *this; + } + DelegateImpl& IRAM_ATTR operator=(std::nullptr_t) { if (FUNC == kind) @@ -1622,6 +1701,12 @@ namespace delegate return *this; } + template DelegateImpl& operator=(F functional) + { + fn = std::forward(functional); + return *this; + } + DelegateImpl& IRAM_ATTR operator=(std::nullptr_t) { fn = nullptr; @@ -1691,7 +1776,7 @@ namespace delegate Delegate(FunPtr fn) : detail::DelegatePImpl::DelegatePImpl(fn) {} - template Delegate(F functional) : detail::DelegatePImpl::DelegatePImpl(functional) {} + template Delegate(F functional) : detail::DelegatePImpl::DelegatePImpl(std::forward(functional)) {} Delegate& operator=(const Delegate& del) { detail::DelegatePImpl::operator=(del); @@ -1708,6 +1793,11 @@ namespace delegate return *this; } + template Delegate& operator=(F functional) { + detail::DelegatePImpl::operator=(std::forward(functional)); + return *this; + } + Delegate& IRAM_ATTR operator=(std::nullptr_t) { detail::DelegatePImpl::operator=(nullptr); return *this; @@ -1770,7 +1860,7 @@ namespace delegate Delegate(FunPtr fn) : detail::DelegatePImpl::DelegatePImpl(fn) {} - template Delegate(F functional) : detail::DelegatePImpl::DelegatePImpl(functional) {} + template Delegate(F functional) : detail::DelegatePImpl::DelegatePImpl(std::forward(functional)) {} Delegate& operator=(const Delegate& del) { detail::DelegatePImpl::operator=(del); @@ -1787,6 +1877,11 @@ namespace delegate return *this; } + template Delegate& operator=(F functional) { + detail::DelegatePImpl::operator=(std::forward(functional)); + return *this; + } + Delegate& IRAM_ATTR operator=(std::nullptr_t) { detail::DelegatePImpl::operator=(nullptr); return *this; @@ -1826,7 +1921,7 @@ namespace delegate Delegate(FunPtr fn) : detail::DelegatePImpl::DelegatePImpl(fn) {} - template Delegate(F functional) : detail::DelegatePImpl::DelegatePImpl(functional) {} + template Delegate(F functional) : detail::DelegatePImpl::DelegatePImpl(std::forward(functional)) {} Delegate& operator=(const Delegate& del) { detail::DelegatePImpl::operator=(del); @@ -1843,6 +1938,11 @@ namespace delegate return *this; } + template Delegate& operator=(F functional) { + detail::DelegatePImpl::operator=(std::forward(functional)); + return *this; + } + Delegate& IRAM_ATTR operator=(std::nullptr_t) { detail::DelegatePImpl::operator=(nullptr); return *this; @@ -1887,7 +1987,7 @@ namespace delegate Delegate(FunPtr fn) : detail::DelegateImpl::DelegateImpl(fn) {} - template Delegate(F functional) : detail::DelegateImpl::DelegateImpl(functional) {} + template Delegate(F functional) : detail::DelegateImpl::DelegateImpl(std::forward(functional)) {} Delegate& operator=(const Delegate& del) { detail::DelegateImpl::operator=(del); @@ -1904,6 +2004,11 @@ namespace delegate return *this; } + template Delegate& operator=(F functional) { + detail::DelegateImpl::operator=(std::forward(functional)); + return *this; + } + Delegate& IRAM_ATTR operator=(std::nullptr_t) { detail::DelegateImpl::operator=(nullptr); return *this; @@ -1966,7 +2071,7 @@ namespace delegate Delegate(FunPtr fn) : detail::DelegateImpl::DelegateImpl(fn) {} - template Delegate(F functional) : detail::DelegateImpl::DelegateImpl(functional) {} + template Delegate(F functional) : detail::DelegateImpl::DelegateImpl(std::forward(functional)) {} Delegate& operator=(const Delegate& del) { detail::DelegateImpl::operator=(del); @@ -1983,6 +2088,11 @@ namespace delegate return *this; } + template Delegate& operator=(F functional) { + detail::DelegateImpl::operator=(std::forward(functional)); + return *this; + } + Delegate& IRAM_ATTR operator=(std::nullptr_t) { detail::DelegateImpl::operator=(nullptr); return *this; @@ -2022,7 +2132,7 @@ namespace delegate Delegate(FunPtr fn) : detail::DelegateImpl::DelegateImpl(fn) {} - template Delegate(F functional) : detail::DelegateImpl::DelegateImpl(functional) {} + template Delegate(F functional) : detail::DelegateImpl::DelegateImpl(std::forward(functional)) {} Delegate& operator=(const Delegate& del) { detail::DelegateImpl::operator=(del); @@ -2039,6 +2149,11 @@ namespace delegate return *this; } + template Delegate& operator=(F functional) { + detail::DelegateImpl::operator=(std::forward(functional)); + return *this; + } + Delegate& IRAM_ATTR operator=(std::nullptr_t) { detail::DelegateImpl::operator=(nullptr); return *this; @@ -2067,7 +2182,7 @@ template class Delegate : pub Delegate(typename delegate::detail::Delegate::FunPtr fn) : delegate::detail::Delegate::Delegate(fn) {} - template Delegate(F functional) : delegate::detail::Delegate::Delegate(functional) {} + template Delegate(F functional) : delegate::detail::Delegate::Delegate(std::forward(functional)) {} Delegate& operator=(const Delegate& del) { delegate::detail::Delegate::operator=(del); @@ -2084,11 +2199,17 @@ template class Delegate : pub return *this; } + template Delegate& operator=(F functional) { + delegate::detail::Delegate::operator=(std::forward(functional)); + return *this; + } + Delegate& IRAM_ATTR operator=(std::nullptr_t) { delegate::detail::Delegate::operator=(nullptr); return *this; } }; + template class Delegate : public delegate::detail::Delegate { public: @@ -2104,7 +2225,7 @@ template class Delegate : public delegate::d Delegate(typename delegate::detail::Delegate::FunPtr fn) : delegate::detail::Delegate::Delegate(fn) {} - template Delegate(F functional) : delegate::detail::Delegate::Delegate(functional) {} + template Delegate(F functional) : delegate::detail::Delegate::Delegate(std::forward(functional)) {} Delegate& operator=(const Delegate& del) { delegate::detail::Delegate::operator=(del); @@ -2121,6 +2242,11 @@ template class Delegate : public delegate::d return *this; } + template Delegate& operator=(F functional) { + delegate::detail::Delegate::operator=(std::forward(functional)); + return *this; + } + Delegate& IRAM_ATTR operator=(std::nullptr_t) { delegate::detail::Delegate::operator=(nullptr); return *this; From 4fa0dbb2a7bb40389e41346c634e419f431c6a8c Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Wed, 27 Jan 2021 14:40:57 +0100 Subject: [PATCH 45/55] Example as performance test for Delegate vs. std::function --- .../examples/DelegatePerf/DelegatePerf.ino | 116 ++++++++++++++++++ libraries/esp8266/examples/DelegatePerf/Foo.h | 14 +++ .../examples/DelegatePerf/TestPrep.cpp | 53 ++++++++ 3 files changed, 183 insertions(+) create mode 100644 libraries/esp8266/examples/DelegatePerf/DelegatePerf.ino create mode 100644 libraries/esp8266/examples/DelegatePerf/Foo.h create mode 100644 libraries/esp8266/examples/DelegatePerf/TestPrep.cpp diff --git a/libraries/esp8266/examples/DelegatePerf/DelegatePerf.ino b/libraries/esp8266/examples/DelegatePerf/DelegatePerf.ino new file mode 100644 index 0000000000..156a87571c --- /dev/null +++ b/libraries/esp8266/examples/DelegatePerf/DelegatePerf.ino @@ -0,0 +1,116 @@ +/* + ESP8266 Delegate class template test by Dirk O. Kaar + This example code is in the public domain +*/ + +#include "Foo.h" +#include +#include + +constexpr long unsigned MAXCNT = 100000UL; +const String TESTCASE = "F"; +const String LATENCY = "Latency/cycles = "; +uint32_t cycles; +uint32_t cnt; + +enum TestCase { F0 = 0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12 }; +TestCase testCases[] = { F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12 }; + +using Fp0 = bool (*)(Foo*, int); +using Fp2 = bool(*)(int); + +Foo* o0; +Fp0 f0; +Foo* o1; +Fp0 f1; +Delegate f2; +Delegate f3; + +std::function f4; +std::function f5; + +Delegate f6; +Delegate f7; +Delegate f8; + +Delegate f9; +Delegate f10; +Delegate f11; +Delegate f12; + +void set_f0(Fp0 _f, Foo* _o) { f0 = _f; o0 = _o; } +void set_f1(Fp0 _f, Foo* _o) { f1 = _f; o1 = _o; } +void set_f2(Fp2 _f) { f2 = { _f }; } +void set_f3(Fp2 _f) { f3 = { _f }; } + +void set_f4(const std::function& _f) { f4 = _f; } +void set_f5(const std::function& _f) { f5 = _f; } + +void set_f6(const Delegate& _f) { f6 = _f; } +void set_f7(const Delegate& _f) { f7 = _f; } +void set_f8(const Delegate& _f) { f8 = _f; } + +void set_f9(const Delegate& _f) { f9 = _f; } +void set_f10(const Delegate& _f) { f10 = _f; } + +void set_f11(const Delegate& _f) { f11 = _f; } +void set_f12(const Delegate& _f) { f12 = _f; } + +extern void testPrep(); + +void stopWatch() +{ + if (MAXCNT == cnt) + { + Serial.print(LATENCY); + Serial.println(cycles / MAXCNT); + cycles = 0; + cnt = 0; + } +} + +void setup() +{ + Serial.begin(115200); + testPrep(); + + cycles = 0; + cnt = 0; +} + +// Add the main program code into the continuous loop() function +void loop() +{ + for (auto tc : testCases) { + Serial.print(TESTCASE); + Serial.print(tc); + Serial.print(": "); + for (unsigned i = 0; i < MAXCNT; ++i) + { + auto start = ESP.getCycleCount(); + switch (tc) { + case F0: f0(o0, 42); break; + case F1: f1(o1, 42); break; + case F2: f2(42); break; // { cbCPtr } + case F3: f3(42); break; // { cbCPtr } + + case F4: f4(42); break; // [o](int result) -> bool { return o->cb(result); } + case F5: f5(42); break; // std::bind(Foo::cbwObj, o, std::placeholders::_1) + + case F6: f6(42); break; // [o](int result) -> bool { return o->cb(result); } + case F7: f7(42); break; // std::bind(Foo::cbwObj, o, std::placeholders::_1) + case F8: f8(42); break; // [](int result) -> bool { return cbCPtr(result); } + + case F9: f9(42); break; // [o](int result) -> bool { return o->cb(result); } <==== antipattern for Delegate, use f11 instead + case F10: f10(42); break; // std::bind(Foo::cbwObj, o, std::placeholders::_1) <==== antipattern for Delegate, use f11 instead + + case F11: f11(42); break; // [](Foo* o, int result) -> bool { return o->cb(result); }, o.get() }) + case F12: f12(42); break; // { Foo::cbwObj, o.get() } + } + cycles += (ESP.getCycleCount() - start); + stopWatch(); + } + yield(); + } + delay(16000); +} diff --git a/libraries/esp8266/examples/DelegatePerf/Foo.h b/libraries/esp8266/examples/DelegatePerf/Foo.h new file mode 100644 index 0000000000..df8e93b3f2 --- /dev/null +++ b/libraries/esp8266/examples/DelegatePerf/Foo.h @@ -0,0 +1,14 @@ +/* + ESP8266 Delegate class template test by Dirk O. Kaar + This example code is in the public domain +*/ + +#include + +extern uint32_t cnt; + +struct Foo { + int val; + bool cb(int result) { val = result; ++cnt; return true; } + static bool cbwObj(Foo* obj, int result) { return ((Foo*)obj)->cb(result); } +}; \ No newline at end of file diff --git a/libraries/esp8266/examples/DelegatePerf/TestPrep.cpp b/libraries/esp8266/examples/DelegatePerf/TestPrep.cpp new file mode 100644 index 0000000000..71c423542f --- /dev/null +++ b/libraries/esp8266/examples/DelegatePerf/TestPrep.cpp @@ -0,0 +1,53 @@ +/* + ESP8266 Delegate class template test by Dirk O. Kaar + This example code is in the public domain +*/ + +#include "Foo.h" +#include +#include + +extern void stopwatch(); + +std::shared_ptr oPtr(new Foo()); +bool inline cbCPtr(int result) { return oPtr->cb(result); } + + +extern void set_f0(bool(*_f)(Foo*, int), Foo* _o); +extern void set_f1(bool(*_f)(Foo*, int), Foo* _o); +extern void set_f2(bool(*)(int result)); +extern void set_f3(bool(*)(int result)); + +extern void set_f4(const std::function& f); +extern void set_f5(const std::function& f); + +extern void set_f6(const Delegate&); +extern void set_f7(const Delegate&); +extern void set_f8(const Delegate&); + +extern void set_f9(const Delegate& f); +extern void set_f10(const Delegate& f); + +extern void set_f11(const Delegate& f); +extern void set_f12(const Delegate& f); + +void testPrep() { + std::shared_ptr o(oPtr); + set_f0(Foo::cbwObj, o.get()); + set_f1([](Foo* o, int result) -> bool { return o->cb(result); }, o.get()); + set_f2(cbCPtr); + set_f3(cbCPtr); + + set_f4([o](int result) -> bool { return o->cb(result); }); + set_f5(std::bind(Foo::cbwObj, o.get(), std::placeholders::_1)); + + set_f6([o](int result) -> bool { return o->cb(result); }); + set_f7(std::bind(Foo::cbwObj, o.get(), std::placeholders::_1)); + set_f8([](int result) -> bool { return cbCPtr(result); }); + + set_f9([o](int result) -> bool { return o->cb(result); }); + set_f10(std::bind(Foo::cbwObj, o.get(), std::placeholders::_1)); + + set_f11({ [](Foo* o, int result) -> bool { return o->cb(result); }, o.get() }); // fast calling! + set_f12({ Foo::cbwObj, o.get() }); // fast calling! +} From 6b6dbeec53b234c0bb4fedce2ef327a8b0ada3ac Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Wed, 27 Jan 2021 15:01:35 +0100 Subject: [PATCH 46/55] Revert "Add assignment operators." This reverts commit 7c9c23e5fdec7264cfcf549ac791193100c3ef7d. --- cores/esp8266/Delegate.h | 162 +++++---------------------------------- 1 file changed, 18 insertions(+), 144 deletions(-) diff --git a/cores/esp8266/Delegate.h b/cores/esp8266/Delegate.h index 65844713ab..613b495d2a 100644 --- a/cores/esp8266/Delegate.h +++ b/cores/esp8266/Delegate.h @@ -239,21 +239,6 @@ namespace delegate return *this; } - template DelegatePImpl& operator=(F functional) - { - if (FUNC == kind) - { - this->functional.~FunctionType(); - } - else if (FPA == kind) - { - obj.~A(); - } - kind = FUNC; - new (&this->functional) FunctionType(std::forward(functional)); - return *this; - } - DelegatePImpl& IRAM_ATTR operator=(std::nullptr_t) { if (FUNC == kind) @@ -436,10 +421,10 @@ namespace delegate DelegatePImpl::fn = fn; } - template DelegatePImpl(F functional) + template DelegatePImpl(F fn) { kind = FP; - fn = std::forward(functional); + DelegatePImpl::fn = std::forward(fn); } DelegatePImpl& operator=(const DelegatePImpl& del) @@ -499,16 +484,6 @@ namespace delegate return *this; } - template DelegatePImpl& operator=(F functional) - { - if (FPA == kind) - { - obj = {}; - } - kind = FP; - fn = std::forward(functional); - } - DelegatePImpl& IRAM_ATTR operator=(std::nullptr_t) { if (FPA == kind) @@ -708,17 +683,6 @@ namespace delegate return *this; } - template DelegatePImpl& operator=(F functional) - { - if (FUNC == kind) - { - this->functional.~FunctionType(); - } - kind = FUNC; - new (&this->functional) FunctionType(std::forward(functional)); - return *this; - } - DelegatePImpl& IRAM_ATTR operator=(std::nullptr_t) { if (FUNC == kind) @@ -859,12 +823,6 @@ namespace delegate return *this; } - template DelegatePImpl& operator=(F functional) - { - fn = std::forward(functional); - return *this; - } - DelegatePImpl& IRAM_ATTR operator=(std::nullptr_t) { fn = nullptr; @@ -1082,21 +1040,6 @@ namespace delegate return *this; } - template DelegateImpl& operator=(F functional) - { - if (FUNC == kind) - { - this->functional.~FunctionType(); - } - else if (FPA == kind) - { - obj.~A(); - } - kind = FUNC; - new (&this->functional) FunctionType(std::forward(functional)); - return *this; - } - DelegateImpl& IRAM_ATTR operator=(std::nullptr_t) { if (FUNC == kind) @@ -1341,17 +1284,6 @@ namespace delegate return *this; } - template DelegateImpl& operator=(F functional) - { - if (FPA == kind) - { - obj.~A(); - } - kind = FP; - fn = std::forward(functional); - return *this; - } - DelegateImpl& IRAM_ATTR operator=(std::nullptr_t) { if (FPA == kind) @@ -1550,17 +1482,6 @@ namespace delegate return *this; } - template DelegateImpl& operator=(F functional) - { - if (FUNC == kind) - { - this->functional.~FunctionType(); - } - kind = FUNC; - new (&this->functional) FunctionType(std::forward(functional)); - return *this; - } - DelegateImpl& IRAM_ATTR operator=(std::nullptr_t) { if (FUNC == kind) @@ -1701,12 +1622,6 @@ namespace delegate return *this; } - template DelegateImpl& operator=(F functional) - { - fn = std::forward(functional); - return *this; - } - DelegateImpl& IRAM_ATTR operator=(std::nullptr_t) { fn = nullptr; @@ -1768,7 +1683,7 @@ namespace delegate static_cast&>(del)) {} Delegate(Delegate&& del) : detail::DelegatePImpl::DelegatePImpl( - std::move(static_cast&>(del))) {} + std::move(static_cast&&>(del))) {} Delegate(FunAPtr fnA, const A& obj) : detail::DelegatePImpl::DelegatePImpl(fnA, obj) {} @@ -1776,7 +1691,7 @@ namespace delegate Delegate(FunPtr fn) : detail::DelegatePImpl::DelegatePImpl(fn) {} - template Delegate(F functional) : detail::DelegatePImpl::DelegatePImpl(std::forward(functional)) {} + template Delegate(F functional) : detail::DelegatePImpl::DelegatePImpl(functional) {} Delegate& operator=(const Delegate& del) { detail::DelegatePImpl::operator=(del); @@ -1793,11 +1708,6 @@ namespace delegate return *this; } - template Delegate& operator=(F functional) { - detail::DelegatePImpl::operator=(std::forward(functional)); - return *this; - } - Delegate& IRAM_ATTR operator=(std::nullptr_t) { detail::DelegatePImpl::operator=(nullptr); return *this; @@ -1854,13 +1764,13 @@ namespace delegate static_cast&>(del)) {} Delegate(Delegate&& del) : detail::DelegatePImpl::DelegatePImpl( - std::move(static_cast&>(del))) {} + std::move(static_cast&&>(del))) {} Delegate(FunAPtr fnA, A* obj) : detail::DelegatePImpl::DelegatePImpl(fnA, obj) {} Delegate(FunPtr fn) : detail::DelegatePImpl::DelegatePImpl(fn) {} - template Delegate(F functional) : detail::DelegatePImpl::DelegatePImpl(std::forward(functional)) {} + template Delegate(F functional) : detail::DelegatePImpl::DelegatePImpl(functional) {} Delegate& operator=(const Delegate& del) { detail::DelegatePImpl::operator=(del); @@ -1877,11 +1787,6 @@ namespace delegate return *this; } - template Delegate& operator=(F functional) { - detail::DelegatePImpl::operator=(std::forward(functional)); - return *this; - } - Delegate& IRAM_ATTR operator=(std::nullptr_t) { detail::DelegatePImpl::operator=(nullptr); return *this; @@ -1917,11 +1822,11 @@ namespace delegate static_cast&>(del)) {} Delegate(Delegate&& del) : detail::DelegatePImpl::DelegatePImpl( - std::move(static_cast&>(del))) {} + std::move(static_cast&&>(del))) {} Delegate(FunPtr fn) : detail::DelegatePImpl::DelegatePImpl(fn) {} - template Delegate(F functional) : detail::DelegatePImpl::DelegatePImpl(std::forward(functional)) {} + template Delegate(F functional) : detail::DelegatePImpl::DelegatePImpl(functional) {} Delegate& operator=(const Delegate& del) { detail::DelegatePImpl::operator=(del); @@ -1938,11 +1843,6 @@ namespace delegate return *this; } - template Delegate& operator=(F functional) { - detail::DelegatePImpl::operator=(std::forward(functional)); - return *this; - } - Delegate& IRAM_ATTR operator=(std::nullptr_t) { detail::DelegatePImpl::operator=(nullptr); return *this; @@ -1979,7 +1879,7 @@ namespace delegate static_cast&>(del)) {} Delegate(Delegate&& del) : detail::DelegateImpl::DelegateImpl( - std::move(static_cast&>(del))) {} + std::move(static_cast&&>(del))) {} Delegate(FunAPtr fnA, const A& obj) : detail::DelegateImpl::DelegateImpl(fnA, obj) {} @@ -1987,7 +1887,7 @@ namespace delegate Delegate(FunPtr fn) : detail::DelegateImpl::DelegateImpl(fn) {} - template Delegate(F functional) : detail::DelegateImpl::DelegateImpl(std::forward(functional)) {} + template Delegate(F functional) : detail::DelegateImpl::DelegateImpl(functional) {} Delegate& operator=(const Delegate& del) { detail::DelegateImpl::operator=(del); @@ -2004,11 +1904,6 @@ namespace delegate return *this; } - template Delegate& operator=(F functional) { - detail::DelegateImpl::operator=(std::forward(functional)); - return *this; - } - Delegate& IRAM_ATTR operator=(std::nullptr_t) { detail::DelegateImpl::operator=(nullptr); return *this; @@ -2065,13 +1960,13 @@ namespace delegate static_cast&>(del)) {} Delegate(Delegate&& del) : detail::DelegateImpl::DelegateImpl( - std::move(static_cast&>(del))) {} + std::move(static_cast&&>(del))) {} Delegate(FunAPtr fnA, A* obj) : detail::DelegateImpl::DelegateImpl(fnA, obj) {} Delegate(FunPtr fn) : detail::DelegateImpl::DelegateImpl(fn) {} - template Delegate(F functional) : detail::DelegateImpl::DelegateImpl(std::forward(functional)) {} + template Delegate(F functional) : detail::DelegateImpl::DelegateImpl(functional) {} Delegate& operator=(const Delegate& del) { detail::DelegateImpl::operator=(del); @@ -2088,11 +1983,6 @@ namespace delegate return *this; } - template Delegate& operator=(F functional) { - detail::DelegateImpl::operator=(std::forward(functional)); - return *this; - } - Delegate& IRAM_ATTR operator=(std::nullptr_t) { detail::DelegateImpl::operator=(nullptr); return *this; @@ -2128,11 +2018,11 @@ namespace delegate static_cast&>(del)) {} Delegate(Delegate&& del) : detail::DelegateImpl::DelegateImpl( - std::move(static_cast&>(del))) {} + std::move(static_cast&&>(del))) {} Delegate(FunPtr fn) : detail::DelegateImpl::DelegateImpl(fn) {} - template Delegate(F functional) : detail::DelegateImpl::DelegateImpl(std::forward(functional)) {} + template Delegate(F functional) : detail::DelegateImpl::DelegateImpl(functional) {} Delegate& operator=(const Delegate& del) { detail::DelegateImpl::operator=(del); @@ -2149,11 +2039,6 @@ namespace delegate return *this; } - template Delegate& operator=(F functional) { - detail::DelegateImpl::operator=(std::forward(functional)); - return *this; - } - Delegate& IRAM_ATTR operator=(std::nullptr_t) { detail::DelegateImpl::operator=(nullptr); return *this; @@ -2174,7 +2059,7 @@ template class Delegate : pub static_cast&>(del)) {} Delegate(Delegate&& del) : delegate::detail::Delegate::Delegate( - std::move(static_cast&>(del))) {} + std::move(static_cast&&>(del))) {} Delegate(typename delegate::detail::Delegate::FunAPtr fnA, const A& obj) : delegate::detail::Delegate::Delegate(fnA, obj) {} @@ -2182,7 +2067,7 @@ template class Delegate : pub Delegate(typename delegate::detail::Delegate::FunPtr fn) : delegate::detail::Delegate::Delegate(fn) {} - template Delegate(F functional) : delegate::detail::Delegate::Delegate(std::forward(functional)) {} + template Delegate(F functional) : delegate::detail::Delegate::Delegate(functional) {} Delegate& operator=(const Delegate& del) { delegate::detail::Delegate::operator=(del); @@ -2199,17 +2084,11 @@ template class Delegate : pub return *this; } - template Delegate& operator=(F functional) { - delegate::detail::Delegate::operator=(std::forward(functional)); - return *this; - } - Delegate& IRAM_ATTR operator=(std::nullptr_t) { delegate::detail::Delegate::operator=(nullptr); return *this; } }; - template class Delegate : public delegate::detail::Delegate { public: @@ -2221,11 +2100,11 @@ template class Delegate : public delegate::d static_cast&>(del)) {} Delegate(Delegate&& del) : delegate::detail::Delegate::Delegate( - std::move(static_cast&>(del))) {} + std::move(static_cast&&>(del))) {} Delegate(typename delegate::detail::Delegate::FunPtr fn) : delegate::detail::Delegate::Delegate(fn) {} - template Delegate(F functional) : delegate::detail::Delegate::Delegate(std::forward(functional)) {} + template Delegate(F functional) : delegate::detail::Delegate::Delegate(functional) {} Delegate& operator=(const Delegate& del) { delegate::detail::Delegate::operator=(del); @@ -2242,11 +2121,6 @@ template class Delegate : public delegate::d return *this; } - template Delegate& operator=(F functional) { - delegate::detail::Delegate::operator=(std::forward(functional)); - return *this; - } - Delegate& IRAM_ATTR operator=(std::nullptr_t) { delegate::detail::Delegate::operator=(nullptr); return *this; From 099fc8674644144d87c4ae376d9e85b7ae17abde Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Wed, 27 Jan 2021 15:09:02 +0100 Subject: [PATCH 47/55] Re-apply std::forwards and minor identifier rename. (cherry picked from commit 7c9c23e5fdec7264cfcf549ac791193100c3ef7d) --- cores/esp8266/Delegate.h | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/cores/esp8266/Delegate.h b/cores/esp8266/Delegate.h index 613b495d2a..fe2c432638 100644 --- a/cores/esp8266/Delegate.h +++ b/cores/esp8266/Delegate.h @@ -421,10 +421,10 @@ namespace delegate DelegatePImpl::fn = fn; } - template DelegatePImpl(F fn) + template DelegatePImpl(F functional) { kind = FP; - DelegatePImpl::fn = std::forward(fn); + fn = std::forward(functional); } DelegatePImpl& operator=(const DelegatePImpl& del) @@ -1683,7 +1683,7 @@ namespace delegate static_cast&>(del)) {} Delegate(Delegate&& del) : detail::DelegatePImpl::DelegatePImpl( - std::move(static_cast&&>(del))) {} + std::move(static_cast&>(del))) {} Delegate(FunAPtr fnA, const A& obj) : detail::DelegatePImpl::DelegatePImpl(fnA, obj) {} @@ -1691,7 +1691,7 @@ namespace delegate Delegate(FunPtr fn) : detail::DelegatePImpl::DelegatePImpl(fn) {} - template Delegate(F functional) : detail::DelegatePImpl::DelegatePImpl(functional) {} + template Delegate(F functional) : detail::DelegatePImpl::DelegatePImpl(std::forward(functional)) {} Delegate& operator=(const Delegate& del) { detail::DelegatePImpl::operator=(del); @@ -1764,13 +1764,13 @@ namespace delegate static_cast&>(del)) {} Delegate(Delegate&& del) : detail::DelegatePImpl::DelegatePImpl( - std::move(static_cast&&>(del))) {} + std::move(static_cast&>(del))) {} Delegate(FunAPtr fnA, A* obj) : detail::DelegatePImpl::DelegatePImpl(fnA, obj) {} Delegate(FunPtr fn) : detail::DelegatePImpl::DelegatePImpl(fn) {} - template Delegate(F functional) : detail::DelegatePImpl::DelegatePImpl(functional) {} + template Delegate(F functional) : detail::DelegatePImpl::DelegatePImpl(std::forward(functional)) {} Delegate& operator=(const Delegate& del) { detail::DelegatePImpl::operator=(del); @@ -1822,11 +1822,11 @@ namespace delegate static_cast&>(del)) {} Delegate(Delegate&& del) : detail::DelegatePImpl::DelegatePImpl( - std::move(static_cast&&>(del))) {} + std::move(static_cast&>(del))) {} Delegate(FunPtr fn) : detail::DelegatePImpl::DelegatePImpl(fn) {} - template Delegate(F functional) : detail::DelegatePImpl::DelegatePImpl(functional) {} + template Delegate(F functional) : detail::DelegatePImpl::DelegatePImpl(std::forward(functional)) {} Delegate& operator=(const Delegate& del) { detail::DelegatePImpl::operator=(del); @@ -1879,7 +1879,7 @@ namespace delegate static_cast&>(del)) {} Delegate(Delegate&& del) : detail::DelegateImpl::DelegateImpl( - std::move(static_cast&&>(del))) {} + std::move(static_cast&>(del))) {} Delegate(FunAPtr fnA, const A& obj) : detail::DelegateImpl::DelegateImpl(fnA, obj) {} @@ -1887,7 +1887,7 @@ namespace delegate Delegate(FunPtr fn) : detail::DelegateImpl::DelegateImpl(fn) {} - template Delegate(F functional) : detail::DelegateImpl::DelegateImpl(functional) {} + template Delegate(F functional) : detail::DelegateImpl::DelegateImpl(std::forward(functional)) {} Delegate& operator=(const Delegate& del) { detail::DelegateImpl::operator=(del); @@ -1960,13 +1960,13 @@ namespace delegate static_cast&>(del)) {} Delegate(Delegate&& del) : detail::DelegateImpl::DelegateImpl( - std::move(static_cast&&>(del))) {} + std::move(static_cast&>(del))) {} Delegate(FunAPtr fnA, A* obj) : detail::DelegateImpl::DelegateImpl(fnA, obj) {} Delegate(FunPtr fn) : detail::DelegateImpl::DelegateImpl(fn) {} - template Delegate(F functional) : detail::DelegateImpl::DelegateImpl(functional) {} + template Delegate(F functional) : detail::DelegateImpl::DelegateImpl(std::forward(functional)) {} Delegate& operator=(const Delegate& del) { detail::DelegateImpl::operator=(del); @@ -2018,11 +2018,11 @@ namespace delegate static_cast&>(del)) {} Delegate(Delegate&& del) : detail::DelegateImpl::DelegateImpl( - std::move(static_cast&&>(del))) {} + std::move(static_cast&>(del))) {} Delegate(FunPtr fn) : detail::DelegateImpl::DelegateImpl(fn) {} - template Delegate(F functional) : detail::DelegateImpl::DelegateImpl(functional) {} + template Delegate(F functional) : detail::DelegateImpl::DelegateImpl(std::forward(functional)) {} Delegate& operator=(const Delegate& del) { detail::DelegateImpl::operator=(del); @@ -2059,7 +2059,7 @@ template class Delegate : pub static_cast&>(del)) {} Delegate(Delegate&& del) : delegate::detail::Delegate::Delegate( - std::move(static_cast&&>(del))) {} + std::move(static_cast&>(del))) {} Delegate(typename delegate::detail::Delegate::FunAPtr fnA, const A& obj) : delegate::detail::Delegate::Delegate(fnA, obj) {} @@ -2067,7 +2067,7 @@ template class Delegate : pub Delegate(typename delegate::detail::Delegate::FunPtr fn) : delegate::detail::Delegate::Delegate(fn) {} - template Delegate(F functional) : delegate::detail::Delegate::Delegate(functional) {} + template Delegate(F functional) : delegate::detail::Delegate::Delegate(std::forward(functional)) {} Delegate& operator=(const Delegate& del) { delegate::detail::Delegate::operator=(del); @@ -2089,6 +2089,7 @@ template class Delegate : pub return *this; } }; + template class Delegate : public delegate::detail::Delegate { public: @@ -2100,11 +2101,11 @@ template class Delegate : public delegate::d static_cast&>(del)) {} Delegate(Delegate&& del) : delegate::detail::Delegate::Delegate( - std::move(static_cast&&>(del))) {} + std::move(static_cast&>(del))) {} Delegate(typename delegate::detail::Delegate::FunPtr fn) : delegate::detail::Delegate::Delegate(fn) {} - template Delegate(F functional) : delegate::detail::Delegate::Delegate(functional) {} + template Delegate(F functional) : delegate::detail::Delegate::Delegate(std::forward(functional)) {} Delegate& operator=(const Delegate& del) { delegate::detail::Delegate::operator=(del); From 0fd063c368556bc3e37cb65e209cfed9f89687ad Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Wed, 27 Jan 2021 17:08:25 +0100 Subject: [PATCH 48/55] More hints for proper use of Delegate to optimize performance. --- libraries/esp8266/examples/DelegatePerf/DelegatePerf.ino | 8 ++++++-- libraries/esp8266/examples/DelegatePerf/TestPrep.cpp | 2 ++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/libraries/esp8266/examples/DelegatePerf/DelegatePerf.ino b/libraries/esp8266/examples/DelegatePerf/DelegatePerf.ino index 156a87571c..31021cee24 100644 --- a/libraries/esp8266/examples/DelegatePerf/DelegatePerf.ino +++ b/libraries/esp8266/examples/DelegatePerf/DelegatePerf.ino @@ -31,10 +31,12 @@ std::function f5; Delegate f6; Delegate f7; + Delegate f8; Delegate f9; Delegate f10; + Delegate f11; Delegate f12; @@ -48,6 +50,7 @@ void set_f5(const std::function& _f) { f5 = _f; } void set_f6(const Delegate& _f) { f6 = _f; } void set_f7(const Delegate& _f) { f7 = _f; } + void set_f8(const Delegate& _f) { f8 = _f; } void set_f9(const Delegate& _f) { f9 = _f; } @@ -97,8 +100,9 @@ void loop() case F4: f4(42); break; // [o](int result) -> bool { return o->cb(result); } case F5: f5(42); break; // std::bind(Foo::cbwObj, o, std::placeholders::_1) - case F6: f6(42); break; // [o](int result) -> bool { return o->cb(result); } - case F7: f7(42); break; // std::bind(Foo::cbwObj, o, std::placeholders::_1) + case F6: f6(42); break; // [o](int result) -> bool { return o->cb(result); } <==== antipattern for Delegate, use f11 instead + case F7: f7(42); break; // std::bind(Foo::cbwObj, o, std::placeholders::_1) <==== antipattern for Delegate, use f11 instead + case F8: f8(42); break; // [](int result) -> bool { return cbCPtr(result); } case F9: f9(42); break; // [o](int result) -> bool { return o->cb(result); } <==== antipattern for Delegate, use f11 instead diff --git a/libraries/esp8266/examples/DelegatePerf/TestPrep.cpp b/libraries/esp8266/examples/DelegatePerf/TestPrep.cpp index 71c423542f..9c49ce2898 100644 --- a/libraries/esp8266/examples/DelegatePerf/TestPrep.cpp +++ b/libraries/esp8266/examples/DelegatePerf/TestPrep.cpp @@ -23,6 +23,7 @@ extern void set_f5(const std::function& f); extern void set_f6(const Delegate&); extern void set_f7(const Delegate&); + extern void set_f8(const Delegate&); extern void set_f9(const Delegate& f); @@ -43,6 +44,7 @@ void testPrep() { set_f6([o](int result) -> bool { return o->cb(result); }); set_f7(std::bind(Foo::cbwObj, o.get(), std::placeholders::_1)); + set_f8([](int result) -> bool { return cbCPtr(result); }); set_f9([o](int result) -> bool { return o->cb(result); }); From 66d1704e5826dcce5895cca2d85844f66a2a3fde Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Wed, 27 Jan 2021 23:41:15 +0100 Subject: [PATCH 49/55] Apply astyle --- .../examples/DelegatePerf/DelegatePerf.ino | 147 ++++++++++-------- 1 file changed, 85 insertions(+), 62 deletions(-) diff --git a/libraries/esp8266/examples/DelegatePerf/DelegatePerf.ino b/libraries/esp8266/examples/DelegatePerf/DelegatePerf.ino index 31021cee24..7edf44b058 100644 --- a/libraries/esp8266/examples/DelegatePerf/DelegatePerf.ino +++ b/libraries/esp8266/examples/DelegatePerf/DelegatePerf.ino @@ -40,81 +40,104 @@ Delegate f10; Delegate f11; Delegate f12; -void set_f0(Fp0 _f, Foo* _o) { f0 = _f; o0 = _o; } -void set_f1(Fp0 _f, Foo* _o) { f1 = _f; o1 = _o; } -void set_f2(Fp2 _f) { f2 = { _f }; } -void set_f3(Fp2 _f) { f3 = { _f }; } +void set_f0(Fp0 _f, Foo* _o) { + f0 = _f; + o0 = _o; +} +void set_f1(Fp0 _f, Foo* _o) { + f1 = _f; + o1 = _o; +} +void set_f2(Fp2 _f) { + f2 = { _f }; +} +void set_f3(Fp2 _f) { + f3 = { _f }; +} -void set_f4(const std::function& _f) { f4 = _f; } -void set_f5(const std::function& _f) { f5 = _f; } +void set_f4(const std::function& _f) { + f4 = _f; +} +void set_f5(const std::function& _f) { + f5 = _f; +} -void set_f6(const Delegate& _f) { f6 = _f; } -void set_f7(const Delegate& _f) { f7 = _f; } +void set_f6(const Delegate& _f) { + f6 = _f; +} +void set_f7(const Delegate& _f) { + f7 = _f; +} -void set_f8(const Delegate& _f) { f8 = _f; } +void set_f8(const Delegate& _f) { + f8 = _f; +} -void set_f9(const Delegate& _f) { f9 = _f; } -void set_f10(const Delegate& _f) { f10 = _f; } +void set_f9(const Delegate& _f) { + f9 = _f; +} +void set_f10(const Delegate& _f) { + f10 = _f; +} -void set_f11(const Delegate& _f) { f11 = _f; } -void set_f12(const Delegate& _f) { f12 = _f; } +void set_f11(const Delegate& _f) { + f11 = _f; +} +void set_f12(const Delegate& _f) { + f12 = _f; +} extern void testPrep(); -void stopWatch() -{ - if (MAXCNT == cnt) - { - Serial.print(LATENCY); - Serial.println(cycles / MAXCNT); - cycles = 0; - cnt = 0; - } +void stopWatch() { + if (MAXCNT == cnt) { + Serial.print(LATENCY); + Serial.println(cycles / MAXCNT); + cycles = 0; + cnt = 0; + } } -void setup() -{ - Serial.begin(115200); - testPrep(); +void setup() { + Serial.begin(115200); + testPrep(); - cycles = 0; - cnt = 0; + cycles = 0; + cnt = 0; } // Add the main program code into the continuous loop() function -void loop() -{ - for (auto tc : testCases) { - Serial.print(TESTCASE); - Serial.print(tc); - Serial.print(": "); - for (unsigned i = 0; i < MAXCNT; ++i) - { - auto start = ESP.getCycleCount(); - switch (tc) { - case F0: f0(o0, 42); break; - case F1: f1(o1, 42); break; - case F2: f2(42); break; // { cbCPtr } - case F3: f3(42); break; // { cbCPtr } - - case F4: f4(42); break; // [o](int result) -> bool { return o->cb(result); } - case F5: f5(42); break; // std::bind(Foo::cbwObj, o, std::placeholders::_1) - - case F6: f6(42); break; // [o](int result) -> bool { return o->cb(result); } <==== antipattern for Delegate, use f11 instead - case F7: f7(42); break; // std::bind(Foo::cbwObj, o, std::placeholders::_1) <==== antipattern for Delegate, use f11 instead - - case F8: f8(42); break; // [](int result) -> bool { return cbCPtr(result); } - - case F9: f9(42); break; // [o](int result) -> bool { return o->cb(result); } <==== antipattern for Delegate, use f11 instead - case F10: f10(42); break; // std::bind(Foo::cbwObj, o, std::placeholders::_1) <==== antipattern for Delegate, use f11 instead - - case F11: f11(42); break; // [](Foo* o, int result) -> bool { return o->cb(result); }, o.get() }) - case F12: f12(42); break; // { Foo::cbwObj, o.get() } - } - cycles += (ESP.getCycleCount() - start); - stopWatch(); - } - yield(); +void loop() { + for (auto tc : testCases) { + Serial.print(TESTCASE); + Serial.print(tc); + Serial.print(": "); + for (unsigned i = 0; i < MAXCNT; ++i) { + auto start = ESP.getCycleCount(); + switch (tc) { + case F0: f0(o0, 42); break; + case F1: f1(o1, 42); break; + case F2: f2(42); break; // { cbCPtr } + case F3: f3(42); break; // { cbCPtr } + + case F4: f4(42); break; // [o](int result) -> bool { return o->cb(result); } + case F5: f5(42); break; // std::bind(Foo::cbwObj, o, std::placeholders::_1) + + case F6: f6(42); break; // [o](int result) -> bool { return o->cb(result); } <==== antipattern for Delegate, use f11 instead + case F7: f7(42); break; // std::bind(Foo::cbwObj, o, std::placeholders::_1) <==== antipattern for Delegate, use f11 instead + + case F8: f8(42); break; // [](int result) -> bool { return cbCPtr(result); } + + case F9: f9(42); break; // [o](int result) -> bool { return o->cb(result); } <==== antipattern for Delegate, use f11 instead + case F10: f10(42); break; // std::bind(Foo::cbwObj, o, std::placeholders::_1) <==== antipattern for Delegate, use f11 instead + + case F11: f11(42); break; // [](Foo* o, int result) -> bool { return o->cb(result); }, o.get() }) + case F12: f12(42); break; // { Foo::cbwObj, o.get() } + } + cycles += (ESP.getCycleCount() - start); + stopWatch(); } - delay(16000); + yield(); + } + delay(16000); } From 6aa1102ea2e08494bf641ea6681a6fc5acaf9bcd Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Thu, 28 Jan 2021 15:25:05 +0100 Subject: [PATCH 50/55] Added preprocessor define NODELEGATE. Use it for side-by-side comparison of Delegate<> vs. std::function<> --- .../examples/DelegatePerf/DelegatePerf.ino | 49 ++++++++++++++ libraries/esp8266/examples/DelegatePerf/Foo.h | 12 +++- .../examples/DelegatePerf/TestPrep.cpp | 66 ++++++++++++++----- 3 files changed, 106 insertions(+), 21 deletions(-) diff --git a/libraries/esp8266/examples/DelegatePerf/DelegatePerf.ino b/libraries/esp8266/examples/DelegatePerf/DelegatePerf.ino index 7edf44b058..1d4912efc5 100644 --- a/libraries/esp8266/examples/DelegatePerf/DelegatePerf.ino +++ b/libraries/esp8266/examples/DelegatePerf/DelegatePerf.ino @@ -4,8 +4,12 @@ */ #include "Foo.h" +#ifndef NODELEGATE #include #include +#else +#include +#endif constexpr long unsigned MAXCNT = 100000UL; const String TESTCASE = "F"; @@ -23,12 +27,18 @@ Foo* o0; Fp0 f0; Foo* o1; Fp0 f1; +#ifndef NODELEGATE Delegate f2; Delegate f3; +#else +std::function f2; +std::function f3; +#endif std::function f4; std::function f5; +#ifndef NODELEGATE Delegate f6; Delegate f7; @@ -39,6 +49,18 @@ Delegate f10; Delegate f11; Delegate f12; +#else +std::function f6; +std::function f7; + +std::function f8; + +std::function f9; +std::function f10; + +std::function f11; +std::function f12; +#endif void set_f0(Fp0 _f, Foo* _o) { f0 = _f; @@ -62,6 +84,7 @@ void set_f5(const std::function& _f) { f5 = _f; } +#ifndef NODELEGATE void set_f6(const Delegate& _f) { f6 = _f; } @@ -86,6 +109,32 @@ void set_f11(const Delegate& _f) { void set_f12(const Delegate& _f) { f12 = _f; } +#else +void set_f6(const std::function& _f) { + f6 = _f; +} +void set_f7(const std::function& _f) { + f7 = _f; +} + +void set_f8(const std::function& _f) { + f8 = _f; +} + +void set_f9(const std::function& _f) { + f9 = _f; +} +void set_f10(const std::function& _f) { + f10 = _f; +} + +void set_f11(const std::function& _f) { + f11 = _f; +} +void set_f12(const std::function& _f) { + f12 = _f; +} +#endif extern void testPrep(); diff --git a/libraries/esp8266/examples/DelegatePerf/Foo.h b/libraries/esp8266/examples/DelegatePerf/Foo.h index df8e93b3f2..3d87548483 100644 --- a/libraries/esp8266/examples/DelegatePerf/Foo.h +++ b/libraries/esp8266/examples/DelegatePerf/Foo.h @@ -8,7 +8,13 @@ extern uint32_t cnt; struct Foo { - int val; - bool cb(int result) { val = result; ++cnt; return true; } - static bool cbwObj(Foo* obj, int result) { return ((Foo*)obj)->cb(result); } + int val; + bool cb(int result) { + val = result; + ++cnt; + return true; + } + static bool cbwObj(Foo* obj, int result) { + return ((Foo*)obj)->cb(result); + } }; \ No newline at end of file diff --git a/libraries/esp8266/examples/DelegatePerf/TestPrep.cpp b/libraries/esp8266/examples/DelegatePerf/TestPrep.cpp index 9c49ce2898..4bf2e73895 100644 --- a/libraries/esp8266/examples/DelegatePerf/TestPrep.cpp +++ b/libraries/esp8266/examples/DelegatePerf/TestPrep.cpp @@ -4,13 +4,19 @@ */ #include "Foo.h" +#ifndef NODELEGATE #include +#else +#include +#endif #include extern void stopwatch(); std::shared_ptr oPtr(new Foo()); -bool inline cbCPtr(int result) { return oPtr->cb(result); } +bool inline cbCPtr(int result) { + return oPtr->cb(result); +} extern void set_f0(bool(*_f)(Foo*, int), Foo* _o); @@ -21,6 +27,7 @@ extern void set_f3(bool(*)(int result)); extern void set_f4(const std::function& f); extern void set_f5(const std::function& f); +#ifndef NODELEGATE extern void set_f6(const Delegate&); extern void set_f7(const Delegate&); @@ -31,25 +38,48 @@ extern void set_f10(const Delegate& f); extern void set_f11(const Delegate& f); extern void set_f12(const Delegate& f); +#else +extern void set_f6(const std::function&); +extern void set_f7(const std::function&); -void testPrep() { - std::shared_ptr o(oPtr); - set_f0(Foo::cbwObj, o.get()); - set_f1([](Foo* o, int result) -> bool { return o->cb(result); }, o.get()); - set_f2(cbCPtr); - set_f3(cbCPtr); - - set_f4([o](int result) -> bool { return o->cb(result); }); - set_f5(std::bind(Foo::cbwObj, o.get(), std::placeholders::_1)); +extern void set_f8(const std::function&); - set_f6([o](int result) -> bool { return o->cb(result); }); - set_f7(std::bind(Foo::cbwObj, o.get(), std::placeholders::_1)); +extern void set_f9(const std::function& f); +extern void set_f10(const std::function& f); - set_f8([](int result) -> bool { return cbCPtr(result); }); +extern void set_f11(const std::function& f); +extern void set_f12(const std::function& f); +#endif - set_f9([o](int result) -> bool { return o->cb(result); }); - set_f10(std::bind(Foo::cbwObj, o.get(), std::placeholders::_1)); - - set_f11({ [](Foo* o, int result) -> bool { return o->cb(result); }, o.get() }); // fast calling! - set_f12({ Foo::cbwObj, o.get() }); // fast calling! +void testPrep() { + std::shared_ptr o(oPtr); + set_f0(Foo::cbwObj, o.get()); + set_f1([](Foo * o, int result) -> bool { return o->cb(result); }, o.get()); + set_f2(cbCPtr); + set_f3(cbCPtr); + + set_f4([o](int result) -> bool { return o->cb(result); }); + set_f5(std::bind(Foo::cbwObj, o.get(), std::placeholders::_1)); + + set_f6([o](int result) -> bool { return o->cb(result); }); + set_f7(std::bind(Foo::cbwObj, o.get(), std::placeholders::_1)); + +#ifndef NODELEGATE + // hint to compiler to generate Delegate constructor for simple fp instead of functional + using Fp2 = bool(*)(int); + set_f8(static_cast([](int result) -> bool { return cbCPtr(result); })); +#else + set_f8([](int result) -> bool { return cbCPtr(result); }); +#endif + + set_f9([o](int result) -> bool { return o->cb(result); }); + set_f10(std::bind(Foo::cbwObj, o.get(), std::placeholders::_1)); + +#ifndef NODELEGATE + set_f11({ [](Foo * o, int result) -> bool { return o->cb(result); }, o.get() }); // fast calling! + set_f12({ Foo::cbwObj, o.get() }); // fast calling! +#else + set_f11([o](int result) -> bool { return o->cb(result); }); + set_f12(std::bind(Foo::cbwObj, o.get(), std::placeholders::_1)); +#endif } From 9644606c616f224e370ea02d040be2396fe60859 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Sat, 30 Jan 2021 11:45:38 +0100 Subject: [PATCH 51/55] Field padding improved --- cores/esp8266/Delegate.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cores/esp8266/Delegate.h b/cores/esp8266/Delegate.h index fe2c432638..029f84a133 100644 --- a/cores/esp8266/Delegate.h +++ b/cores/esp8266/Delegate.h @@ -341,7 +341,6 @@ namespace delegate } protected: - enum { FUNC, FP, FPA } kind; union { FunctionType functional; FunPtr fn; @@ -350,6 +349,7 @@ namespace delegate A obj; }; }; + enum { FUNC, FP, FPA } kind; }; #else template @@ -551,12 +551,12 @@ namespace delegate } protected: - enum { FP, FPA } kind; union { FunPtr fn; FunAPtr fnA; }; A obj; + enum { FP, FPA } kind; }; #endif @@ -758,11 +758,11 @@ namespace delegate } protected: - enum { FUNC, FP } kind; union { FunctionType functional; FunPtr fn; }; + enum { FUNC, FP } kind; }; #else template @@ -1141,7 +1141,6 @@ namespace delegate } protected: - enum { FUNC, FP, FPA } kind; union { FunctionType functional; FunPtr fn; @@ -1150,6 +1149,7 @@ namespace delegate A obj; }; }; + enum { FUNC, FP, FPA } kind; }; #else template @@ -1350,12 +1350,12 @@ namespace delegate } protected: - enum { FP, FPA } kind; union { FunPtr fn; FunAPtr fnA; }; A obj; + enum { FP, FPA } kind; }; #endif @@ -1557,11 +1557,11 @@ namespace delegate } protected: - enum { FUNC, FP } kind; union { FunctionType functional; FunPtr fn; }; + enum { FUNC, FP } kind; }; #else template From 8e75ef9fe35fa681b347482328d3b7ad82d45248 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Mon, 15 Mar 2021 01:14:50 +0100 Subject: [PATCH 52/55] Remove the now-deprecated ICACHE_RAM_ATTR. --- cores/esp8266/Delegate.h | 1 - 1 file changed, 1 deletion(-) diff --git a/cores/esp8266/Delegate.h b/cores/esp8266/Delegate.h index 029f84a133..193ca8a8fe 100644 --- a/cores/esp8266/Delegate.h +++ b/cores/esp8266/Delegate.h @@ -25,7 +25,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #elif defined(ESP32) #include #else -#define ICACHE_RAM_ATTR #define IRAM_ATTR #endif From 12c27a41da8f3be30a2da8fd2d335f925c7be400 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Tue, 17 Dec 2019 16:54:47 +0100 Subject: [PATCH 53/55] Ticker ported to Delegate --- libraries/Ticker/src/Ticker.cpp | 12 +---- libraries/Ticker/src/Ticker.h | 77 +++++++++++++++------------------ 2 files changed, 38 insertions(+), 51 deletions(-) diff --git a/libraries/Ticker/src/Ticker.cpp b/libraries/Ticker/src/Ticker.cpp index dca4435dc2..4aa23be650 100644 --- a/libraries/Ticker/src/Ticker.cpp +++ b/libraries/Ticker/src/Ticker.cpp @@ -33,7 +33,7 @@ Ticker::~Ticker() detach(); } -void Ticker::_attach_ms(uint32_t milliseconds, bool repeat, callback_with_arg_t callback, void* arg) +void Ticker::_attach_ms(uint32_t milliseconds, bool repeat, callback_with_arg_t* callback, void* arg) { if (_timer) { @@ -43,7 +43,6 @@ void Ticker::_attach_ms(uint32_t milliseconds, bool repeat, callback_with_arg_t { _timer = &_etsTimer; } - os_timer_setfn(_timer, callback, arg); os_timer_arm(_timer, milliseconds, repeat); } @@ -55,17 +54,10 @@ void Ticker::detach() os_timer_disarm(_timer); _timer = nullptr; - _callback_function = nullptr; + _callback = nullptr; } bool Ticker::active() const { return _timer; } - -void Ticker::_static_callback(void* arg) -{ - Ticker* _this = reinterpret_cast(arg); - if (_this && _this->_callback_function) - _this->_callback_function(); -} diff --git a/libraries/Ticker/src/Ticker.h b/libraries/Ticker/src/Ticker.h index 791ff94567..39cf438825 100644 --- a/libraries/Ticker/src/Ticker.h +++ b/libraries/Ticker/src/Ticker.h @@ -22,7 +22,7 @@ #ifndef TICKER_H #define TICKER_H -#include +#include #include #include @@ -32,42 +32,42 @@ class Ticker Ticker(); ~Ticker(); - typedef void (*callback_with_arg_t)(void*); - typedef std::function callback_function_t; + using callback_t = Delegate; + using callback_with_arg_t = void(void*); // callback will be called at following loop() after ticker fires - void attach_scheduled(float seconds, callback_function_t callback) + void attach_scheduled(float seconds, callback_t callback) { - _callback_function = [callback]() { schedule_function(callback); }; - _attach_ms(1000UL * seconds, true); + _callback = [callback]() { schedule_function(callback); }; + _attach_ms(1000UL * seconds, true, _callback, _callback.arg()); } // callback will be called in SYS ctx when ticker fires - void attach(float seconds, callback_function_t callback) + void attach(float seconds, callback_t callback) { - _callback_function = std::move(callback); - _attach_ms(1000UL * seconds, true); + _callback = std::move(callback); + _attach_ms(1000UL * seconds, true, _callback, _callback.arg()); } // callback will be called at following loop() after ticker fires - void attach_ms_scheduled(uint32_t milliseconds, callback_function_t callback) + void attach_ms_scheduled(uint32_t milliseconds, callback_t callback) { - _callback_function = [callback]() { schedule_function(callback); }; - _attach_ms(milliseconds, true); + _callback = [callback]() { schedule_function(callback); }; + _attach_ms(milliseconds, true, _callback, _callback.arg()); } // callback will be called at following yield() after ticker fires - void attach_ms_scheduled_accurate(uint32_t milliseconds, callback_function_t callback) + void attach_ms_scheduled_accurate(uint32_t milliseconds, callback_t callback) { - _callback_function = [callback]() { schedule_recurrent_function_us([callback]() { callback(); return false; }, 0); }; - _attach_ms(milliseconds, true); + _callback = [callback]() { schedule_recurrent_function_us([callback]() { callback(); return false; }, 0); }; + _attach_ms(milliseconds, true, _callback, _callback.arg()); } // callback will be called in SYS ctx when ticker fires - void attach_ms(uint32_t milliseconds, callback_function_t callback) + void attach_ms(uint32_t milliseconds, callback_t callback) { - _callback_function = std::move(callback); - _attach_ms(milliseconds, true); + _callback = std::move(callback); + _attach_ms(milliseconds, true, _callback, _callback.arg()); } // callback will be called in SYS ctx when ticker fires @@ -77,7 +77,7 @@ class Ticker #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wcast-function-type" static_assert(sizeof(TArg) <= sizeof(void*), "attach() callback argument size must be <= sizeof(void*)"); - _attach_ms(1000UL * seconds, true, reinterpret_cast(callback), reinterpret_cast(arg)); + _attach_ms(1000UL * seconds, true, reinterpret_cast(callback), reinterpret_cast(arg)); #pragma GCC diagnostic pop } @@ -88,36 +88,36 @@ class Ticker #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wcast-function-type" static_assert(sizeof(TArg) <= sizeof(void*), "attach() callback argument size must be <= sizeof(void*)"); - _attach_ms(milliseconds, true, reinterpret_cast(callback), reinterpret_cast(arg)); + _attach_ms(milliseconds, true, reinterpret_cast(callback), reinterpret_cast(arg)); #pragma GCC diagnostic pop } // callback will be called at following loop() after ticker fires - void once_scheduled(float seconds, callback_function_t callback) + void once_scheduled(float seconds, callback_t callback) { - _callback_function = [callback]() { schedule_function(callback); }; - _attach_ms(1000UL * seconds, false); + _callback = [callback]() { schedule_function(callback); }; + _attach_ms(1000UL * seconds, false, _callback, _callback.arg()); } // callback will be called in SYS ctx when ticker fires - void once(float seconds, callback_function_t callback) + void once(float seconds, callback_t callback) { - _callback_function = std::move(callback); - _attach_ms(1000UL * seconds, false); + _callback = std::move(callback); + _attach_ms(1000UL * seconds, false, _callback, _callback.arg()); } // callback will be called at following loop() after ticker fires - void once_ms_scheduled(uint32_t milliseconds, callback_function_t callback) + void once_ms_scheduled(uint32_t milliseconds, callback_t callback) { - _callback_function = [callback]() { schedule_function(callback); }; - _attach_ms(milliseconds, false); + _callback = [callback]() { schedule_function(callback); }; + _attach_ms(milliseconds, false, _callback, _callback.arg()); } // callback will be called in SYS ctx when ticker fires - void once_ms(uint32_t milliseconds, callback_function_t callback) + void once_ms(uint32_t milliseconds, callback_t callback) { - _callback_function = std::move(callback); - _attach_ms(milliseconds, false); + _callback = std::move(callback); + _attach_ms(milliseconds, false, _callback, _callback.arg()); } // callback will be called in SYS ctx when ticker fires @@ -125,7 +125,7 @@ class Ticker void once(float seconds, void (*callback)(TArg), TArg arg) { static_assert(sizeof(TArg) <= sizeof(void*), "attach() callback argument size must be <= sizeof(void*)"); - _attach_ms(1000UL * seconds, false, reinterpret_cast(callback), reinterpret_cast(arg)); + _attach_ms(1000UL * seconds, false, reinterpret_cast(callback), reinterpret_cast(arg)); } // callback will be called in SYS ctx when ticker fires @@ -133,22 +133,17 @@ class Ticker void once_ms(uint32_t milliseconds, void (*callback)(TArg), TArg arg) { static_assert(sizeof(TArg) <= sizeof(void*), "attach() callback argument size must be <= sizeof(void*)"); - _attach_ms(milliseconds, false, reinterpret_cast(callback), reinterpret_cast(arg)); + _attach_ms(milliseconds, false, reinterpret_cast(callback), reinterpret_cast(arg)); } void detach(); bool active() const; protected: - static void _static_callback(void* arg); - void _attach_ms(uint32_t milliseconds, bool repeat, callback_with_arg_t callback, void* arg); - void _attach_ms(uint32_t milliseconds, bool repeat) - { - _attach_ms(milliseconds, repeat, _static_callback, this); - } + void _attach_ms(uint32_t milliseconds, bool repeat, callback_with_arg_t* callback, void* arg); ETSTimer* _timer; - callback_function_t _callback_function = nullptr; + callback_t _callback = nullptr; private: ETSTimer _etsTimer; From c55ffe650108aafb44cbfcd2e148f822d5ea1e74 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Wed, 22 Jan 2020 08:52:08 +0100 Subject: [PATCH 54/55] std::bind is IRAM cache safe, but lambdas are not. --- libraries/Ticker/src/Ticker.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/Ticker/src/Ticker.h b/libraries/Ticker/src/Ticker.h index 39cf438825..0b4f3ec1f6 100644 --- a/libraries/Ticker/src/Ticker.h +++ b/libraries/Ticker/src/Ticker.h @@ -38,7 +38,7 @@ class Ticker // callback will be called at following loop() after ticker fires void attach_scheduled(float seconds, callback_t callback) { - _callback = [callback]() { schedule_function(callback); }; + _callback = std::bind(schedule_function, callback); _attach_ms(1000UL * seconds, true, _callback, _callback.arg()); } @@ -52,14 +52,14 @@ class Ticker // callback will be called at following loop() after ticker fires void attach_ms_scheduled(uint32_t milliseconds, callback_t callback) { - _callback = [callback]() { schedule_function(callback); }; + _callback = std::bind(schedule_function, callback); _attach_ms(milliseconds, true, _callback, _callback.arg()); } // callback will be called at following yield() after ticker fires void attach_ms_scheduled_accurate(uint32_t milliseconds, callback_t callback) { - _callback = [callback]() { schedule_recurrent_function_us([callback]() { callback(); return false; }, 0); }; + _callback = std::bind(schedule_recurrent_function_us, [callback]() { callback(); return false; }, 0, nullptr); _attach_ms(milliseconds, true, _callback, _callback.arg()); } @@ -95,7 +95,7 @@ class Ticker // callback will be called at following loop() after ticker fires void once_scheduled(float seconds, callback_t callback) { - _callback = [callback]() { schedule_function(callback); }; + _callback = std::bind(schedule_function, callback); _attach_ms(1000UL * seconds, false, _callback, _callback.arg()); } @@ -109,7 +109,7 @@ class Ticker // callback will be called at following loop() after ticker fires void once_ms_scheduled(uint32_t milliseconds, callback_t callback) { - _callback = [callback]() { schedule_function(callback); }; + _callback = std::bind(schedule_function, callback); _attach_ms(milliseconds, false, _callback, _callback.arg()); } From 1878d6f30169f77acc8490863012f27c4caf148e Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Fri, 2 Apr 2021 16:20:58 +0200 Subject: [PATCH 55/55] Review has proven that Ticker callbacks are documented to occur in SYS context, they are scheduled, not called in ISR. --- .../examples/TickerFunctional/TickerFunctional.ino | 6 ++++-- libraries/Ticker/src/Ticker.h | 10 +++++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/libraries/Ticker/examples/TickerFunctional/TickerFunctional.ino b/libraries/Ticker/examples/TickerFunctional/TickerFunctional.ino index 33c9435982..83b26e54f1 100644 --- a/libraries/Ticker/examples/TickerFunctional/TickerFunctional.ino +++ b/libraries/Ticker/examples/TickerFunctional/TickerFunctional.ino @@ -12,7 +12,9 @@ class ExampleClass { public: ExampleClass(int pin, int duration) : _pin(pin), _duration(duration) { pinMode(_pin, OUTPUT); - _myTicker.attach_ms(_duration, std::bind(&ExampleClass::classBlink, this)); + _myTicker.attach_ms(_duration, [this]() { + classBlink(); + }); } ~ExampleClass() {}; @@ -52,7 +54,7 @@ void setup() { scheduledTicker.attach_ms_scheduled(100, scheduledBlink); pinMode(LED4, OUTPUT); - parameterTicker.attach_ms(100, std::bind(parameterBlink, LED4)); + parameterTicker.attach_ms(100, parameterBlink, LED4); pinMode(LED5, OUTPUT); lambdaTicker.attach_ms(100, []() { diff --git a/libraries/Ticker/src/Ticker.h b/libraries/Ticker/src/Ticker.h index 0b4f3ec1f6..39cf438825 100644 --- a/libraries/Ticker/src/Ticker.h +++ b/libraries/Ticker/src/Ticker.h @@ -38,7 +38,7 @@ class Ticker // callback will be called at following loop() after ticker fires void attach_scheduled(float seconds, callback_t callback) { - _callback = std::bind(schedule_function, callback); + _callback = [callback]() { schedule_function(callback); }; _attach_ms(1000UL * seconds, true, _callback, _callback.arg()); } @@ -52,14 +52,14 @@ class Ticker // callback will be called at following loop() after ticker fires void attach_ms_scheduled(uint32_t milliseconds, callback_t callback) { - _callback = std::bind(schedule_function, callback); + _callback = [callback]() { schedule_function(callback); }; _attach_ms(milliseconds, true, _callback, _callback.arg()); } // callback will be called at following yield() after ticker fires void attach_ms_scheduled_accurate(uint32_t milliseconds, callback_t callback) { - _callback = std::bind(schedule_recurrent_function_us, [callback]() { callback(); return false; }, 0, nullptr); + _callback = [callback]() { schedule_recurrent_function_us([callback]() { callback(); return false; }, 0); }; _attach_ms(milliseconds, true, _callback, _callback.arg()); } @@ -95,7 +95,7 @@ class Ticker // callback will be called at following loop() after ticker fires void once_scheduled(float seconds, callback_t callback) { - _callback = std::bind(schedule_function, callback); + _callback = [callback]() { schedule_function(callback); }; _attach_ms(1000UL * seconds, false, _callback, _callback.arg()); } @@ -109,7 +109,7 @@ class Ticker // callback will be called at following loop() after ticker fires void once_ms_scheduled(uint32_t milliseconds, callback_t callback) { - _callback = std::bind(schedule_function, callback); + _callback = [callback]() { schedule_function(callback); }; _attach_ms(milliseconds, false, _callback, _callback.arg()); }