borg_public/libLSS/tools/static_init.hpp
2023-05-29 10:41:03 +02:00

201 lines
5.9 KiB
C++

/*+
ARES/HADES/BORG Package -- ./libLSS/tools/static_init.hpp
Copyright (C) 2014-2020 Guilhem Lavaux <guilhem.lavaux@iap.fr>
Copyright (C) 2009-2020 Jens Jasche <jens.jasche@fysik.su.se>
Additional contributions from:
Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
+*/
#ifndef __LIBLSS_STATIC_INIT_HPP
#define __LIBLSS_STATIC_INIT_HPP
#include <vector>
#include <queue>
#include <boost/function.hpp>
#include <string>
#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<LOG_DEBUG>("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<LOG_DEBUG>("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<RegisterStaticInitBase *, std::vector<RegisterStaticInitBase *>, CompareStaticInit> InitList;
typedef std::priority_queue<RegisterStaticInitBase *, std::vector<RegisterStaticInitBase *>, 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<void()> function;
/**
* Hold the finalizer functor.
*/
std::function<void()> 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<typename Derived>
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<typename Derived1, typename Derived2>
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