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

Generated by: LCOV version 1.14