Merge branch 'modules-cleanup'

Modernize wxModule code and add AreInitialized() function.

See https://github.com/wxWidgets/wxWidgets/pull/2268
This commit is contained in:
Vadim Zeitlin
2021-03-07 23:51:04 +01:00
3 changed files with 76 additions and 67 deletions

View File

@@ -12,18 +12,11 @@
#define _WX_MODULE_H_ #define _WX_MODULE_H_
#include "wx/object.h" #include "wx/object.h"
#include "wx/list.h" #include "wx/vector.h"
#include "wx/arrstr.h"
#include "wx/dynarray.h"
// declare a linked list of modules class wxModule;
class WXDLLIMPEXP_FWD_BASE wxModule;
WX_DECLARE_USER_EXPORTED_LIST(wxModule, wxModuleList, WXDLLIMPEXP_BASE);
// and an array of class info objects
WX_DEFINE_USER_EXPORTED_ARRAY_PTR(wxClassInfo *, wxArrayClassInfo,
class WXDLLIMPEXP_BASE);
typedef wxVector<wxModule*> wxModuleList;
// declaring a class derived from wxModule will automatically create an // declaring a class derived from wxModule will automatically create an
// instance of this class on program startup, call its OnInit() method and call // instance of this class on program startup, call its OnInit() method and call
@@ -54,14 +47,17 @@ public:
static void RegisterModule(wxModule *module); static void RegisterModule(wxModule *module);
static void RegisterModules(); static void RegisterModules();
static bool InitializeModules(); static bool InitializeModules();
static void CleanUpModules() { DoCleanUpModules(m_modules); } static void CleanUpModules();
static bool AreInitialized() { return ms_areInitialized; }
// used by wxObjectLoader when unloading shared libs's // used by wxObjectLoader when unloading shared libs's
static void UnregisterModule(wxModule *module); static void UnregisterModule(wxModule *module);
protected: protected:
static wxModuleList m_modules; static wxModuleList ms_modules;
static bool ms_areInitialized;
// the function to call from constructor of a deriving class add module // the function to call from constructor of a deriving class add module
// dependency which will be initialized before the module and unloaded // dependency which will be initialized before the module and unloaded
@@ -70,14 +66,14 @@ protected:
{ {
wxCHECK_RET( dep, wxT("NULL module dependency") ); wxCHECK_RET( dep, wxT("NULL module dependency") );
m_dependencies.Add(dep); m_dependencies.push_back(dep);
} }
// same as the version above except it will look up wxClassInfo by name on // same as the version above except it will look up wxClassInfo by name on
// its own. Note that className must be ASCII // its own. Note that className must be ASCII
void AddDependency(const char *className) void AddDependency(const char *className)
{ {
m_namedDependencies.Add(wxASCII_STR(className)); m_namedDependencies.push_back(wxASCII_STR(className));
} }
@@ -89,7 +85,7 @@ private:
// cleanup the modules in the specified list (which may not contain all // cleanup the modules in the specified list (which may not contain all
// modules if we're called during initialization because not all modules // modules if we're called during initialization because not all modules
// could be initialized) and also empty m_modules itself // could be initialized) and also empty ms_modules itself
static void DoCleanUpModules(const wxModuleList& modules); static void DoCleanUpModules(const wxModuleList& modules);
// resolve all named dependencies and add them to the normal m_dependencies // resolve all named dependencies and add them to the normal m_dependencies
@@ -98,11 +94,12 @@ private:
// module dependencies: contains wxClassInfo pointers for all modules which // module dependencies: contains wxClassInfo pointers for all modules which
// must be initialized before this one // must be initialized before this one
typedef wxVector<wxClassInfo*> wxArrayClassInfo;
wxArrayClassInfo m_dependencies; wxArrayClassInfo m_dependencies;
// and the named dependencies: those will be resolved during run-time and // and the named dependencies: those will be resolved during run-time and
// added to m_dependencies // added to m_dependencies
wxArrayString m_namedDependencies; wxVector<wxString> m_namedDependencies;
// used internally while initializing/cleaning up modules // used internally while initializing/cleaning up modules
enum enum

View File

@@ -20,25 +20,32 @@
#include "wx/log.h" #include "wx/log.h"
#endif #endif
#include "wx/listimpl.cpp"
#define TRACE_MODULE wxT("module") #define TRACE_MODULE wxT("module")
WX_DEFINE_LIST(wxModuleList)
wxIMPLEMENT_ABSTRACT_CLASS(wxModule, wxObject) wxIMPLEMENT_ABSTRACT_CLASS(wxModule, wxObject)
wxModuleList wxModule::m_modules; wxModuleList wxModule::ms_modules;
bool wxModule::ms_areInitialized = false;
void wxModule::RegisterModule(wxModule* module) void wxModule::RegisterModule(wxModule* module)
{ {
module->m_state = State_Registered; module->m_state = State_Registered;
m_modules.Append(module); ms_modules.push_back(module);
} }
void wxModule::UnregisterModule(wxModule* module) void wxModule::UnregisterModule(wxModule* module)
{ {
m_modules.DeleteObject(module); for ( wxModuleList::iterator it = ms_modules.begin();
it != ms_modules.end();
++it )
{
if ( *it == module )
{
ms_modules.erase(it);
break;
}
}
delete module; delete module;
} }
@@ -87,23 +94,25 @@ bool wxModule::DoInitializeModule(wxModule *module,
wxClassInfo * cinfo = dependencies[i]; wxClassInfo * cinfo = dependencies[i];
// Check if the module is already initialized // Check if the module is already initialized
wxModuleList::compatibility_iterator node; wxModuleList::const_iterator it;
for ( node = initializedModules.GetFirst(); node; node = node->GetNext() ) for ( it = initializedModules.begin();
it != initializedModules.end();
++it )
{ {
if ( node->GetData()->GetClassInfo() == cinfo ) if ( (*it)->GetClassInfo() == cinfo )
break; break;
} }
if ( node ) if ( it != initializedModules.end() )
{ {
// this dependency is already initialized, nothing to do // this dependency is already initialized, nothing to do
continue; continue;
} }
// find the module in the registered modules list // find the module in the registered modules list
for ( node = m_modules.GetFirst(); node; node = node->GetNext() ) for ( it = ms_modules.begin(); it != ms_modules.end(); ++it )
{ {
wxModule *moduleDep = node->GetData(); wxModule *moduleDep = *it;
if ( moduleDep->GetClassInfo() == cinfo ) if ( moduleDep->GetClassInfo() == cinfo )
{ {
if ( !DoInitializeModule(moduleDep, initializedModules ) ) if ( !DoInitializeModule(moduleDep, initializedModules ) )
@@ -116,7 +125,7 @@ bool wxModule::DoInitializeModule(wxModule *module,
} }
} }
if ( !node ) if ( it == ms_modules.end() )
{ {
wxLogError(_("Dependency \"%s\" of module \"%s\" doesn't exist."), wxLogError(_("Dependency \"%s\" of module \"%s\" doesn't exist."),
cinfo->GetClassName(), cinfo->GetClassName(),
@@ -136,7 +145,7 @@ bool wxModule::DoInitializeModule(wxModule *module,
module->GetClassInfo()->GetClassName()); module->GetClassInfo()->GetClassName());
module->m_state = State_Initialized; module->m_state = State_Initialized;
initializedModules.Append(module); initializedModules.push_back(module);
return true; return true;
} }
@@ -146,11 +155,11 @@ bool wxModule::InitializeModules()
{ {
wxModuleList initializedModules; wxModuleList initializedModules;
for ( wxModuleList::compatibility_iterator node = m_modules.GetFirst(); for ( wxModuleList::const_iterator it = ms_modules.begin();
node; it != ms_modules.end();
node = node->GetNext() ) ++it )
{ {
wxModule *module = node->GetData(); wxModule *module = *it;
// the module could have been already initialized as dependency of // the module could have been already initialized as dependency of
// another one // another one
@@ -168,24 +177,33 @@ bool wxModule::InitializeModules()
} }
// remember the real initialisation order // remember the real initialisation order
m_modules = initializedModules; ms_modules = initializedModules;
ms_areInitialized = true;
return true; return true;
} }
void wxModule::CleanUpModules()
{
DoCleanUpModules(ms_modules);
ms_areInitialized = false;
}
// Clean up all currently initialized modules // Clean up all currently initialized modules
void wxModule::DoCleanUpModules(const wxModuleList& modules) void wxModule::DoCleanUpModules(const wxModuleList& modules)
{ {
// cleanup user-defined modules in the reverse order compared to their // cleanup user-defined modules in the reverse order compared to their
// initialization -- this ensures that dependencies are respected // initialization -- this ensures that dependencies are respected
for ( wxModuleList::compatibility_iterator node = modules.GetLast(); for ( wxModuleList::const_reverse_iterator rit = modules.rbegin();
node; rit != modules.rend();
node = node->GetPrevious() ) ++rit )
{ {
wxLogTrace(TRACE_MODULE, wxT("Cleanup module %s"), wxLogTrace(TRACE_MODULE, wxT("Cleanup module %s"),
node->GetData()->GetClassInfo()->GetClassName()); (*rit)->GetClassInfo()->GetClassName());
wxModule * module = node->GetData(); wxModule * module = *rit;
wxASSERT_MSG( module->m_state == State_Initialized, wxASSERT_MSG( module->m_state == State_Initialized,
wxT("not initialized module being cleaned up") ); wxT("not initialized module being cleaned up") );
@@ -195,7 +213,14 @@ void wxModule::DoCleanUpModules(const wxModuleList& modules)
} }
// clear all modules, even the non-initialized ones // clear all modules, even the non-initialized ones
WX_CLEAR_LIST(wxModuleList, m_modules); for ( wxModuleList::const_iterator it = ms_modules.begin();
it != ms_modules.end();
++it )
{
delete *it;
}
ms_modules.clear();
} }
bool wxModule::ResolveNamedDependencies() bool wxModule::ResolveNamedDependencies()
@@ -214,7 +239,7 @@ bool wxModule::ResolveNamedDependencies()
// add it even if it is not derived from wxModule because // add it even if it is not derived from wxModule because
// DoInitializeModule() will make sure a module with the same class // DoInitializeModule() will make sure a module with the same class
// info exists and fail if it doesn't // info exists and fail if it doesn't
m_dependencies.Add(info); m_dependencies.push_back(info);
} }
return true; return true;

View File

@@ -15,16 +15,18 @@
#include "wx/module.h" #include "wx/module.h"
#include "wx/wxcrt.h" // for wxStrcat() #include "wx/wxcrt.h" // for wxStrcat()
static bool gs_wasInitialized = wxModule::AreInitialized();
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// test classes derived from wxModule // test classes derived from wxModule
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
char g_strLoadOrder[256] = "\0"; wxString g_strLoadOrder;
class Module : public wxModule class Module : public wxModule
{ {
protected: protected:
virtual bool OnInit() wxOVERRIDE { wxStrcat(g_strLoadOrder, GetClassInfo()->GetClassName()); return true; } virtual bool OnInit() wxOVERRIDE { g_strLoadOrder += GetClassInfo()->GetClassName(); return true; }
virtual void OnExit() wxOVERRIDE { } virtual void OnExit() wxOVERRIDE { }
}; };
@@ -86,32 +88,17 @@ ModuleD::ModuleD()
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// test class // tests themselves
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
class ModuleTestCase : public CppUnit::TestCase TEST_CASE("wxModule::Initialized", "[module]")
{ {
public: CHECK( !gs_wasInitialized );
ModuleTestCase() { } CHECK( wxModule::AreInitialized() );
}
private: TEST_CASE("wxModule::LoadOrder", "[module]")
CPPUNIT_TEST_SUITE( ModuleTestCase );
CPPUNIT_TEST( LoadOrder );
CPPUNIT_TEST_SUITE_END();
void LoadOrder();
wxDECLARE_NO_COPY_CLASS(ModuleTestCase);
};
// register in the unnamed registry so that these tests are run by default
CPPUNIT_TEST_SUITE_REGISTRATION( ModuleTestCase );
// also include in its own registry so that these tests can be run alone
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( ModuleTestCase, "ModuleTestCase" );
void ModuleTestCase::LoadOrder()
{ {
// module D is the only one with no dependencies and so should load as first (and so on): // module D is the only one with no dependencies and so should load as first (and so on):
CPPUNIT_ASSERT_EQUAL( std::string("ModuleDModuleCModuleBModuleA"), CHECK( g_strLoadOrder == "ModuleDModuleCModuleBModuleA" );
g_strLoadOrder );
} }