aboutsummaryrefslogtreecommitdiff
path: root/Src/external_dependencies/openmpt-trunk/common/ComponentManager.h
diff options
context:
space:
mode:
Diffstat (limited to 'Src/external_dependencies/openmpt-trunk/common/ComponentManager.h')
-rw-r--r--Src/external_dependencies/openmpt-trunk/common/ComponentManager.h508
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