diff options
Diffstat (limited to 'Src/external_dependencies/openmpt-trunk/common/ComponentManager.h')
-rw-r--r-- | Src/external_dependencies/openmpt-trunk/common/ComponentManager.h | 508 |
1 files changed, 508 insertions, 0 deletions
diff --git a/Src/external_dependencies/openmpt-trunk/common/ComponentManager.h b/Src/external_dependencies/openmpt-trunk/common/ComponentManager.h new file mode 100644 index 00000000..6733ad07 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/common/ComponentManager.h @@ -0,0 +1,508 @@ +/* + * ComponentManager.h + * ------------------ + * Purpose: Manages loading of optional components. + * Notes : (currently none) + * Authors: Joern Heusipp + * OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + +#pragma once + +#include "openmpt/all/BuildSettings.hpp" + +#include "mpt/mutex/mutex.hpp" + +#include <map> +#include <vector> +#include "../common/misc_util.h" +#if defined(MODPLUG_TRACKER) +#include "../misc/mptLibrary.h" +#endif + + +OPENMPT_NAMESPACE_BEGIN + + +enum ComponentType +{ + ComponentTypeUnknown = 0, + ComponentTypeBuiltin, // PortAudio + ComponentTypeSystem, // mf.dll + ComponentTypeSystemInstallable, // acm mp3 codec + ComponentTypeBundled, // libsoundtouch + ComponentTypeForeign, // libmp3lame +}; + + +class ComponentFactoryBase; + + +class IComponent +{ + + friend class ComponentFactoryBase; + +protected: + + IComponent() = default; + +public: + + virtual ~IComponent() = default; + +public: + + virtual ComponentType GetType() const = 0; + + virtual bool IsInitialized() const = 0; // Initialize() has been called + virtual bool IsAvailable() const = 0; // Initialize() has been successfull + virtual mpt::ustring GetVersion() const = 0; + + virtual void Initialize() = 0; // try to load the component + +}; + + +class ComponentBase + : public IComponent +{ + +private: + + ComponentType m_Type; + + bool m_Initialized; + bool m_Available; + +protected: + + ComponentBase(ComponentType type); + +public: + + ~ComponentBase() override; + +protected: + + void SetInitialized(); + void SetAvailable(); + +public: + + ComponentType GetType() const override; + bool IsInitialized() const override; + bool IsAvailable() const override; + + mpt::ustring GetVersion() const override; + +public: + + void Initialize() override; + +protected: + + virtual bool DoInitialize() = 0; + +}; + + +class ComponentBuiltin : public ComponentBase +{ +public: + ComponentBuiltin() + : ComponentBase(ComponentTypeBuiltin) + { + return; + } + bool DoInitialize() override + { + return true; + } +}; + + +#define MPT_GLOBAL_BIND(lib, name) name = &::name; + + +#if defined(MODPLUG_TRACKER) + + +class ComponentLibrary + : public ComponentBase +{ + +private: + + typedef std::map<std::string, mpt::Library> TLibraryMap; + TLibraryMap m_Libraries; + + bool m_BindFailed; + +protected: + + ComponentLibrary(ComponentType type); + +public: + + virtual ~ComponentLibrary(); + +protected: + + bool AddLibrary(const std::string &libName, const mpt::LibraryPath &libPath); + void ClearLibraries(); + void SetBindFailed(); + void ClearBindFailed(); + bool HasBindFailed() const; + +public: + + virtual mpt::Library GetLibrary(const std::string &libName) const; + + template <typename Tfunc> + bool Bind(Tfunc * & f, const std::string &libName, const std::string &symbol) const + { + return GetLibrary(libName).Bind(f, symbol); + } + +protected: + + bool DoInitialize() override = 0; + +}; + + +#define MPT_COMPONENT_BIND(libName, func) do { if(!Bind( func , libName , #func )) { SetBindFailed(); } } while(0) +#define MPT_COMPONENT_BIND_OPTIONAL(libName, func) Bind( func , libName , #func ) +#define MPT_COMPONENT_BIND_SYMBOL(libName, symbol, func) do { if(!Bind( func , libName , symbol )) { SetBindFailed(); } } while(0) +#define MPT_COMPONENT_BIND_SYMBOL_OPTIONAL(libName, symbol, func) Bind( func , libName , symbol ) + +#if MPT_OS_WINDOWS +#ifdef UNICODE +#define MPT_COMPONENT_BINDWIN_SUFFIX "W" +#else +#define MPT_COMPONENT_BINDWIN_SUFFIX "A" +#endif +#define MPT_COMPONENT_BINDWIN(libName, func) do { if(!Bind( func , libName , #func MPT_COMPONENT_BINDWIN_SUFFIX )) { SetBindFailed(); } } while(0) +#define MPT_COMPONENT_BINDWIN_OPTIONAL(libName, func) Bind( func , libName , #func MPT_COMPONENT_BINDWIN_SUFFIX ) +#define MPT_COMPONENT_BINDWIN_SYMBOL(libName, symbol, func) do { if(!Bind( func , libName , symbol MPT_COMPONENT_BINDWIN_SUFFIX )) { SetBindFailed(); } } while(0) +#define MPT_COMPONENT_BINDWIN_SYMBOL_OPTIONAL(libName, symbol, func) Bind( func , libName , symbol MPT_COMPONENT_BINDWIN_SUFFIX ) +#endif + + +class ComponentSystemDLL : public ComponentLibrary +{ +private: + mpt::PathString m_BaseName; +public: + ComponentSystemDLL(const mpt::PathString &baseName) + : ComponentLibrary(ComponentTypeSystem) + , m_BaseName(baseName) + { + return; + } + bool DoInitialize() override + { + AddLibrary(m_BaseName.ToUTF8(), mpt::LibraryPath::System(m_BaseName)); + return GetLibrary(m_BaseName.ToUTF8()).IsValid(); + } +}; + + +class ComponentBundledDLL : public ComponentLibrary +{ +private: + mpt::PathString m_FullName; +public: + ComponentBundledDLL(const mpt::PathString &fullName) + : ComponentLibrary(ComponentTypeBundled) + , m_FullName(fullName) + { + return; + } + bool DoInitialize() override + { + AddLibrary(m_FullName.ToUTF8(), mpt::LibraryPath::AppFullName(m_FullName)); + return GetLibrary(m_FullName.ToUTF8()).IsValid(); + } +}; + + +#endif // MODPLUG_TRACKER + + +#if MPT_COMPONENT_MANAGER + + +class ComponentManager; + +typedef std::shared_ptr<IComponent> (*ComponentFactoryMethod)(ComponentManager &componentManager); + + +class IComponentFactory +{ +protected: + IComponentFactory() = default; +public: + virtual ~IComponentFactory() = default; +public: + virtual std::string GetID() const = 0; + virtual std::string GetSettingsKey() const = 0; + virtual std::shared_ptr<IComponent> Construct(ComponentManager &componentManager) const = 0; + virtual ComponentFactoryMethod GetStaticConstructor() const = 0; +}; + + +class ComponentFactoryBase + : public IComponentFactory +{ +private: + std::string m_ID; + std::string m_SettingsKey; +protected: + ComponentFactoryBase(const std::string &id, const std::string &settingsKey); + void PreConstruct() const; + void Initialize(ComponentManager &componentManager, std::shared_ptr<IComponent> component) const; +public: + virtual ~ComponentFactoryBase(); + std::string GetID() const override; + std::string GetSettingsKey() const override; + std::shared_ptr<IComponent> Construct(ComponentManager &componentManager) const override = 0; + ComponentFactoryMethod GetStaticConstructor() const override = 0; +}; + + +template <typename T> +class ComponentFactory + : public ComponentFactoryBase +{ +public: + ComponentFactory() + : ComponentFactoryBase(T::g_ID, T::g_SettingsKey) + { + return; + } +public: + std::shared_ptr<IComponent> Construct(ComponentManager &componentManager) const override + { + PreConstruct(); + std::shared_ptr<IComponent> component = std::make_shared<T>(); + Initialize(componentManager, component); + return component; + } + static std::shared_ptr<IComponent> StaticConstruct(ComponentManager &componentManager) + { + return ComponentFactory().Construct(componentManager); + } + virtual ComponentFactoryMethod GetStaticConstructor() const override + { + return &StaticConstruct; + } +}; + + +class IComponentManagerSettings +{ +public: + virtual bool LoadOnStartup() const = 0; + virtual bool KeepLoaded() const = 0; + virtual bool IsBlocked(const std::string &key) const = 0; + virtual mpt::PathString Path() const = 0; +protected: + virtual ~IComponentManagerSettings() = default; +}; + + +class ComponentManagerSettingsDefault + : public IComponentManagerSettings +{ +public: + bool LoadOnStartup() const override { return false; } + bool KeepLoaded() const override { return true; } + bool IsBlocked(const std::string & /*key*/ ) const override { return false; } + mpt::PathString Path() const override { return mpt::PathString(); } +}; + + +enum ComponentState +{ + ComponentStateUnregistered, + ComponentStateBlocked, + ComponentStateUnintialized, + ComponentStateUnavailable, + ComponentStateAvailable, +}; + + +struct ComponentInfo +{ + std::string name; + ComponentState state; + std::string settingsKey; + ComponentType type; +}; + + +class ComponentManager +{ + friend class ComponentFactoryBase; +public: + static void Init(const IComponentManagerSettings &settings); + static void Release(); + static std::shared_ptr<ComponentManager> Instance(); +private: + ComponentManager(const IComponentManagerSettings &settings); +private: + struct RegisteredComponent + { + std::string settingsKey; + ComponentFactoryMethod factoryMethod; + std::shared_ptr<IComponent> instance; + std::weak_ptr<IComponent> weakInstance; + }; + typedef std::map<std::string, RegisteredComponent> TComponentMap; + const IComponentManagerSettings &m_Settings; + TComponentMap m_Components; +private: + bool IsComponentBlocked(const std::string &settingsKey) const; + void InitializeComponent(std::shared_ptr<IComponent> component) const; +public: + void Register(const IComponentFactory &componentFactory); + void Startup(); + std::shared_ptr<const IComponent> GetComponent(const IComponentFactory &componentFactory); + std::shared_ptr<const IComponent> ReloadComponent(const IComponentFactory &componentFactory); + std::vector<std::string> GetRegisteredComponents() const; + ComponentInfo GetComponentInfo(std::string name) const; + mpt::PathString GetComponentPath() const; +}; + + +struct ComponentListEntry +{ + ComponentListEntry *next; + void (*reg)(ComponentManager &componentManager); +}; + +bool ComponentListPush(ComponentListEntry *entry); + +template <typename TComponent> +struct ComponentRegisterer +{ + static inline void RegisterComponent(ComponentManager &componentManager) + { + componentManager.Register(ComponentFactory<TComponent>()); + } + static inline ComponentListEntry &GetComponentListEntry() + { + static ComponentListEntry s_ComponentListEntry = {nullptr, &RegisterComponent}; + return s_ComponentListEntry; + } + static inline bool g_ComponentRegistered = ComponentListPush(&GetComponentListEntry()); +}; + +#define MPT_DECLARE_COMPONENT_MEMBERS(name, settingsKey) \ + public: \ + static constexpr const char *g_ID = #name ; \ + static constexpr const char *g_SettingsKey = settingsKey ; \ + static inline ComponentRegisterer< name > s_ComponentRegisterer; \ +/**/ + + +template <typename type> +std::shared_ptr<const type> GetComponent() +{ + return std::dynamic_pointer_cast<const type>(ComponentManager::Instance()->GetComponent(ComponentFactory<type>())); +} + + +template <typename type> +std::shared_ptr<const type> ReloadComponent() +{ + return std::dynamic_pointer_cast<const type>(ComponentManager::Instance()->ReloadComponent(ComponentFactory<type>())); +} + + +inline mpt::PathString GetComponentPath() +{ + return ComponentManager::Instance()->GetComponentPath(); +} + + +#else // !MPT_COMPONENT_MANAGER + + +#define MPT_DECLARE_COMPONENT_MEMBERS(name, settingsKey) + + +template <typename type> +std::shared_ptr<const type> GetComponent() +{ + static std::weak_ptr<type> cache; + static mpt::mutex m; + mpt::lock_guard<mpt::mutex> l(m); + std::shared_ptr<type> component = cache.lock(); + if(!component) + { + component = std::make_shared<type>(); + component->Initialize(); + cache = component; + } + return component; +} + + +#endif // MPT_COMPONENT_MANAGER + + +// Simple wrapper around std::shared_ptr<ComponentType> which automatically +// gets a reference to the component (or constructs it) on initialization. +template <typename T> +class ComponentHandle +{ +private: + std::shared_ptr<const T> component; +public: + ComponentHandle() + : component(GetComponent<T>()) + { + return; + } + ~ComponentHandle() + { + return; + } + bool IsAvailable() const + { + return component && component->IsAvailable(); + } + const T *get() const + { + return component.get(); + } + const T &operator*() const + { + return *component; + } + const T *operator->() const + { + return &*component; + } +#if MPT_COMPONENT_MANAGER + void Reload() + { + component = nullptr; + component = ReloadComponent<T>(); + } +#endif +}; + + +template <typename T> +bool IsComponentAvailable(const ComponentHandle<T> &handle) +{ + return handle.IsAvailable(); +} + + +OPENMPT_NAMESPACE_END |