#include "MetaCoreFoundation/MetaCoreAssetDependencyGraph.h" namespace MetaCore { MetaCoreAssetDependencyGraph& MetaCoreAssetDependencyGraph::Get() { static MetaCoreAssetDependencyGraph graph; return graph; } void MetaCoreAssetDependencyGraph::SetDependencies( const MetaCoreAssetGuid& assetGuid, const AssetGuidSet& dependencies ) { if (!assetGuid.IsValid()) { return; } std::scoped_lock lock(Mutex_); if (const auto previous = Dependencies_.find(assetGuid); previous != Dependencies_.end()) { for (const MetaCoreAssetGuid& dependency : previous->second) { if (auto dependents = Dependents_.find(dependency); dependents != Dependents_.end()) { dependents->second.erase(assetGuid); if (dependents->second.empty()) { Dependents_.erase(dependents); } } } } AssetGuidSet validDependencies; for (const MetaCoreAssetGuid& dependency : dependencies) { if (!dependency.IsValid() || dependency == assetGuid) { continue; } validDependencies.insert(dependency); Dependents_[dependency].insert(assetGuid); } if (validDependencies.empty()) { Dependencies_.erase(assetGuid); } else { Dependencies_[assetGuid] = std::move(validDependencies); } } MetaCoreAssetDependencyGraph::AssetGuidSet MetaCoreAssetDependencyGraph::GetDependencies( const MetaCoreAssetGuid& assetGuid ) const { std::scoped_lock lock(Mutex_); const auto iterator = Dependencies_.find(assetGuid); return iterator == Dependencies_.end() ? AssetGuidSet{} : iterator->second; } MetaCoreAssetDependencyGraph::AssetGuidSet MetaCoreAssetDependencyGraph::GetDependents( const MetaCoreAssetGuid& assetGuid ) const { std::scoped_lock lock(Mutex_); const auto iterator = Dependents_.find(assetGuid); return iterator == Dependents_.end() ? AssetGuidSet{} : iterator->second; } MetaCoreAssetDependencyGraph::AssetGuidSet MetaCoreAssetDependencyGraph::GetDependencyClosure( const std::vector& roots ) const { std::scoped_lock lock(Mutex_); AssetGuidSet closure; std::vector pending; for (const auto& root : roots) { if (root.IsValid() && closure.insert(root).second) pending.push_back(root); } while (!pending.empty()) { const MetaCoreAssetGuid current = pending.back(); pending.pop_back(); const auto dependencies = Dependencies_.find(current); if (dependencies == Dependencies_.end()) continue; for (const auto& dependency : dependencies->second) { if (closure.insert(dependency).second) pending.push_back(dependency); } } return closure; } void MetaCoreAssetDependencyGraph::RemoveAsset(const MetaCoreAssetGuid& assetGuid) { if (!assetGuid.IsValid()) { return; } std::scoped_lock lock(Mutex_); if (const auto dependencies = Dependencies_.find(assetGuid); dependencies != Dependencies_.end()) { for (const MetaCoreAssetGuid& dependency : dependencies->second) { if (auto dependents = Dependents_.find(dependency); dependents != Dependents_.end()) { dependents->second.erase(assetGuid); if (dependents->second.empty()) { Dependents_.erase(dependents); } } } Dependencies_.erase(dependencies); } if (const auto dependents = Dependents_.find(assetGuid); dependents != Dependents_.end()) { for (const MetaCoreAssetGuid& dependent : dependents->second) { if (auto dependencies = Dependencies_.find(dependent); dependencies != Dependencies_.end()) { dependencies->second.erase(assetGuid); if (dependencies->second.empty()) { Dependencies_.erase(dependencies); } } } Dependents_.erase(dependents); } } void MetaCoreAssetDependencyGraph::Clear() { std::scoped_lock lock(Mutex_); Dependencies_.clear(); Dependents_.clear(); } } // namespace MetaCore