Merge branch 'develop' into feature/uiwebview

This commit is contained in:
Martín Lucas Golini
2026-07-04 00:13:15 -03:00
3 changed files with 163 additions and 115 deletions

View File

@@ -1,98 +1,128 @@
#ifndef EE_SYSTEMSINGLETON_H
#define EE_SYSTEMSINGLETON_H
#include <eepp/core.hpp>
#include <eepp/system/lock.hpp>
#include <eepp/system/mutex.hpp>
/** Internally we gonna use the macro singleton because it works with the engine compiled as dynamic
* libraries */
#define SINGLETON_DECLARE_HEADERS( T ) \
public: \
static T* createSingleton(); \
\
static T* existsSingleton(); \
\
static bool isShuttingDown(); \
\
static T* instance(); \
\
static void destroySingleton(); \
\
static void detachSingleton();
#define SINGLETON_DECLARE_IMPLEMENTATION( T ) \
\
static T* ms_singleton = NULL; \
static bool ms_is_shutting_down = false; \
static Mutex ms_mutex; \
\
T* T::createSingleton() { \
Lock l( ms_mutex ); \
if ( NULL == ms_singleton ) \
ms_singleton = eeNew( T, () ); \
return ms_singleton; \
} \
\
T* T::existsSingleton() { \
return ms_singleton; \
} \
\
bool T::isShuttingDown() { \
return ms_is_shutting_down; \
} \
\
T* T::instance() { \
return createSingleton(); \
} \
\
void T::destroySingleton() { \
ms_is_shutting_down = true; \
Lock l( ms_mutex ); \
eeSAFE_DELETE( ms_singleton ); \
ms_is_shutting_down = false; \
} \
\
void T::detachSingleton() { \
Lock l( ms_mutex ); \
ms_singleton = nullptr; \
}
namespace EE { namespace System {
/** @brief Template class for only one instance classes. */
template <typename T> class Singleton {
protected:
static T* ms_singleton;
static Mutex ms_mutex;
public:
/** Get the singleton pointer (without instance verification) */
static T* existsSingleton() {
return ms_singleton;
}
/** Get the singleton pointer */
static T* instance() {
Lock l( ms_mutex );
if ( NULL == ms_singleton )
ms_singleton = eeNew( T, () );
return ms_singleton;
}
/** Destroy the singleton instance */
static void destroySingleton() {
Lock l( ms_mutex );
eeSAFE_DELETE( ms_singleton );
}
/** Detaches the existing singleton. Instance will keep existing but not associated */
static void detachSingleton() {
Lock l( ms_mutex );
ms_singleton = nullptr;
}
};
}} // namespace EE::System
#endif
#ifndef EE_SYSTEMSINGLETON_H
#define EE_SYSTEMSINGLETON_H
#include <atomic>
#include <eepp/core.hpp>
#include <eepp/system/lock.hpp>
#include <eepp/system/mutex.hpp>
/** Internally we gonna use the macro singleton because it works with the engine compiled as dynamic
* libraries.
*
* Lifecycle contract:
* - Creation is thread-safe. The first caller creates the singleton under ms_mutex, publishes it
* with release semantics, and later callers use an acquire-load fast path without locking.
* - Destruction and detach are teardown operations only. They must not run concurrently with
* instance(), existsSingleton(), or normal use of a previously returned raw pointer. The atomic
* only protects pointer publication; it does not protect pointee lifetime after return.
* - destroySingleton() intentionally keeps the pointer visible while T::~T() runs because several
* eepp teardown paths query singleton state while ms_is_shutting_down is true.
* - Expand SINGLETON_DECLARE_IMPLEMENTATION exactly once in a .cpp file. Expanding it in a header
* creates one internal-linkage singleton per translation unit.
*/
#define SINGLETON_DECLARE_HEADERS( T ) \
public: \
static T* createSingleton(); \
\
static T* existsSingleton(); \
\
static bool isShuttingDown(); \
\
static T* instance(); \
\
static void destroySingleton(); \
\
static void detachSingleton();
#define SINGLETON_DECLARE_IMPLEMENTATION( T ) \
\
static std::atomic<T*> ms_singleton{ NULL }; \
static std::atomic<bool> ms_is_shutting_down{ false }; \
static Mutex ms_mutex; \
\
T* T::createSingleton() { \
T* singleton = ms_singleton.load( std::memory_order_acquire ); \
if ( NULL != singleton ) \
return singleton; \
Lock l( ms_mutex ); \
singleton = ms_singleton.load( std::memory_order_acquire ); \
if ( NULL == singleton ) { \
singleton = eeNew( T, () ); \
ms_singleton.store( singleton, std::memory_order_release ); \
} \
return singleton; \
} \
\
T* T::existsSingleton() { \
return ms_singleton.load( std::memory_order_acquire ); \
} \
\
bool T::isShuttingDown() { \
return ms_is_shutting_down.load( std::memory_order_acquire ); \
} \
\
T* T::instance() { \
return createSingleton(); \
} \
\
void T::destroySingleton() { \
ms_is_shutting_down.store( true, std::memory_order_release ); \
Lock l( ms_mutex ); \
T* singleton = ms_singleton.load( std::memory_order_acquire ); \
eeSAFE_DELETE( singleton ); \
ms_singleton.store( NULL, std::memory_order_release ); \
ms_is_shutting_down.store( false, std::memory_order_release ); \
} \
\
void T::detachSingleton() { \
Lock l( ms_mutex ); \
ms_singleton.store( nullptr, std::memory_order_release ); \
}
namespace EE { namespace System {
/** @brief Template class for only one instance classes.
* Creation is thread-safe, but destroySingleton() and detachSingleton() have the same teardown-only
* raw-pointer lifetime contract documented above for SINGLETON_DECLARE_IMPLEMENTATION.
*/
template <typename T> class Singleton {
protected:
static std::atomic<T*> ms_singleton;
static Mutex ms_mutex;
public:
/** Get the singleton pointer (without instance verification) */
static T* existsSingleton() { return ms_singleton.load( std::memory_order_acquire ); }
/** Get the singleton pointer */
static T* instance() {
T* singleton = ms_singleton.load( std::memory_order_acquire );
if ( NULL != singleton )
return singleton;
Lock l( ms_mutex );
singleton = ms_singleton.load( std::memory_order_acquire );
if ( NULL == singleton ) {
singleton = eeNew( T, () );
ms_singleton.store( singleton, std::memory_order_release );
}
return singleton;
}
/** Destroy the singleton instance */
static void destroySingleton() {
Lock l( ms_mutex );
T* singleton = ms_singleton.load( std::memory_order_acquire );
eeSAFE_DELETE( singleton );
ms_singleton.store( NULL, std::memory_order_release );
}
/** Detaches the existing singleton. Instance will keep existing but not associated */
static void detachSingleton() {
Lock l( ms_mutex );
ms_singleton.store( nullptr, std::memory_order_release );
}
};
}} // namespace EE::System
#endif

View File

@@ -32,25 +32,37 @@ std::unordered_map<std::string, LogLevel> Log::getMapFlag() {
Log* Log::create( const std::string& logPath, const LogLevel& level, bool stdOutLog,
bool liveWrite ) {
if ( NULL == ms_singleton ) {
ms_singleton = eeNew( Log, ( logPath, level, stdOutLog, liveWrite ) );
Log* singleton = ms_singleton.load( std::memory_order_acquire );
if ( NULL == singleton ) {
Lock l( ms_mutex );
singleton = ms_singleton.load( std::memory_order_acquire );
if ( NULL == singleton ) {
singleton = eeNew( Log, ( logPath, level, stdOutLog, liveWrite ) );
ms_singleton.store( singleton, std::memory_order_release );
}
} else {
ms_singleton->setLogLevelThreshold( level );
ms_singleton->setLogToStdOut( stdOutLog );
ms_singleton->setLiveWrite( liveWrite );
singleton->setLogLevelThreshold( level );
singleton->setLogToStdOut( stdOutLog );
singleton->setLiveWrite( liveWrite );
}
return ms_singleton;
return singleton;
}
Log* Log::create( const LogLevel& level, bool stdOutLog, bool liveWrite ) {
if ( NULL == ms_singleton ) {
ms_singleton = eeNew( Log, ( "", level, stdOutLog, liveWrite ) );
Log* singleton = ms_singleton.load( std::memory_order_acquire );
if ( NULL == singleton ) {
Lock l( ms_mutex );
singleton = ms_singleton.load( std::memory_order_acquire );
if ( NULL == singleton ) {
singleton = eeNew( Log, ( "", level, stdOutLog, liveWrite ) );
ms_singleton.store( singleton, std::memory_order_release );
}
} else {
ms_singleton->setLogLevelThreshold( level );
ms_singleton->setLogToStdOut( stdOutLog );
ms_singleton->setLiveWrite( liveWrite );
singleton->setLogLevelThreshold( level );
singleton->setLogToStdOut( stdOutLog );
singleton->setLiveWrite( liveWrite );
}
return ms_singleton;
return singleton;
}
Log::Log() : mSave( false ), mStdOutEnabled( false ), mLiveWrite( false ), mFS( NULL ) {

View File

@@ -163,11 +163,17 @@ SINGLETON_DECLARE_IMPLEMENTATION( SyntaxDefinitionManager )
SyntaxDefinitionManager*
SyntaxDefinitionManager::createSingleton( std::size_t reserveSpaceForLanguages ) {
if ( NULL == ms_singleton ) {
ms_singleton = eeNew( SyntaxDefinitionManager, ( reserveSpaceForLanguages ) );
SyntaxDefinitionManager* singleton = ms_singleton.load( std::memory_order_acquire );
if ( NULL == singleton ) {
Lock l( ms_mutex );
singleton = ms_singleton.load( std::memory_order_acquire );
if ( NULL == singleton ) {
singleton = eeNew( SyntaxDefinitionManager, ( reserveSpaceForLanguages ) );
ms_singleton.store( singleton, std::memory_order_release );
}
}
return ms_singleton;
return singleton;
}
static void addPlainText() {
@@ -179,8 +185,8 @@ static void addPlainText() {
// lite-plugins (https://github.com/rxi/lite-plugins) supported languages.
SyntaxDefinitionManager::SyntaxDefinitionManager( std::size_t reserveSpaceForLanguages ) {
if ( ms_singleton == nullptr )
ms_singleton = this;
if ( ms_singleton.load( std::memory_order_acquire ) == nullptr )
ms_singleton.store( this, std::memory_order_release );
{
Lock l( mMutex );