summaryrefslogtreecommitdiffstats
path: root/xbmc/utils/ComponentContainer.h
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/utils/ComponentContainer.h')
-rw-r--r--xbmc/utils/ComponentContainer.h78
1 files changed, 78 insertions, 0 deletions
diff --git a/xbmc/utils/ComponentContainer.h b/xbmc/utils/ComponentContainer.h
new file mode 100644
index 0000000..3aa826a
--- /dev/null
+++ b/xbmc/utils/ComponentContainer.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2022 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include "threads/CriticalSection.h"
+
+#include <cstddef>
+#include <memory>
+#include <mutex>
+#include <stdexcept>
+#include <typeindex>
+#include <unordered_map>
+#include <utility>
+
+//! \brief A generic container for components.
+//! \details A component has to be derived from the BaseType.
+//! Only a single instance of each derived type can be registered.
+//! Intended use is through inheritance.
+template<class BaseType>
+class CComponentContainer
+{
+public:
+ //! \brief Obtain a component.
+ template<class T>
+ std::shared_ptr<T> GetComponent()
+ {
+ return std::const_pointer_cast<T>(std::as_const(*this).template GetComponent<T>());
+ }
+
+ //! \brief Obtain a component.
+ template<class T>
+ std::shared_ptr<const T> GetComponent() const
+ {
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ const auto it = m_components.find(std::type_index(typeid(T)));
+ if (it != m_components.end())
+ return std::static_pointer_cast<const T>((*it).second);
+
+ throw std::logic_error("ComponentContainer: Attempt to obtain non-existent component");
+ }
+
+ //! \brief Returns number of registered components.
+ std::size_t size() const { return m_components.size(); }
+
+protected:
+ //! \brief Register a new component instance.
+ void RegisterComponent(const std::shared_ptr<BaseType>& component)
+ {
+ if (!component)
+ return;
+
+ // Note: Extra var needed to avoid clang warning
+ // "Expression with side effects will be evaluated despite being used as an operand to 'typeid'"
+ // https://stackoverflow.com/questions/46494928/clang-warning-on-expression-side-effects
+ const auto& componentRef = *component;
+
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ m_components.insert({std::type_index(typeid(componentRef)), component});
+ }
+
+ //! \brief Deregister a component.
+ void DeregisterComponent(const std::type_info& typeInfo)
+ {
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ m_components.erase(typeInfo);
+ }
+
+private:
+ mutable CCriticalSection m_critSection; //!< Critical section for map updates
+ std::unordered_map<std::type_index, std::shared_ptr<BaseType>>
+ m_components; //!< Map of components
+};