// Copyright Advanced Micro Devices, Inc., or its affiliates. // SPDX-License-Identifier: MIT #pragma once #include #include #include #include #include namespace rocRoller { namespace Component { template requires(!CSingleUse) std::shared_ptr Get(typename Base::Argument const& arg) { using Factory = ComponentFactory; auto& factory = Factory::Instance(); return factory.get(arg); } template requires(!CSingleUse) std::shared_ptr Get(typename Base::Argument&& arg) { using Factory = ComponentFactory; auto const& factory = Factory::Instance(); return factory.get(arg); } // clang-format off template requires(!CSingleUse && !std::same_as && std::constructible_from) std::shared_ptr Get(Arg0 const& arg0, Args const&... args) { return Get(typename Base::Argument(arg0, args...)); } // clang-format on template std::shared_ptr GetNew(typename Base::Argument const& arg) { using Factory = ComponentFactory; auto& factory = Factory::Instance(); return factory.getNew(arg); } template std::shared_ptr GetNew(typename Base::Argument&& arg) { using Factory = ComponentFactory; auto& factory = Factory::Instance(); return factory.getNew(arg); } // clang-format off template requires(!std::same_as && std::constructible_from) std::shared_ptr GetNew(Arg0 const& arg0, Args const&... args) { return GetNew(typename Base::Argument(arg0, args...)); } // clang-format on template bool RegisterComponentImpl() { using Factory = ComponentFactory; auto& factory = Factory::Instance(); return factory.template registerComponent(); } template ComponentFactory::ComponentFactory() { ComponentFactory::registerImplementations(); } template ComponentFactory& ComponentFactory::Instance() { static ComponentFactory instance; return instance; } template template std::shared_ptr ComponentFactory::get(T&& arg) const { WriterLock lock{m_instanceCacheLock}; auto iter = m_instanceCache.find(arg); if(iter != m_instanceCache.end()) { return iter->second; } auto newInstance = getNew(arg); m_instanceCache[std::forward(arg)] = newInstance; return newInstance; } template template std::shared_ptr ComponentFactory::getNew(T&& arg) const { auto const& entry = getEntry(arg); return entry.builder(std::forward(arg)); } template template typename ComponentFactory::Entry const& ComponentFactory::getEntry(T&& arg) const { WriterLock lock{m_entryCacheLock}; auto iter = m_entryCache.find(arg); if(iter != m_entryCache.end()) { return iter->second; } Entry const& e = findEntry(arg); return m_entryCache[std::forward(arg)] = e; } template template typename ComponentFactory::Entry const& ComponentFactory::findEntry(T&& arg) const { ReaderLock lock{m_entriesLock}; auto foundIter = m_entries.end(); for(auto iter = m_entries.begin(); iter != m_entries.end(); iter++) { if(iter->matcher(std::forward(arg))) { if(!Debug) return *iter; if(foundIter == m_entries.end()) { foundIter = iter; } else { rocRoller::Log::warn("Multiple suitable components found for {}: {}, {}", Base::Basename, foundIter->name, iter->name); } } } // TODO Investigate why cppcheck isn't ensuring that this macro // is expanded correctly, requiring the derefInvalidIterator // suppression. AssertFatal(foundIter != m_entries.end(), Base::Basename, ": No valid component found: ", ShowValue(arg)); // cppcheck-suppress derefInvalidIterator return *foundIter; } template template bool ComponentFactory::registerComponent() { return registerComponent(Comp::Name, Comp::Match, Comp::Build); } template bool ComponentFactory::registerComponent(std::string const& name, Matcher matcher, Builder builder) { if(name == "") throw std::runtime_error(concatenate("Empty ", Base::Basename, " component name")); auto sameName = [&name](auto const& entry) { return entry.name == name; }; WriterLock lock{m_entriesLock}; if(std::any_of(m_entries.begin(), m_entries.end(), sameName)) throw std::runtime_error( concatenate("Duplicate ", Base::Basename, " component names: '", name, "'")); RegisterBase(this); m_entries.push_back({name, matcher, builder}); return true; } template template void ComponentFactory::emptyCache(T&& arg) { { WriterLock lock{m_entryCacheLock}; m_entryCache.erase(arg); } { WriterLock lock{m_instanceCacheLock}; m_instanceCache.erase(arg); } } template void ComponentFactory::emptyCache() { { WriterLock lock{m_entryCacheLock}; m_entryCache.clear(); } { WriterLock lock{m_instanceCacheLock}; m_instanceCache.clear(); } } inline void ComponentFactoryBase::ClearAllCaches() { for(auto ins : m_instances) ins->emptyCache(); } inline void ComponentFactoryBase::RegisterBase(ComponentFactoryBase* base) { m_instances.insert(base); } // std::unordered_set ComponentFactoryBase::m_instances; } }