/* * 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 #include #include #include #include #include #include //! \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 CComponentContainer { public: //! \brief Obtain a component. template std::shared_ptr GetComponent() { return std::const_pointer_cast(std::as_const(*this).template GetComponent()); } //! \brief Obtain a component. template std::shared_ptr GetComponent() const { std::unique_lock lock(m_critSection); const auto it = m_components.find(std::type_index(typeid(T))); if (it != m_components.end()) return std::static_pointer_cast((*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& 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 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 lock(m_critSection); m_components.erase(typeInfo); } private: mutable CCriticalSection m_critSection; //!< Critical section for map updates std::unordered_map> m_components; //!< Map of components };