LCOV - code coverage report
Current view: top level - include/interfaces - DependencyResolverInterface.h (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 32 33 97.0 %
Date: 2025-07-17 01:28:37 Functions: 20 31 64.5 %
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      213198 :   DependencyResolverInterface() {}
      32             : 
      33             :   /**
      34             :    * Return a set containing the names of items requested by the object.
      35             :    */
      36             :   virtual const std::set<std::string> & getRequestedItems() = 0;
      37             : 
      38             :   /**
      39             :    * Return a set containing the names of items owned by the object.
      40             :    */
      41             :   virtual const std::set<std::string> & getSuppliedItems() = 0;
      42             : 
      43             :   /**
      44             :    * Given a vector, sort using the getRequested/SuppliedItems sets.
      45             :    */
      46             :   template <typename T>
      47             :   static void sort(typename std::vector<T> & vector);
      48             : 
      49             :   /**
      50             :    * Given a vector, sort using the depth-first search
      51             :    */
      52             :   template <typename T>
      53             :   static void sortDFS(typename std::vector<T> & vector);
      54             : 
      55             :   /**
      56             :    * A helper method for cyclic errors.
      57             :    */
      58             :   template <typename T, typename T2>
      59             :   static void cyclicDependencyError(CyclicDependencyException<T2> & e, const std::string & header);
      60             : };
      61             : 
      62             : template <typename T>
      63             : void
      64     2646978 : DependencyResolverInterface::sort(typename std::vector<T> & vector)
      65             : {
      66     2646978 :   sortDFS(vector);
      67     2646974 : }
      68             : 
      69             : template <typename T>
      70             : void
      71     2646978 : DependencyResolverInterface::sortDFS(typename std::vector<T> & vector)
      72             : {
      73     2646978 :   if (vector.size() <= 1)
      74     2412738 :     return;
      75             : 
      76             :   /**
      77             :    * Class that represents the dependency as a graph
      78             :    */
      79      234240 :   DependencyResolver<T> graph;
      80             : 
      81             :   // Map of suppliers: what is supplied -> by what object
      82      234240 :   std::multimap<std::string, T> suppliers_map;
      83     1028736 :   for (auto & v : vector)
      84             :   {
      85             :     // Whether or not this object supplies something, we will always
      86             :     // add it as a node because we want to make sure that it gets returned
      87      794496 :     graph.addNode(v);
      88             : 
      89     1598325 :     for (const auto & supplied_item : v->getSuppliedItems())
      90      803829 :       suppliers_map.emplace(supplied_item, v);
      91             :   }
      92             : 
      93             :   // build the dependency graph
      94     1028736 :   for (auto & v : vector)
      95      866137 :     for (const auto & requested_item : v->getRequestedItems())
      96             :     {
      97       71641 :       const auto & [begin_it, end_it] = suppliers_map.equal_range(requested_item);
      98      116352 :       for (const auto & [supplier_name, supplier_object] : as_range(begin_it, end_it))
      99             :       {
     100       44711 :         libmesh_ignore(supplier_name);
     101             : 
     102             :         // We allow an object to have a circular dependency within itself; e.g. we choose to
     103             :         // trust a developer knows what they are doing within a single object
     104       44711 :         if (supplier_object != v)
     105       29493 :           graph.addEdge(supplier_object, v);
     106             :       }
     107             :     }
     108             : 
     109      234240 :   const auto & sorted = graph.dfs();
     110             : 
     111             :   // The set here gets unique objects, as it's valid to pass in duplicates
     112             :   mooseAssert(sorted.size() == std::set<T>(vector.begin(), vector.end()).size(), "Size mismatch");
     113             : 
     114      234236 :   vector = sorted;
     115      234244 : }
     116             : 
     117             : template <typename T, typename T2>
     118             : void
     119           4 : DependencyResolverInterface::cyclicDependencyError(CyclicDependencyException<T2> & e,
     120             :                                                    const std::string & header)
     121             : {
     122           4 :   std::ostringstream oss;
     123             : 
     124           4 :   oss << header << ":\n";
     125           4 :   const auto cycle = e.getCyclicDependencies();
     126           4 :   std::vector<std::string> names(cycle.size());
     127          16 :   for (const auto i : index_range(cycle))
     128          12 :     names[i] = static_cast<T>(cycle[i])->name();
     129           4 :   oss << MooseUtils::join(names, " <- ");
     130           4 :   mooseError(oss.str());
     131           0 : }

Generated by: LCOV version 1.14