diff --git a/src/lib/depend-inject.hpp b/src/lib/depend-inject.hpp index e667af3b1..11342c059 100644 --- a/src/lib/depend-inject.hpp +++ b/src/lib/depend-inject.hpp @@ -160,6 +160,7 @@ namespace lib { public: /** configure dependency-injection for type SRV to build a subclass singleton + * @note actually a delegation to `Depend` is installed into `Depend` * @tparam SUB concrete subclass type to build on demand when invoking `Depend` * @throws error::Logic (LUMIERA_ERROR_LIFECYCLE) when the default factory has already * been invoked at the point when calling this (re)configuration function. @@ -168,11 +169,14 @@ namespace lib { static void useSingleton() { - installFactory ([]{ return & Depend{}(); }); + __assert_compatible(); + installFactory(); } /** configure dependency-injection for type SRV to manage a subclass singleton, * which is created lazily on demand by invoking the given builder function + * @note actual Subclass type is determined from the given functor and then + * a delegation to `Depend` is installed into `Depend` * @param ctor functor to create a heap allocated instance of subclass * @throws error::Logic (LUMIERA_ERROR_LIFECYCLE) when the default factory has already * been invoked at the point when calling this (re)configuration function. @@ -181,11 +185,11 @@ namespace lib { static void useSingleton(FUN&& ctor) { - using Fun = typename SubclassFactory::Fun; - using Sub = typename SubclassFactory::Sub; - __assert_compatible(); + using Fun = typename SubclassFactoryType::Fun; + using Sub = typename SubclassFactoryType::Sub; - installFactory (buildCustomSingleton (forward (ctor))); + __assert_compatible(); + installFactory (forward (ctor)); } @@ -258,7 +262,7 @@ namespace lib { std::unique_ptr mock_; SRV* origInstance_; - Factory origFactory_; + DependencyFactory origFactory_; public: Local() @@ -270,7 +274,7 @@ namespace lib { Local (FUN&& buildInstance) { __assert_compatible(); - __assert_compatible::Sub>(); + __assert_compatible::Sub>(); temporarilyInstallAlternateFactory (origInstance_, origFactory_ ,[=]() @@ -281,7 +285,7 @@ namespace lib { } ~Local() { - restoreOriginalFactory (origInstance_, origFactory_); + restoreOriginalFactory (origInstance_, move(origFactory_)); } explicit @@ -322,8 +326,17 @@ namespace lib { ,"Installed implementation class must be compatible to the interface."); } + static void + __ensure_pristine() + { + if (Depend::instance) + throw error::Logic("Attempt to reconfigure dependency injection after the fact. " + "The previously installed factory (typically Singleton) was already used." + , error::LUMIERA_ERROR_LIFECYCLE); + } + template - struct SubclassFactory + struct SubclassFactoryType { static_assert (meta::_Fun(), "Need a Lambda or Function object to create a heap allocated instance"); @@ -337,49 +350,53 @@ namespace lib { }; + template static void - installFactory (Factory&& otherFac) + installFactory (FUN&& ctor) { Lock guard; - if (Depend::instance) - throw error::Logic("Attempt to reconfigure dependency injection after the fact. " - "The previously installed factory (typically Singleton) was already used." - , error::LUMIERA_ERROR_LIFECYCLE); - Depend::factory = move (otherFac); - } - - /** wrap custom factory function to plant a singleton instance - * @remark call through this intermediary function because we need to capture a _copy_ of the functor, - * to invoke it later, on-demand. Especially we need the ability to change the type of this functor, - * since sometimes the argument is passed as function reference, which can not be instantiated, - * but needs to be wrapped into a std::function. */ - template - static Factory - buildCustomSingleton (FUN&& ctor) - { - static std::unique_ptr singleton; - return ([ctor]() // copy of ctor in the closure - { - singleton.reset (ctor()); - return singleton.get(); - }); + if (std::is_same()) + { + __ensure_pristine(); + Depend::factory.defineCreatorAndManage (forward (ctor)); + } + else + { + __ensure_pristine(); + Depend::factory.defineCreator ([]{ return & Depend{}(); }); + DependInject::useSingleton (forward (ctor)); + } // delegate actual instance creation to Depend } + template static void - temporarilyInstallAlternateFactory (SRV*& stashInstance, Factory& stashFac, Factory&& newFac) + installFactory () + { + if (not std::is_same()) + { + Lock guard; + __ensure_pristine(); + Depend::factory.defineCreator ([]{ return & Depend{}(); }); + } + } + + + template + static void + temporarilyInstallAlternateFactory (SRV*& stashInstance, Factory& stashFac, FUN&& newFac) { Lock guard; - stashFac = move(Depend::factory); + stashFac = move(Depend::factory); //////////////////////////////////////TICKET #1059 : GCC-4.9 stubbornly picks the copy assignment stashInstance = Depend::instance; - Depend::factory = move(newFac); + Depend::factory.defineCreator (forward(newFac)); //////////////////////////////////////TICKET #1059 : GCC-4.9 stubbornly picks the copy assignment Depend::instance = nullptr; } static void - restoreOriginalFactory (SRV*& stashInstance, Factory& stashFac) + restoreOriginalFactory (SRV*& stashInstance, Factory&& stashFac) { Lock guard; - Depend::factory = move(stashFac); + Depend::factory = move(stashFac); //////////////////////////////////////TICKET #1059 : GCC-4.9 stubbornly picks the copy assignment Depend::instance = stashInstance; } @@ -392,7 +409,7 @@ namespace lib { "but another instance has already been dependency-injected." , error::LUMIERA_ERROR_LIFECYCLE); Depend::instance = &newInstance; - Depend::factory = Depend::disabledFactory; + Depend::factory.disable(); } static void @@ -400,7 +417,7 @@ namespace lib { { Lock guard; Depend::instance = nullptr; - Depend::factory = Depend::disabledFactory; + Depend::factory.disable(); } }; diff --git a/src/lib/depend2.hpp b/src/lib/depend2.hpp index 9faad643c..0277b7b54 100644 --- a/src/lib/depend2.hpp +++ b/src/lib/depend2.hpp @@ -110,7 +110,7 @@ namespace lib { */ template class DependencyFactory - : util::MoveOnly +// : util::MoveAssign //////////////////////////////////////////////TICKET #1059 : GCC-4.9 stubbornly picks the copy assignment { using Creator = std::function; using Deleter = std::function; @@ -126,11 +126,6 @@ namespace lib { deleter_(); } - explicit operator bool() const - { - return bool(creator_); - } - OBJ* operator() () { @@ -138,15 +133,37 @@ namespace lib { : buildAndManage(); } - OBJ* - buildAndManage() + template + void + defineCreator (FUN&& ctor) { - OBJ* obj = buildInstance(); - atDestruction ([obj]{ delete obj; }); + creator_ = std::forward (ctor); } template - DependencyFactory& + void + defineCreatorAndManage (FUN&& ctor) + { + creator_ = [this,ctor] + { + OBJ* obj = ctor(); + atDestruction ([obj]{ delete obj; }); + return obj; + }; + } + + void + disable() + { + creator_ = []() -> OBJ* + { + throw error::Fatal("Service not available at this point of the Application Lifecycle" + ,error::LUMIERA_ERROR_LIFECYCLE); + }; + } + + template + void atDestruction (FUN&& additionalAction) { if (deleter_) @@ -160,10 +177,24 @@ namespace lib { } else deleter_ = std::forward (additionalAction); - return *this; } private: + OBJ* + buildAndManage() + { + OBJ* obj = buildInstance(); + atDestruction ([obj]{ delete obj; }); + return obj; + } + + template + static meta::enable_if, + TAR* > + buildInstance() + { + return new TAR; + } template static meta::enable_if, ABS* > @@ -172,21 +203,14 @@ namespace lib { throw error::Fatal("Attempt to create a singleton instance of an abstract class. " "Application architecture or lifecycle is seriously broken."); } - template - static meta::disable_if, - TAR* > + template + static meta::disable_if,std::is_constructible>, + ABS* > buildInstance() { - return new TAR; + throw error::Fatal("Desired singleton class is not default constructible. " + "Application architecture or lifecycle is seriously broken."); } - - static void - destroy (OBJ* obj) - { - if (obj) - delete obj; - } - }; @@ -214,11 +238,11 @@ namespace lib { template class Depend { - using Factory = std::function; + using Factory = DependencyFactory; using Lock = ClassLock; static std::atomic instance; - static Factory factory; + static DependencyFactory factory; friend class DependInject; @@ -240,75 +264,15 @@ namespace lib { object = instance.load (std::memory_order_relaxed); if (!object) { - if (!factory) - { - object = buildInstance(); - deleter = []{ - destroy (instance); - instance = nullptr; - }; - } - else - object = factory(); - factory = disabledFactory; + object = factory(); + factory.disable(); + factory.atDestruction([]{ instance = nullptr; }); } instance.store (object, std::memory_order_release); } ENSURE (object); return *object; } - - - private: - /** @internal preconfigured factory to block any (further) on-demand instance creation */ - static SRV* - disabledFactory() - { - throw error::Fatal("Service not available at this point of the Application Lifecycle" - ,error::LUMIERA_ERROR_LIFECYCLE); - } - - template - static meta::enable_if, - ABS* > - buildInstance() - { - throw error::Fatal("Attempt to create a singleton instance of an abstract class. " - "Application architecture or lifecycle is seriously broken."); - } - template - static meta::disable_if, - TAR* > - buildInstance() - { - return new TAR; - } - - static void - destroy (SRV* obj) - { - if (obj) - delete obj; - } - - class Deleter - { - std::function cleanUp_; - - public: - ~Deleter() - { - if (cleanUp_) - cleanUp_(); - } - template - void operator= (DEL&& fun) - { - cleanUp_ = std::forward (fun); - } - }; - - static Deleter deleter; }; @@ -319,10 +283,7 @@ namespace lib { std::atomic Depend::instance; template - typename Depend::Factory Depend::factory; - - template - typename Depend::Deleter Depend::deleter; + DependencyFactory Depend::factory; diff --git a/src/lib/nocopy.hpp b/src/lib/nocopy.hpp index cf56310aa..3ce888b39 100644 --- a/src/lib/nocopy.hpp +++ b/src/lib/nocopy.hpp @@ -58,12 +58,26 @@ namespace util { class MoveOnly { protected: - ~MoveOnly() = default; - MoveOnly() = default; - MoveOnly (MoveOnly&&) = default; - MoveOnly (MoveOnly const&) = delete; - MoveOnly& operator= (MoveOnly&&) = delete; - MoveOnly& operator= (MoveOnly const&) = delete; + ~MoveOnly() = default; + MoveOnly() = default; + MoveOnly (MoveOnly&&) = default; + MoveOnly (MoveOnly const&) = delete; + MoveOnly& operator= (MoveOnly&&) = delete; + MoveOnly& operator= (MoveOnly const&) = delete; + }; + + /** + * Types marked with this mix-in may be moved and move-assigned + */ + class MoveAssign + { + protected: + ~MoveAssign() = default; + MoveAssign() = default; + MoveAssign (MoveAssign&&) = default; + MoveAssign (MoveAssign const&) = delete; + MoveAssign& operator= (MoveAssign&&) = default; + MoveAssign& operator= (MoveAssign const&) = delete; }; /** @@ -77,12 +91,12 @@ namespace util { class Cloneable { protected: - ~Cloneable() = default; - Cloneable() = default; - Cloneable (Cloneable&&) = default; - Cloneable (Cloneable const&) = default; - Cloneable& operator= (Cloneable&&) = delete; - Cloneable& operator= (Cloneable const&) = delete; + ~Cloneable() = default; + Cloneable() = default; + Cloneable (Cloneable&&) = default; + Cloneable (Cloneable const&) = default; + Cloneable& operator= (Cloneable&&) = delete; + Cloneable& operator= (Cloneable const&) = delete; }; /** diff --git a/tests/library/singleton-subclass-test.cpp b/tests/library/singleton-subclass-test.cpp index 90f9a76e9..04634edf6 100644 --- a/tests/library/singleton-subclass-test.cpp +++ b/tests/library/singleton-subclass-test.cpp @@ -66,7 +66,7 @@ namespace test{ Interface () : TestTargetObj(cnt) {} virtual ~Interface() {} - friend class lib::Depend; + friend class lib::DependencyFactory; }; int Interface::cnt = 0; diff --git a/tests/library/singleton-test.cpp b/tests/library/singleton-test.cpp index 6ae29744d..519060060 100644 --- a/tests/library/singleton-test.cpp +++ b/tests/library/singleton-test.cpp @@ -59,7 +59,7 @@ namespace test{ protected: TargetObj () : TestTargetObj(cnt) {} - friend class lib::Depend; + friend class lib::DependencyFactory; }; int TargetObj::cnt = 0; diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index fc70113b5..9501c5a1a 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -27772,8 +27772,8 @@ - - + + @@ -27787,35 +27787,89 @@ - - + + - - + + - - + + - - + + - - - - + + + + - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +