https://mooseframework.inl.gov
TheWarehouse.h
Go to the documentation of this file.
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 
50 class Attribute
51 {
52 public:
55  Attribute(TheWarehouse & w, const std::string name);
56  virtual ~Attribute() {}
57 
58  inline bool operator==(const Attribute & other) const
59  {
60  return _id == other._id && isEqual(other);
61  }
62  inline bool operator!=(const Attribute & other) const { return !(*this == other); }
63 
67  inline unsigned int id() const { return _id; }
68 
75  virtual std::size_t hash() const = 0;
76 
78  virtual void initFrom(const MooseObject * obj) = 0;
82  virtual bool isMatch(const Attribute & other) const = 0;
86  virtual bool isEqual(const Attribute & other) const = 0;
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 
112 class AttribSorted : public Attribute
113 {
114 public:
115  typedef bool Key;
116  void setFrom(const Key & k) { _val = k; }
117 
118  AttribSorted(TheWarehouse & w) : Attribute(w, "sorted"), _val(false), _initd(false) {}
120  : Attribute(w, "sorted"), _val(is_sorted), _initd(true)
121  {
122  }
123  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  hashfunc(_val);
133 
134 private:
135  bool _val;
136  bool _initd;
137 };
138 
139 #undef clonefunc
140 #undef hashfunc
141 
144 bool operator==(const std::unique_ptr<Attribute> & lhs, const std::unique_ptr<Attribute> & rhs);
145 
146 namespace std
147 {
149 template <>
150 struct hash<Attribute>
151 {
152 public:
153  std::size_t operator()(const Attribute & attrib) const
154  {
155  std::size_t h = attrib.hash();
156  Moose::hash_combine(h, attrib.id());
157  return h;
158  }
159 };
160 
162 template <>
163 struct hash<std::vector<std::unique_ptr<Attribute>>>
164 {
165 public:
166  std::size_t operator()(const std::vector<std::unique_ptr<Attribute>> & attribs) const
167  {
168  std::size_t h = 0;
169  for (auto & attrib : attribs)
170  Moose::hash_combine(h, *attrib);
171  return h;
172  }
173 };
174 }
175 
186 {
187 public:
188  template <typename T>
189  using KeyType = typename T::Key;
190  template <typename T>
191  using AttribType = T *;
192 
207  template <typename... Attribs>
209  {
210  public:
211  typedef std::tuple<KeyType<Attribs>...> KeyTuple;
212  typedef std::tuple<AttribType<Attribs>...> AttribTuple;
213 
215 
219  {
220  addAttribs<0, Attribs...>();
221  _attribs.reserve(5);
222  }
223 
224  template <typename T>
225  QueryCache(const T & q) : _w(&q.warehouse())
226  {
227  addAttribs<0, Attribs...>();
228  _attribs.reserve(5);
229 
230  for (auto & attrib : q.attributes())
231  _attribs.push_back(attrib->clone());
232  }
233 
234  QueryCache & operator=(const QueryCache & other)
235  {
236  if (this == &other)
237  return *this;
238 
239  _attribs.clear();
240  _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  addAttribs<0, Attribs...>();
244  _key_tup = other._key_tup;
245  // do NOT copy the cache.
246 
247  // only copy over non-parametrized attributes
248  for (std::size_t i = std::tuple_size<AttribTuple>::value; i < other._attribs.size(); i++)
249  _attribs.push_back(other._attribs[i]->clone());
250  return *this;
251  }
252 
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  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  addAttribs<0, Attribs...>(); // MUST have own pointers to attribs to avoid data races.
275  for (std::size_t i = std::tuple_size<AttribTuple>::value; i < other._attribs.size(); i++)
276  _attribs.push_back(other._attribs[i]->clone());
277  }
278 
283  template <typename T, typename... Args>
284  QueryCache & condition(Args &&... args)
285  {
286  _attribs.emplace_back(new T(*_w, std::forward<Args>(args)...));
287  _cache.clear(); // invalidate cache if base query changes.
288  return *this;
289  }
290 
292  QueryCache clone() const { return Query(*this); }
295  std::size_t count() { return _w->count(_attribs); }
296 
297  TheWarehouse & warehouse() const { return *_w; }
298 
300  std::vector<std::unique_ptr<Attribute>> attributes() const { return clone()._attribs; }
301 
310  template <typename T, typename... Args>
311  std::vector<T *> & queryInto(std::vector<T *> & results, Args &&... args)
312  {
313  return queryIntoHelper(results, true, args...);
314  }
315 
323  template <typename T, typename... Args>
324  std::vector<T *> & queryIntoUnsorted(std::vector<T *> & results, Args &&... args)
325  {
326  return queryIntoHelper(results, false, args...);
327  }
328 
330  std::size_t numAttribs() const { return _attribs.size(); }
331 
332  private:
341  template <typename T, typename... Args>
342  std::vector<T *> & queryIntoHelper(std::vector<T *> & results, const bool sort, Args &&... args)
343  {
344  std::lock_guard<std::mutex> lock(_cache_mutex);
345  setKeysInner<0, KeyType<Attribs>...>(args...);
346 
347  std::size_t query_id;
348  const auto entry = _cache.find(std::make_pair(sort, _key_tup));
349  if (entry == _cache.end())
350  {
351  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  _attribs.emplace_back(new AttribSorted(*_w, sort));
355  query_id = _w->queryID(_attribs);
356  _cache[std::make_pair(sort, _key_tup)] = query_id;
357  // remove the sort attribute
358  _attribs.pop_back();
359  }
360  else
361  query_id = entry->second;
362 
363  return _w->queryInto(query_id, results);
364  }
365 
366  template <int Index, typename A, typename... As>
367  void addAttribs()
368  {
369  std::get<Index>(_attrib_tup) = new A(*_w);
370  _attribs.emplace_back(std::get<Index>(_attrib_tup));
371  addAttribs<Index + 1, As...>();
372  }
373  template <int Index>
374  void addAttribs()
375  {
376  }
377 
378  template <int Index, typename K, typename... Args>
379  void setKeysInner(K & k, Args &... args)
380  {
381  std::get<Index>(_key_tup) = k;
382  setKeysInner<Index + 1, Args...>(args...);
383  }
384  template <int Index>
386  {
387  }
388 
389  template <int Index, typename K, typename... Args>
390  void setAttribsInner(K k, Args &... args)
391  {
392  std::get<Index>(_attrib_tup)->setFrom(k);
393  setAttribsInner<Index + 1, Args...>(args...);
394  }
395  template <int Index>
397  {
398  }
399 
400  TheWarehouse * _w = nullptr;
401  std::vector<std::unique_ptr<Attribute>> _attribs;
402 
405  std::map<std::pair<bool, KeyTuple>, std::size_t> _cache;
406  std::mutex _cache_mutex;
407  };
408 
410 
411  TheWarehouse();
412  ~TheWarehouse();
413 
428  template <typename T, typename... Args>
429  unsigned int registerAttribute(const std::string & name, Args... dummy_args)
430  {
431  auto it = _attrib_ids.find(name);
432  if (it != _attrib_ids.end())
433  return it->second;
434 
435  _attrib_ids[name] = _attrib_list.size();
436  _attrib_list.push_back(std::unique_ptr<Attribute>(new T(*this, dummy_args...)));
437  return _attrib_list.size() - 1;
438  }
439 
443  inline unsigned int attribID(const std::string & name)
444  {
445  auto it = _attrib_ids.find(name);
446  if (it != _attrib_ids.end())
447  return it->second;
448  mooseError("no ID exists for unregistered attribute '", name, "'");
449  }
450 
453  void add(std::shared_ptr<MooseObject> obj);
454 
458  void update(MooseObject * obj);
463  void update(MooseObject * obj, const Attribute & extra);
466  Query query() { return Query(*this); }
470  std::size_t count(const std::vector<std::unique_ptr<Attribute>> & conds);
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  std::vector<T *> & queryInto(int query_id, std::vector<T *> & results, bool show_all = false)
487  {
488  std::lock_guard<std::mutex> lock(_obj_cache_mutex);
489  auto & objs = query(query_id);
490  results.clear();
491  results.reserve(objs.size());
492  for (auto & obj : objs)
493  {
494  mooseAssert(obj, "Null object");
495  auto cast_obj = dynamic_cast<T *>(obj);
496  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  if (show_all || obj->enabled())
503  results.push_back(cast_obj);
504  }
505  return results;
506  }
507 
508 private:
510  int prepare(std::vector<std::unique_ptr<Attribute>> conds);
511 
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 };
std::string name(const ElemQuality q)
unsigned int id() const
returns the unique attribute ID associated with all attributes that have the same (mose derived) clas...
Definition: TheWarehouse.h:67
std::mutex _obj_cache_mutex
Definition: TheWarehouse.h:535
std::size_t count(const std::vector< std::unique_ptr< Attribute >> &conds)
count returns the number of objects that match the provided query conditions.
Definition: TheWarehouse.C:263
std::vector< T * > & queryIntoHelper(std::vector< T *> &results, const bool sort, Args &&... args)
queryInto executes the query and stores the results in the given vector.
Definition: TheWarehouse.h:342
QueryCache is a convenient way to construct and pass around (possible partially constructed) warehous...
Definition: TheWarehouse.h:208
bool operator!=(const Attribute &other) const
Definition: TheWarehouse.h:62
Attribute is an abstract class that can be implemented in order to track custom metadata about MooseO...
Definition: TheWarehouse.h:50
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:302
void add(std::shared_ptr< MooseObject > obj)
add adds a new object to the warehouse and stores attributes/metadata about it for running queries/fi...
Definition: TheWarehouse.C:116
std::vector< T * > & queryInto(std::vector< T *> &results, Args &&... args)
queryInto executes the query and stores the results in the given vector.
Definition: TheWarehouse.h:311
virtual bool isEqual(const Attribute &other) const =0
isEqual returns true if the meta-data stored in this attribute is identical to that stored in other...
This attribute describes sorting state.
Definition: TheWarehouse.h:112
QueryCache(const QueryCache &other)
Definition: TheWarehouse.h:269
bool operator==(const Attribute &other) const
Definition: TheWarehouse.h:58
std::tuple< KeyType< Attribs >... > KeyTuple
Definition: TheWarehouse.h:211
Attribute(TheWarehouse &w, const std::string name)
Constructs/initializes a new attribute with the specified name for use in warehouse w...
Definition: TheWarehouse.C:36
void hash_combine(std::size_t &)
Used for hash function specialization for Attribute objects.
Definition: MooseHashing.h:22
std::size_t count()
count returns the number of results that match the query (this requires actually running the query)...
Definition: TheWarehouse.h:295
QueryCache(TheWarehouse &w)
Creates a new query operating on the given warehouse w.
Definition: TheWarehouse.h:218
virtual std::size_t hash() const =0
This function must return a deterministic value that is uniquely determined by the data the attribute...
virtual bool isEqual(const Attribute &other) const override
isEqual returns true if the meta-data stored in this attribute is identical to that stored in other...
Definition: TheWarehouse.C:51
std::size_t operator()(const Attribute &attrib) const
Definition: TheWarehouse.h:153
std::vector< std::unique_ptr< Attribute > > _attribs
Definition: TheWarehouse.h:401
std::unique_ptr< WarehouseStorage > _store
Definition: TheWarehouse.h:518
void setAttribsInner(K k, Args &... args)
Definition: TheWarehouse.h:390
std::unordered_map< std::string, unsigned int > _attrib_ids
Definition: TheWarehouse.h:530
QueryCache & operator=(const T &q)
Copy constructor from another Query.
Definition: TheWarehouse.h:255
std::mutex _query_cache_mutex
Definition: TheWarehouse.h:534
QueryCache<> Query
Definition: TheWarehouse.h:409
std::map< std::pair< bool, KeyTuple >, std::size_t > _cache
Definition: TheWarehouse.h:405
bool operator==(const std::unique_ptr< Attribute > &lhs, const std::unique_ptr< Attribute > &rhs)
TheWarehouse uses this operator function for indexing and caching queries.
Definition: TheWarehouse.C:31
std::vector< std::shared_ptr< MooseObject > > _objects
Definition: TheWarehouse.h:519
Every object that can be built by the factory should be derived from this class.
Definition: MooseObject.h:28
std::size_t numAttribs() const
Gets the number of attributes associated with the cached query.
Definition: TheWarehouse.h:330
QueryCache & operator=(const QueryCache &other)
Definition: TheWarehouse.h:234
void readAttribs(const MooseObject *obj, std::vector< std::unique_ptr< Attribute >> &attribs)
Definition: TheWarehouse.C:276
TheWarehouse & warehouse() const
Definition: TheWarehouse.h:297
std::size_t queryID(const std::vector< std::unique_ptr< Attribute >> &conds)
Definition: TheWarehouse.C:246
TheWarehouse is a container for MooseObjects that allows querying/filtering over various customizeabl...
Definition: TheWarehouse.h:185
virtual bool isMatch(const Attribute &other) const override
isMatch returns true if the meta-data stored in this attribute is equivalent to that stored in other...
Definition: TheWarehouse.C:44
std::vector< T * > & queryInto(int query_id, std::vector< T *> &results, bool show_all=false)
Definition: TheWarehouse.h:486
int prepare(std::vector< std::unique_ptr< Attribute >> conds)
prepares a query and returns an associated query_id (i.e. for use with the query function).
Definition: TheWarehouse.C:166
QueryCache clone() const
clone creates and returns an independent copy of the query in its current state.
Definition: TheWarehouse.h:292
constexpr bool is_sorted()
Check if the given index sequence is sorted ()internal function)
std::tuple< AttribType< Attribs >... > AttribTuple
Definition: TheWarehouse.h:212
std::unordered_map< std::vector< std::unique_ptr< Attribute > >, int > _query_cache
Definition: TheWarehouse.h:528
std::mutex _obj_mutex
Definition: TheWarehouse.h:533
virtual ~Attribute()
Definition: TheWarehouse.h:56
AttribSorted(TheWarehouse &w)
Definition: TheWarehouse.h:118
std::unordered_map< MooseObject *, std::size_t > _obj_ids
Definition: TheWarehouse.h:520
std::size_t operator()(const std::vector< std::unique_ptr< Attribute >> &attribs) const
Definition: TheWarehouse.h:166
void setKeysInner(K &k, Args &... args)
Definition: TheWarehouse.h:379
void update(MooseObject *obj)
update updates the metadata/attribute-info stored for the given object obj that must already exists i...
Definition: TheWarehouse.C:154
Query query()
query creates and returns an initialized a query object for querying objects from the warehouse...
Definition: TheWarehouse.h:466
void setFrom(const Key &k)
Definition: TheWarehouse.h:116
unsigned int registerAttribute(const std::string &name, Args... dummy_args)
registers a new "tracked" attribute of type T for the warehouse.
Definition: TheWarehouse.h:429
std::vector< std::unique_ptr< Attribute > > attributes() const
attribs returns a copy of the constructed Attribute list for the query in its current state...
Definition: TheWarehouse.h:300
virtual void initFrom(const MooseObject *obj) override
initFrom reads and stores the desired meta-data from obj for later matching comparisons.
Definition: TheWarehouse.C:39
std::vector< T * > & queryInto(const std::vector< std::unique_ptr< Attribute >> &conds, std::vector< T *> &results)
queryInto takes the given conditions (i.e.
Definition: TheWarehouse.h:477
QueryCache & condition(Args &&... args)
Adds a new condition to the query.
Definition: TheWarehouse.h:284
typename T::Key KeyType
Definition: TheWarehouse.h:189
unsigned int attribID(const std::string &name)
Returns a unique ID associated with the given attribute name - i.e.
Definition: TheWarehouse.h:443
AttribSorted & operator=(const AttribSorted &)=default
std::vector< T * > & queryIntoUnsorted(std::vector< T *> &results, Args &&... args)
queryInto executes the query and stores the results in the given vector.
Definition: TheWarehouse.h:324
AttribSorted(TheWarehouse &w, bool is_sorted)
Definition: TheWarehouse.h:119
virtual bool isMatch(const Attribute &other) const =0
isMatch returns true if the meta-data stored in this attribute is equivalent to that stored in other...
clonefunc(AttribSorted)
virtual void initFrom(const MooseObject *obj)=0
initFrom reads and stores the desired meta-data from obj for later matching comparisons.
std::vector< std::unique_ptr< Attribute > > _attrib_list
Definition: TheWarehouse.h:531
std::vector< std::vector< MooseObject * > > _obj_cache
Definition: TheWarehouse.h:524
virtual std::unique_ptr< Attribute > clone() const =0
clone creates and returns and identical (deep) copy of this attribute - i.e.