LCOV - code coverage report
Current view: top level - include/interfaces - DependencyResolverInterface.h (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 99787a Lines: 35 36 97.2 %
Date: 2025-10-14 20:01:24 Functions: 21 32 65.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* This file is part of the MOOSE framework
       2             : //* https://mooseframework.inl.gov
       3             : //*
       4             : //* All rights reserved, see COPYRIGHT for full restrictions
       5             : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
       6             : //*
       7             : //* Licensed under LGPL 2.1, please see LICENSE for details
       8             : //* https://www.gnu.org/licenses/lgpl-2.1.html
       9             : 
      10             : #pragma once
      11             : 
      12             : // STL includes
      13             : #include <string>
      14             : #include <set>
      15             : #include <iostream>
      16             : #include <algorithm>
      17             : 
      18             : // MOOSE includes
      19             : #include "DependencyResolver.h"
      20             : #include "MooseUtils.h"
      21             : 
      22             : /**
      23             :  * Interface for sorting dependent vectors of objects.
      24             :  */
      25             : class DependencyResolverInterface
      26             : {
      27             : public:
      28             :   /**
      29             :    * Constructor.
      30             :    */
      31      239132 :   DependencyResolverInterface() {}
      32             : 
      33             : #ifdef MOOSE_KOKKOS_ENABLED
      34             :   /**
      35             :    * Special constructor used for Kokkos functor copy during parallel dispatch
      36             :    */
      37       37959 :   DependencyResolverInterface(const DependencyResolverInterface &,
      38             :                               const Moose::Kokkos::FunctorCopy &)
      39       37959 :   {
      40       37959 :   }
      41             : #endif
      42             : 
      43             :   /**
      44             :    * Return a set containing the names of items requested by the object.
      45             :    */
      46             :   virtual const std::set<std::string> & getRequestedItems() = 0;
      47             : 
      48             :   /**
      49             :    * Return a set containing the names of items owned by the object.
      50             :    */
      51             :   virtual const std::set<std::string> & getSuppliedItems() = 0;
      52             : 
      53             :   /**
      54             :    * Given a vector, sort using the getRequested/SuppliedItems sets.
      55             :    */
      56             :   template <typename T>
      57             :   static void sort(typename std::vector<T> & vector);
      58             : 
      59             :   /**
      60             :    * Given a vector, sort using the depth-first search
      61             :    */
      62             :   template <typename T>
      63             :   static void sortDFS(typename std::vector<T> & vector);
      64             : 
      65             :   /**
      66             :    * A helper method for cyclic errors.
      67             :    */
      68             :   template <typename T, typename T2>
      69             :   static void cyclicDependencyError(CyclicDependencyException<T2> & e, const std::string & header);
      70             : };
      71             : 
      72             : template <typename T>
      73             : void
      74     2986425 : DependencyResolverInterface::sort(typename std::vector<T> & vector)
      75             : {
      76     2986425 :   sortDFS(vector);
      77     2986419 : }
      78             : 
      79             : template <typename T>
      80             : void
      81     2986425 : DependencyResolverInterface::sortDFS(typename std::vector<T> & vector)
      82             : {
      83     2986425 :   if (vector.size() <= 1)
      84     2724233 :     return;
      85             : 
      86             :   /**
      87             :    * Class that represents the dependency as a graph
      88             :    */
      89      262192 :   DependencyResolver<T> graph;
      90             : 
      91             :   // Map of suppliers: what is supplied -> by what object
      92      262192 :   std::multimap<std::string, T> suppliers_map;
      93     1150204 :   for (auto & v : vector)
      94             :   {
      95             :     // Whether or not this object supplies something, we will always
      96             :     // add it as a node because we want to make sure that it gets returned
      97      888012 :     graph.addNode(v);
      98             : 
      99     1785972 :     for (const auto & supplied_item : v->getSuppliedItems())
     100      897960 :       suppliers_map.emplace(supplied_item, v);
     101             :   }
     102             : 
     103             :   // build the dependency graph
     104     1150204 :   for (auto & v : vector)
     105      973592 :     for (const auto & requested_item : v->getRequestedItems())
     106             :     {
     107       85580 :       const auto & [begin_it, end_it] = suppliers_map.equal_range(requested_item);
     108      142148 :       for (const auto & [supplier_name, supplier_object] : as_range(begin_it, end_it))
     109             :       {
     110       56568 :         libmesh_ignore(supplier_name);
     111             : 
     112             :         // We allow an object to have a circular dependency within itself; e.g. we choose to
     113             :         // trust a developer knows what they are doing within a single object
     114       56568 :         if (supplier_object != v)
     115       40020 :           graph.addEdge(supplier_object, v);
     116             :       }
     117             :     }
     118             : 
     119      262192 :   const auto & sorted = graph.dfs();
     120             : 
     121             :   // The set here gets unique objects, as it's valid to pass in duplicates
     122             :   mooseAssert(sorted.size() == std::set<T>(vector.begin(), vector.end()).size(), "Size mismatch");
     123             : 
     124      262186 :   vector = sorted;
     125      262198 : }
     126             : 
     127             : template <typename T, typename T2>
     128             : void
     129           6 : DependencyResolverInterface::cyclicDependencyError(CyclicDependencyException<T2> & e,
     130             :                                                    const std::string & header)
     131             : {
     132           6 :   std::ostringstream oss;
     133             : 
     134           6 :   oss << header << ":\n";
     135           6 :   const auto cycle = e.getCyclicDependencies();
     136           6 :   std::vector<std::string> names(cycle.size());
     137          24 :   for (const auto i : index_range(cycle))
     138          18 :     names[i] = static_cast<T>(cycle[i])->name();
     139           6 :   oss << MooseUtils::join(names, " <- ");
     140           6 :   mooseError(oss.str());
     141           0 : }

Generated by: LCOV version 1.14