/*+ ARES/HADES/BORG Package -- ./libLSS/tools/static_init.hpp Copyright (C) 2014-2020 Guilhem Lavaux Copyright (C) 2009-2020 Jens Jasche Additional contributions from: Guilhem Lavaux (2023) +*/ #ifndef __LIBLSS_STATIC_INIT_HPP #define __LIBLSS_STATIC_INIT_HPP #include #include #include #include #include "libLSS/tools/console.hpp" #include "libLSS/tools/log_traits.hpp" namespace LibLSS { #if !defined(DOXYGEN_SHOULD_SKIP_THIS) class RegisterStaticInitBase { protected: int priority; std::string text; friend struct CompareStaticInit; friend struct CompareStaticFinal; friend class StaticInit; public: virtual void executeStaticInit() = 0; virtual void executeStaticFinal() = 0; virtual ~RegisterStaticInitBase() {} }; struct CompareStaticInit { bool operator()(RegisterStaticInitBase *a, RegisterStaticInitBase *b) { return a->priority >= b->priority; } }; struct CompareStaticFinal { bool operator()(RegisterStaticInitBase *a, RegisterStaticInitBase *b) { return a->priority <= b->priority; } }; #endif /** * Helper class to handle initialization of some global state. * There is by design only one instance of this class. It may obtained * through the static method StaticInit::instance(). * Nearly all test cases give an example of the use this API. Typically, * this is the first line of code and the last line of code in the "main" * function. * @code * int main() { * StaticInit::initialize(); * // Do something * StaticInit::finalize(); * return 0; * } * @endcode * The initializers and finalizers are executed according to their priority code, * provided at the registration. * * @see LibLSS::RegisterStaticInit * @see LibLSS::Console */ class StaticInit { private: StaticInit() {} void _execute() { while (!all_initializers.empty()) { RegisterStaticInitBase *i = all_initializers.top(); if (i->text.length() > 0) { Console::instance().print("INIT: " + i->text); } i->executeStaticInit(); all_initializers.pop(); } } void _finalize() { while (!all_finalizers.empty()) { RegisterStaticInitBase *i = all_finalizers.top(); if (i->text.length() > 0) { Console::instance().print("CLEANUP: " + i->text); } i->executeStaticFinal(); all_finalizers.pop(); } } public: static const int MAX_PRIORITY = 0; static const int MIN_PRIORITY = 99; typedef std::priority_queue, CompareStaticInit> InitList; typedef std::priority_queue, CompareStaticFinal> FinalList; InitList all_initializers; FinalList all_finalizers; static StaticInit& instance(); /** * @see LibLSS::RegisterStaticInit */ void add(RegisterStaticInitBase *b) { all_initializers.push(b); all_finalizers.push(b); } /** * Run all initializers. */ static void execute() { instance()._execute(); } /** * Run all finalizers. */ static void finalize() { instance()._finalize(); } }; /** * Specific implementation of a registrator for static initializer . * It introduces itself directly in the queue of the sole instance of the class LibLSS::StaticInit. * They then call the adequate functors in initialization or finalization stage. */ class RegisterStaticInit: public RegisterStaticInitBase { public: /** * Hold the initializer functor. */ std::function function; /** * Hold the finalizer functor. */ std::function function_final; /** * Constructor, without finalizer. * * @param f The functor corresponding to initialization. There is no finalizer in this case. * @param _priority The execution priority. * @param _text an information to print in debug mode. */ template RegisterStaticInit(Derived f, int _priority = StaticInit::MIN_PRIORITY, const std::string& _text = "") { function = f; this->priority = _priority; this->text = _text; StaticInit::instance().all_initializers.push(this); } /** * Constructor. * @param f The functor corresponding to initialization. * @param f2 The functor corresponding to finalization. * @param _priority The execution priority. * @param _text an information to print in debug mode. */ template RegisterStaticInit(Derived1 f, Derived2 f2, int _priority = StaticInit::MIN_PRIORITY, const std::string& _text = "") { function = f; function_final = f2; this->priority = _priority; this->text = _text; StaticInit::instance().all_initializers.push(this); StaticInit::instance().all_finalizers.push(this); } /** * Do not use. This is called by the internal machinery. */ virtual void executeStaticInit() { function(); } /** * Do not use. This is called by the internal machinery. */ virtual void executeStaticFinal() { if (function_final) function_final(); } private: RegisterStaticInit() { } }; }; #endif