LCOV - code coverage report
Current view: top level - include/base - TheWarehouse.h (source / functions) Hit Total Coverage
Test: idaholab/moose framework: fa5e60 Lines: 111 114 97.4 %
Date: 2026-06-24 08:03:36 Functions: 273 284 96.1 %
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             : #include <map>
      13             : #include <string>
      14             : #include <vector>
      15             : #include <unordered_map>
      16             : #include <iostream>
      17             : #include <mutex>
      18             : #include <type_traits>
      19             : 
      20             : #include "MooseObject.h"
      21             : #include "MooseHashing.h"
      22             : #include "MooseUtils.h"
      23             : 
      24             : class MooseObject;
      25             : class WarehouseStorage;
      26             : class TheWarehouse;
      27             : 
      28             : /// Attribute is an abstract class that can be implemented in order to track custom metadata about
      29             : /// MooseObject instances - enabling warehouse queries over the attribute.  Attribute subclasses
      30             : /// must be registered with the warehouse (i.e. via TheWarehouse::registerAttribute) where they will
      31             : /// be used *before* objects are added to that warehouse.  Specific Attribute instances cannot (and
      32             : /// should not) generally be created before the class is registered with a warehouse.
      33             : ///
      34             : /// In order to work with QueryCache objects, attribute classes should include
      35             : /// a public typedef for a Key type, as well as a setFromKey function that
      36             : /// takes this type as an argument:
      37             : ///
      38             : /// @begincode
      39             : /// class FooAttribute : public Attribute
      40             : /// {
      41             : /// public:
      42             : ///   typedef [type-for-foo] Key;
      43             : ///
      44             : ///   void
      45             : ///   setFrom(Key k)
      46             : ///   {
      47             : ///     // code to mutate/reinitialize FooAttribute using k
      48             : ///   }
      49             : /// }
      50             : /// @endcode
      51             : class Attribute
      52             : {
      53             : public:
      54             :   /// Constructs/initializes a new attribute with the specified name for use in warehouse w.  The
      55             :   /// attribute must have been previously registered with w prior to calling this constructor.
      56             :   Attribute(TheWarehouse & w, const std::string name);
      57   320317144 :   virtual ~Attribute() {}
      58             : 
      59   239239086 :   inline bool operator==(const Attribute & other) const
      60             :   {
      61   239239086 :     return _id == other._id && isEqual(other);
      62             :   }
      63             :   inline bool operator!=(const Attribute & other) const { return !(*this == other); }
      64             : 
      65             :   /// returns the unique attribute ID associated with all attributes that have the same (mose
      66             :   /// derived) class as this object. This ID is determined at construction time
      67             :   /// this
      68   317244369 :   inline unsigned int id() const { return _id; }
      69             : 
      70             :   /// This function must return a deterministic value that is uniquely determined by
      71             :   /// the data the attribute holds (i.e. is initialized with).  Ideally, the data should be
      72             :   /// uniformly and randomly distributed across the domain of size_t values - e.g. 1 and 2 should
      73             :   /// hash to completely unrelated values.  Use of std::hash for POD is encouraged.  A convenience
      74             :   /// hash_combine function is also provided to combine the results an existing hash with one or
      75             :   /// more other values.
      76             :   virtual std::size_t hash() const = 0;
      77             : 
      78             :   /// initFrom reads and stores the desired meta-data from obj for later matching comparisons.
      79             :   virtual void initFrom(const MooseObject * obj) = 0;
      80             :   /// isMatch returns true if the meta-data stored in this attribute is equivalent to that
      81             :   /// stored in other. This is is for query matching - not exact equivalence. isMatch does not need
      82             :   /// to check/compare the values from the instances' id() functions.
      83             :   virtual bool isMatch(const Attribute & other) const = 0;
      84             :   /// isEqual returns true if the meta-data stored in this attribute is identical to that
      85             :   /// stored in other. isEqual does not need to check/compare the values from the instances' id()
      86             :   /// functions.
      87             :   virtual bool isEqual(const Attribute & other) const = 0;
      88             :   /// clone creates and returns and identical (deep) copy of this attribute - i.e. the result of
      89             :   /// clone should return true if passed into isMatch.
      90             :   virtual std::unique_ptr<Attribute> clone() const = 0;
      91             : 
      92             : private:
      93             :   int _id = -1;
      94             : };
      95             : 
      96             : #define clonefunc(T)                                                                               \
      97             :   virtual std::unique_ptr<Attribute> clone() const override                                        \
      98             :   {                                                                                                \
      99             :     return std::unique_ptr<Attribute>(new T(*this));                                               \
     100             :   }
     101             : 
     102             : #define hashfunc(...)                                                                              \
     103             :   virtual std::size_t hash() const override                                                        \
     104             :   {                                                                                                \
     105             :     std::size_t h = 0;                                                                             \
     106             :     Moose::hash_combine(h, __VA_ARGS__);                                                           \
     107             :     return h;                                                                                      \
     108             :   }
     109             : 
     110             : /**
     111             :  * This attribute describes sorting state
     112             :  */
     113             : class AttribSorted : public Attribute
     114             : {
     115             : public:
     116             :   typedef bool Key;
     117             :   void setFrom(const Key & k) { _val = k; }
     118             : 
     119      201894 :   AttribSorted(TheWarehouse & w) : Attribute(w, "sorted"), _val(false), _initd(false) {}
     120    54326472 :   AttribSorted(TheWarehouse & w, bool is_sorted)
     121   105945936 :     : Attribute(w, "sorted"), _val(is_sorted), _initd(true)
     122             :   {
     123    53649720 :   }
     124     4783226 :   AttribSorted(const AttribSorted &) = default;
     125             :   AttribSorted(AttribSorted &&) = default;
     126             :   AttribSorted & operator=(const AttribSorted &) = default;
     127             :   AttribSorted & operator=(AttribSorted &&) = default;
     128             : 
     129             :   virtual void initFrom(const MooseObject * obj) override;
     130             :   virtual bool isMatch(const Attribute & other) const override;
     131             :   virtual bool isEqual(const Attribute & other) const override;
     132    57876544 :   hashfunc(_val);
     133     4783226 :   clonefunc(AttribSorted);
     134             : 
     135             : private:
     136             :   bool _val;
     137             :   bool _initd;
     138             : };
     139             : 
     140             : #undef clonefunc
     141             : #undef hashfunc
     142             : 
     143             : /// TheWarehouse uses this operator function for indexing and caching queries. So this is
     144             : /// important even though you don't see it being called (directly) anywhere - it *IS* being used.
     145             : bool operator==(const std::unique_ptr<Attribute> & lhs, const std::unique_ptr<Attribute> & rhs);
     146             : 
     147             : namespace std
     148             : {
     149             : /// This template specialization allows Attributes to be used as unordered map key.
     150             : template <>
     151             : struct hash<Attribute>
     152             : {
     153             : public:
     154   278379466 :   std::size_t operator()(const Attribute & attrib) const
     155             :   {
     156   278379466 :     std::size_t h = attrib.hash();
     157   278379466 :     Moose::hash_combine(h, attrib.id());
     158   278379466 :     return h;
     159             :   }
     160             : };
     161             : 
     162             : /// This template specialization allows vector<Attribute> to be used as unordered map key.
     163             : template <>
     164             : struct hash<std::vector<std::unique_ptr<Attribute>>>
     165             : {
     166             : public:
     167    58286851 :   std::size_t operator()(const std::vector<std::unique_ptr<Attribute>> & attribs) const
     168             :   {
     169    58286851 :     std::size_t h = 0;
     170   336666317 :     for (auto & attrib : attribs)
     171   278379466 :       Moose::hash_combine(h, *attrib);
     172    58286851 :     return h;
     173             :   }
     174             : };
     175             : }
     176             : 
     177             : /// TheWarehouse is a container for MooseObjects that allows querying/filtering over various
     178             : /// customizeable attributes.  The meta-data about the objects is read/stored when the objects are
     179             : /// added to the warehouse - updates to objects' state will not be reflected in query
     180             : /// results unless the object is explicitly updated through the warehouse interface.  The
     181             : /// warehouse object can safely be queried concurrently from multiple threads.
     182             : ///
     183             : /// Once Query and Attribute objects have been constructed, they are tied to the specific
     184             : /// warehouse they were created with.  They must not be used for different warehouses or the
     185             : /// attribute ID they store internally will be wrong and that is bad.
     186             : class TheWarehouse
     187             : {
     188             : public:
     189             :   template <typename T>
     190             :   using KeyType = typename T::Key;
     191             :   template <typename T>
     192             :   using AttribType = T *;
     193             : 
     194             :   /// QueryCache is a convenient way to construct and pass around (possible
     195             :   /// partially constructed) warehouse queries.  The warehouse's "query()" or
     196             :   /// "queryCache(...)" functions should generally be used to create new Query
     197             :   /// objects rather than constructing them directly.  A Query object holds a
     198             :   /// list of persistent conditions used to filter/select objects from the
     199             :   /// warehouse.  When the query is executed/run, results are filtered by
     200             :   /// "and"ing each condition together - i.e. only objects that match *all*
     201             :   /// conditions are returned.
     202             :   ///
     203             :   ///
     204             :   /// Template arguments (i.e. Attribs) are used to specify parametrized query
     205             :   /// conditions.  The passed template parameters should be the Attribute
     206             :   /// classes you want to use for parameterization (i.e. the values that will
     207             :   /// change from query to query).
     208             :   template <typename... Attribs>
     209             :   class QueryCache
     210             :   {
     211             :   public:
     212             :     typedef std::tuple<KeyType<Attribs>...> KeyTuple;
     213             :     typedef std::tuple<AttribType<Attribs>...> AttribTuple;
     214             : 
     215       21684 :     QueryCache() {}
     216             : 
     217             :     /// Creates a new query operating on the given warehouse w.  You should generally use
     218             :     /// TheWarehouse::query() instead.
     219    39212620 :     QueryCache(TheWarehouse & w) : _w(&w)
     220             :     {
     221    39212620 :       addAttribs<0, Attribs...>();
     222    39212620 :       _attribs.reserve(5);
     223    39212620 :     }
     224             : 
     225             :     template <typename T>
     226      413608 :     QueryCache(const T & q) : _w(&q.warehouse())
     227             :     {
     228      413608 :       addAttribs<0, Attribs...>();
     229      413608 :       _attribs.reserve(5);
     230             : 
     231     2119942 :       for (auto & attrib : q.attributes())
     232     1706334 :         _attribs.push_back(attrib->clone());
     233      413608 :     }
     234             : 
     235       21684 :     QueryCache & operator=(const QueryCache & other)
     236             :     {
     237       21684 :       if (this == &other)
     238           0 :         return *this;
     239             : 
     240       21684 :       _attribs.clear();
     241       21684 :       _w = other._w;
     242             :       // MUST have own pointers to attribs to avoid data races - don't copy _key_attribs.
     243             :       // initialize parametrized attributes and tuple:
     244       21684 :       addAttribs<0, Attribs...>();
     245             :       _key_tup = other._key_tup;
     246             :       // do NOT copy the cache.
     247             : 
     248             :       // only copy over non-parametrized attributes
     249       43368 :       for (std::size_t i = std::tuple_size<AttribTuple>::value; i < other._attribs.size(); i++)
     250       21684 :         _attribs.push_back(other._attribs[i]->clone());
     251       21684 :       return *this;
     252             :     }
     253             : 
     254             :     /// Copy constructor from another Query
     255             :     template <typename T>
     256             :     QueryCache & operator=(const T & q)
     257             :     {
     258             :       _attribs.clear();
     259             :       _w = &q.warehouse();
     260             : 
     261             :       addAttribs<0, Attribs...>();
     262             :       _attribs.reserve(5);
     263             : 
     264             :       for (auto & attrib : q.attributes())
     265             :         _attribs.push_back(attrib->clone());
     266             : 
     267             :       return *this;
     268             :     }
     269             : 
     270    34179560 :     QueryCache(const QueryCache & other) : _w(other._w), _key_tup(other._key_tup)
     271             :     {
     272             :       // do NOT copy the cache.
     273             : 
     274             :       // initialize parametrized attributes and tuple:
     275    34179560 :       addAttribs<0, Attribs...>(); // MUST have own pointers to attribs to avoid data races.
     276   117204573 :       for (std::size_t i = std::tuple_size<AttribTuple>::value; i < other._attribs.size(); i++)
     277    83025013 :         _attribs.push_back(other._attribs[i]->clone());
     278    34179560 :     }
     279             : 
     280             :     /// Adds a new condition to the query.  The template parameter T is the Attribute class of
     281             :     /// interest and args are forwarded to T's constructor to build+add the attribute in-situ.
     282             :     /// Conditions represent persistent query conditions that do not change
     283             :     /// from query to query for a particular QueryCache instance.
     284             :     template <typename T, typename... Args>
     285   154401803 :     QueryCache & condition(Args &&... args)
     286             :     {
     287   172473088 :       _attribs.emplace_back(new T(*_w, std::forward<Args>(args)...));
     288   154401803 :       _cache.clear(); // invalidate cache if base query changes.
     289   154401803 :       return *this;
     290             :     }
     291             : 
     292             :     /// clone creates and returns an independent copy of the query in its current state.
     293    12307946 :     QueryCache clone() const { return Query(*this); }
     294             :     /// count returns the number of results that match the query (this requires actually running
     295             :     /// the query).
     296      331115 :     std::size_t count() { return _w->count(_attribs); }
     297             : 
     298      413608 :     TheWarehouse & warehouse() const { return *_w; }
     299             : 
     300             :     /// attribs returns a copy of the constructed Attribute list for the query in its current state.
     301      415361 :     std::vector<std::unique_ptr<Attribute>> attributes() const { return clone()._attribs; }
     302             : 
     303             :     /// queryInto executes the query and stores the results in the given
     304             :     /// vector.  For parametrized queries (i.e. QueryCaches created with more
     305             :     /// than zero template arguments) args must contain one value for each
     306             :     /// parametrized query attribute - the types of args should be equal to the
     307             :     /// ::Key typedef specified for each corresponding parametrized attribute.
     308             :     /// All results must be castable to the templated type T. If the objects
     309             :     /// we are querying into inherit from the dependency resolver interface, then
     310             :     /// they will be sorted
     311             :     template <typename T, typename... Args>
     312    92216284 :     std::vector<T *> & queryInto(std::vector<T *> & results, Args &&... args)
     313             :     {
     314    92216284 :       return queryIntoHelper(results, true, args...);
     315             :     }
     316             : 
     317             :     /// queryInto executes the query and stores the results in the given
     318             :     /// vector.  For parametrized queries (i.e. QueryCaches created with more
     319             :     /// than zero template arguments) args must contain one value for each
     320             :     /// parametrized query attribute - the types of args should be equal to the
     321             :     /// ::Key typedef specified for each corresponding parametrized attribute.
     322             :     /// All results must be castable to the templated type T. These objects
     323             :     /// will not be sorted
     324             :     template <typename T, typename... Args>
     325    24339996 :     std::vector<T *> & queryIntoUnsorted(std::vector<T *> & results, Args &&... args)
     326             :     {
     327    24339996 :       return queryIntoHelper(results, false, args...);
     328             :     }
     329             : 
     330             :     /// Gets the number of attributes associated with the cached query
     331             :     std::size_t numAttribs() const { return _attribs.size(); }
     332             : 
     333             :   private:
     334             :     /// queryInto executes the query and stores the results in the given
     335             :     /// vector.  For parametrized queries (i.e. QueryCaches created with more
     336             :     /// than zero template arguments) args must contain one value for each
     337             :     /// parametrized query attribute - the types of args should be equal to the
     338             :     /// ::Key typedef specified for each corresponding parametrized attribute.
     339             :     /// All results must be castable to the templated type T. If the objects
     340             :     /// we are querying into inherit from the dependency resolver interface, then
     341             :     /// they will be sorted if \p sort is true
     342             :     template <typename T, typename... Args>
     343   116556280 :     std::vector<T *> & queryIntoHelper(std::vector<T *> & results, const bool sort, Args &&... args)
     344             :     {
     345   116556280 :       std::lock_guard<std::mutex> lock(_cache_mutex);
     346   116556280 :       setKeysInner<0, KeyType<Attribs>...>(args...);
     347             : 
     348             :       std::size_t query_id;
     349   116556280 :       const auto entry = _cache.find(std::make_pair(sort, _key_tup));
     350   116556280 :       if (entry == _cache.end())
     351             :       {
     352    53600834 :         setAttribsInner<0, KeyType<Attribs>...>(args...);
     353             :         // add the sort attribute. No need (I think) to clear the cache because the base query is
     354             :         // not changing
     355    53600834 :         _attribs.emplace_back(new AttribSorted(*_w, sort));
     356    53600834 :         query_id = _w->queryID(_attribs);
     357    53600834 :         _cache[std::make_pair(sort, _key_tup)] = query_id;
     358             :         // remove the sort attribute
     359    53600834 :         _attribs.pop_back();
     360             :       }
     361             :       else
     362    62955446 :         query_id = entry->second;
     363             : 
     364   233112560 :       return _w->queryInto(query_id, results);
     365   116556280 :     }
     366             : 
     367             :     template <int Index, typename A, typename... As>
     368     1241202 :     void addAttribs()
     369             :     {
     370     1241202 :       std::get<Index>(_attrib_tup) = new A(*_w);
     371     1241202 :       _attribs.emplace_back(std::get<Index>(_attrib_tup));
     372     1241202 :       addAttribs<Index + 1, As...>();
     373     1241202 :     }
     374             :     template <int Index>
     375    73827472 :     void addAttribs()
     376             :     {
     377    73827472 :     }
     378             : 
     379             :     template <int Index, typename K, typename... Args>
     380    26131971 :     void setKeysInner(K & k, Args &... args)
     381             :     {
     382    26131971 :       std::get<Index>(_key_tup) = k;
     383    26131971 :       setKeysInner<Index + 1, Args...>(args...);
     384    26131971 :     }
     385             :     template <int Index>
     386   116556280 :     void setKeysInner()
     387             :     {
     388   116556280 :     }
     389             : 
     390             :     template <int Index, typename K, typename... Args>
     391     5639652 :     void setAttribsInner(K k, Args &... args)
     392             :     {
     393     5639652 :       std::get<Index>(_attrib_tup)->setFrom(k);
     394     5639652 :       setAttribsInner<Index + 1, Args...>(args...);
     395     5639652 :     }
     396             :     template <int Index>
     397    53600834 :     void setAttribsInner()
     398             :     {
     399    53600834 :     }
     400             : 
     401             :     TheWarehouse * _w = nullptr;
     402             :     std::vector<std::unique_ptr<Attribute>> _attribs;
     403             : 
     404             :     KeyTuple _key_tup;
     405             :     AttribTuple _attrib_tup;
     406             :     std::map<std::pair<bool, KeyTuple>, std::size_t> _cache;
     407             :     std::mutex _cache_mutex;
     408             :   };
     409             : 
     410             :   using Query = QueryCache<>;
     411             : 
     412             :   TheWarehouse();
     413             :   ~TheWarehouse();
     414             : 
     415             :   /// registers a new "tracked" attribute of type T for the warehouse.  args are all arguments
     416             :   /// necessary to create an instance of the T class excluding the warehouse reference/pointer
     417             :   /// which is assumed to be first and automatically inserted.  An instance of every registered
     418             :   /// attribute will be created for and initialized to each object added to the warehouse allowing
     419             :   /// queries to be executed over specific values the attribute may take on. Attributes must be
     420             :   /// registered *before* objects are added to the warehouse.  A unique ID associated with the
     421             :   /// registered attribute is returned - which is generally not needed used by users.
     422             :   ///
     423             :   /// As an example, to register a class with the constructor "YourAttribute(TheWarehouse& w, int
     424             :   /// foo)", you would call "registerAttribute<YourAttribute>("your_attrib_name", constructor_arg1,
     425             :   /// ...)".  Custom attribute classes are required to pass an attribute name (i.e.
     426             :   /// "your_attrib_name") to the Attribute base class.  The dummy args are forwarded to the attrib
     427             :   /// class' constructor. The name passed here into registerAttribute
     428             :   /// must be the same string as the name passed to the Attribute base class's constructor.
     429             :   template <typename T, typename... Args>
     430     1211286 :   unsigned int registerAttribute(const std::string & name, Args... dummy_args)
     431             :   {
     432     1211286 :     auto it = _attrib_ids.find(name);
     433     1211286 :     if (it != _attrib_ids.end())
     434           0 :       return it->second;
     435             : 
     436     1211286 :     _attrib_ids[name] = _attrib_list.size();
     437     1345870 :     _attrib_list.push_back(std::unique_ptr<Attribute>(new T(*this, dummy_args...)));
     438     1211286 :     return _attrib_list.size() - 1;
     439             :   }
     440             : 
     441             :   /// Returns a unique ID associated with the given attribute name - i.e. an attribute and name
     442             :   /// that were previously registered via calls to registerAttribute.  Users should generally *not*
     443             :   /// need to use this function.
     444   210580297 :   inline unsigned int attribID(const std::string & name)
     445             :   {
     446   210580297 :     auto it = _attrib_ids.find(name);
     447   210580297 :     if (it != _attrib_ids.end())
     448   421160594 :       return it->second;
     449           0 :     mooseError("no ID exists for unregistered attribute '", name, "'");
     450             :   }
     451             : 
     452             :   /// add adds a new object to the warehouse and stores attributes/metadata about it for running
     453             :   /// queries/filtering.  The warehouse will maintain a pointer to the object indefinitely.
     454             :   void add(std::shared_ptr<MooseObject> obj);
     455             : 
     456             :   /// update updates the metadata/attribute-info stored for the given object obj that must already
     457             :   /// exists in the warehouse.  Call this if an object's state has changed in such a way that its
     458             :   /// warehouse attributes have become stale/incorrect.
     459             :   void update(MooseObject * obj);
     460             :   /// update updates the metadata/attribute-info stored for the given object obj that must already
     461             :   /// exists in the warehouse.  Call this if an object's state has changed in such a way that its
     462             :   /// warehouse attributes have become stale/incorrect.
     463             :   /// Any attribute specified in extra overwrites/trumps one read from the object's current state.
     464             :   void update(MooseObject * obj, const Attribute & extra);
     465             :   /// query creates and returns an initialized a query object for querying objects from the
     466             :   /// warehouse.
     467    39212620 :   Query query() { return Query(*this); }
     468             :   /// count returns the number of objects that match the provided query conditions. This requires
     469             :   /// executing a full query operation (i.e. as if calling queryInto). A Query object should
     470             :   /// generally be used via the query() member function instead.
     471             :   std::size_t count(const std::vector<std::unique_ptr<Attribute>> & conds);
     472             :   /// queryInto takes the given conditions (i.e. Attributes holding the values to filter/match
     473             :   /// over) and filters all objects in the warehouse that match all conditions (i.e. "and"ing the
     474             :   /// conditions together) and stores them in the results vector. All result objects must be
     475             :   /// castable to the templated type T. This function filters out disabled objects on the fly -
     476             :   /// only returning enabled ones.
     477             :   template <typename T>
     478             :   std::vector<T *> & queryInto(const std::vector<std::unique_ptr<Attribute>> & conds,
     479             :                                std::vector<T *> & results)
     480             :   {
     481             :     return queryInto(queryID(conds), results);
     482             :   }
     483             : 
     484             :   std::size_t queryID(const std::vector<std::unique_ptr<Attribute>> & conds);
     485             : 
     486             :   template <typename T>
     487   116558033 :   std::vector<T *> & queryInto(int query_id, std::vector<T *> & results, bool show_all = false)
     488             :   {
     489   116558033 :     std::lock_guard<std::mutex> lock(_obj_cache_mutex);
     490   116558033 :     auto & objs = query(query_id);
     491   116558033 :     results.clear();
     492   116558033 :     results.reserve(objs.size());
     493   186780927 :     for (auto & obj : objs)
     494             :     {
     495             :       mooseAssert(obj, "Null object");
     496             :       T * cast_obj;
     497             :       // We've been using dynamic_cast plus an assert that it
     498             :       // succeeds, but if we know the correct type T then often we can
     499             :       // use a much-cheaper static_cast.  libMesh::cast_ptr will still
     500             :       // use a dynamic_cast + assertion in devel/dbg modes.
     501             :       if constexpr (std::is_convertible_v<MooseObject *, std::remove_cv_t<T> *> ||
     502             :                     std::is_convertible_v<std::remove_cv_t<T> *, MooseObject *>)
     503             :       {
     504    69839851 :         cast_obj = cast_ptr<T *>(obj);
     505             :       }
     506             :       // Side-casts or virtual inheritence are always expensive.
     507             :       // Someone should figure out how to get rid of this code path.
     508             :       else
     509             :       {
     510      383043 :         cast_obj = dynamic_cast<T *>(obj);
     511             :         mooseAssert(cast_obj,
     512             :                     "Queried object " + obj->typeAndName() + " has incompatible c++ type with " +
     513             :                         MooseUtils::prettyCppType<T>());
     514             :       }
     515             : 
     516             :       mooseAssert(std::find(results.begin(), results.end(), cast_obj) == results.end(),
     517             :                   "Duplicate object");
     518    70222894 :       if (show_all || obj->enabled())
     519    70206131 :         results.push_back(cast_obj);
     520             :     }
     521   116558033 :     return results;
     522   116558033 :   }
     523             : 
     524             : private:
     525             :   /// prepares a query and returns an associated query_id (i.e. for use with the query function).
     526             :   int prepare(std::vector<std::unique_ptr<Attribute>> conds);
     527             : 
     528             :   /// callers of this function must lock _obj_cache_mutex as long as a reference to the returned
     529             :   /// vector is being used.
     530             :   const std::vector<MooseObject *> & query(int query_id);
     531             : 
     532             :   void readAttribs(const MooseObject * obj, std::vector<std::unique_ptr<Attribute>> & attribs);
     533             : 
     534             :   std::unique_ptr<WarehouseStorage> _store;
     535             :   std::vector<std::shared_ptr<MooseObject>> _objects;
     536             :   std::unordered_map<MooseObject *, std::size_t> _obj_ids;
     537             : 
     538             :   // Results from queries are cached here. The outer vector index is the query id as stored by the
     539             :   // _query_cache data structure.  A list objects that match each query id are stored.
     540             :   std::vector<std::vector<MooseObject *>> _obj_cache;
     541             :   // This stores a query id for every query keyed by the query conditions/attributes.
     542             :   // User-initiated queries check this map to see if a queries results have already been cached.
     543             :   // The query id is an index into the _obj_cache data structure.
     544             :   std::unordered_map<std::vector<std::unique_ptr<Attribute>>, int> _query_cache;
     545             : 
     546             :   std::unordered_map<std::string, unsigned int> _attrib_ids;
     547             :   std::vector<std::unique_ptr<Attribute>> _attrib_list;
     548             : 
     549             :   std::mutex _obj_mutex;
     550             :   std::mutex _query_cache_mutex;
     551             :   std::mutex _obj_cache_mutex;
     552             : };

Generated by: LCOV version 1.14