https://mooseframework.inl.gov
Loading...
Searching...
No Matches
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#include <type_traits>
19
20#include "MooseObject.h"
21#include "MooseHashing.h"
22#include "MooseUtils.h"
23
24class MooseObject;
26class TheWarehouse;
27
52{
53public:
56 Attribute(TheWarehouse & w, const std::string name);
57 virtual ~Attribute() {}
58
59 inline bool operator==(const Attribute & other) const
60 {
61 return _id == other._id && isEqual(other);
62 }
63 inline bool operator!=(const Attribute & other) const { return !(*this == other); }
64
68 inline unsigned int id() const { return _id; }
69
76 virtual std::size_t hash() const = 0;
77
79 virtual void initFrom(const MooseObject * obj) = 0;
83 virtual bool isMatch(const Attribute & other) const = 0;
87 virtual bool isEqual(const Attribute & other) const = 0;
90 virtual std::unique_ptr<Attribute> clone() const = 0;
91
92private:
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
114{
115public:
116 typedef bool Key;
117 void setFrom(const Key & k) { _val = k; }
118
119 AttribSorted(TheWarehouse & w) : Attribute(w, "sorted"), _val(false), _initd(false) {}
120 AttribSorted(TheWarehouse & w, bool is_sorted)
121 : Attribute(w, "sorted"), _val(is_sorted), _initd(true)
122 {
123 }
124 AttribSorted(const AttribSorted &) = default;
126 AttribSorted & operator=(const 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;
134
135private:
136 bool _val;
137 bool _initd;
138};
139
140#undef clonefunc
141#undef hashfunc
142
145bool operator==(const std::unique_ptr<Attribute> & lhs, const std::unique_ptr<Attribute> & rhs);
146
147namespace std
148{
150template <>
151struct hash<Attribute>
152{
153public:
154 std::size_t operator()(const Attribute & attrib) const
155 {
156 std::size_t h = attrib.hash();
157 Moose::hash_combine(h, attrib.id());
158 return h;
159 }
160};
161
163template <>
164struct hash<std::vector<std::unique_ptr<Attribute>>>
165{
166public:
167 std::size_t operator()(const std::vector<std::unique_ptr<Attribute>> & attribs) const
168 {
169 std::size_t h = 0;
170 for (auto & attrib : attribs)
171 Moose::hash_combine(h, *attrib);
172 return h;
173 }
174};
175}
176
187{
188public:
189 template <typename T>
190 using KeyType = typename T::Key;
191 template <typename T>
192 using AttribType = T *;
193
208 template <typename... Attribs>
210 {
211 public:
212 typedef std::tuple<KeyType<Attribs>...> KeyTuple;
213 typedef std::tuple<AttribType<Attribs>...> AttribTuple;
214
216
220 {
221 addAttribs<0, Attribs...>();
222 _attribs.reserve(5);
223 }
224
225 template <typename T>
226 QueryCache(const T & q) : _w(&q.warehouse())
227 {
228 addAttribs<0, Attribs...>();
229 _attribs.reserve(5);
230
231 for (auto & attrib : q.attributes())
232 _attribs.push_back(attrib->clone());
233 }
234
236 {
237 if (this == &other)
238 return *this;
239
240 _attribs.clear();
241 _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 addAttribs<0, Attribs...>();
245 _key_tup = other._key_tup;
246 // do NOT copy the cache.
247
248 // only copy over non-parametrized attributes
249 for (std::size_t i = std::tuple_size<AttribTuple>::value; i < other._attribs.size(); i++)
250 _attribs.push_back(other._attribs[i]->clone());
251 return *this;
252 }
253
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 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 addAttribs<0, Attribs...>(); // MUST have own pointers to attribs to avoid data races.
276 for (std::size_t i = std::tuple_size<AttribTuple>::value; i < other._attribs.size(); i++)
277 _attribs.push_back(other._attribs[i]->clone());
278 }
279
284 template <typename T, typename... Args>
285 QueryCache & condition(Args &&... args)
286 {
287 _attribs.emplace_back(new T(*_w, std::forward<Args>(args)...));
288 _cache.clear(); // invalidate cache if base query changes.
289 return *this;
290 }
291
293 QueryCache clone() const { return Query(*this); }
296 std::size_t count() { return _w->count(_attribs); }
297
298 TheWarehouse & warehouse() const { return *_w; }
299
301 std::vector<std::unique_ptr<Attribute>> attributes() const { return clone()._attribs; }
302
311 template <typename T, typename... Args>
312 std::vector<T *> & queryInto(std::vector<T *> & results, Args &&... args)
313 {
314 return queryIntoHelper(results, true, args...);
315 }
316
324 template <typename T, typename... Args>
325 std::vector<T *> & queryIntoUnsorted(std::vector<T *> & results, Args &&... args)
326 {
327 return queryIntoHelper(results, false, args...);
328 }
329
331 std::size_t numAttribs() const { return _attribs.size(); }
332
333 private:
342 template <typename T, typename... Args>
343 std::vector<T *> & queryIntoHelper(std::vector<T *> & results, const bool sort, Args &&... args)
344 {
345 std::lock_guard<std::mutex> lock(_cache_mutex);
346 setKeysInner<0, KeyType<Attribs>...>(args...);
347
348 std::size_t query_id;
349 const auto entry = _cache.find(std::make_pair(sort, _key_tup));
350 if (entry == _cache.end())
351 {
352 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 _attribs.emplace_back(new AttribSorted(*_w, sort));
356 query_id = _w->queryID(_attribs);
357 _cache[std::make_pair(sort, _key_tup)] = query_id;
358 // remove the sort attribute
359 _attribs.pop_back();
360 }
361 else
362 query_id = entry->second;
363
364 return _w->queryInto(query_id, results);
365 }
366
367 template <int Index, typename A, typename... As>
369 {
370 std::get<Index>(_attrib_tup) = new A(*_w);
371 _attribs.emplace_back(std::get<Index>(_attrib_tup));
372 addAttribs<Index + 1, As...>();
373 }
374 template <int Index>
376 {
377 }
378
379 template <int Index, typename K, typename... Args>
380 void setKeysInner(K & k, Args &... args)
381 {
382 std::get<Index>(_key_tup) = k;
383 setKeysInner<Index + 1, Args...>(args...);
384 }
385 template <int Index>
387 {
388 }
389
390 template <int Index, typename K, typename... Args>
391 void setAttribsInner(K k, Args &... args)
392 {
393 std::get<Index>(_attrib_tup)->setFrom(k);
394 setAttribsInner<Index + 1, Args...>(args...);
395 }
396 template <int Index>
398 {
399 }
400
401 TheWarehouse * _w = nullptr;
402 std::vector<std::unique_ptr<Attribute>> _attribs;
403
406 std::map<std::pair<bool, KeyTuple>, std::size_t> _cache;
407 std::mutex _cache_mutex;
408 };
409
411
412 TheWarehouse();
414
429 template <typename T, typename... Args>
430 unsigned int registerAttribute(const std::string & name, Args... dummy_args)
431 {
432 auto it = _attrib_ids.find(name);
433 if (it != _attrib_ids.end())
434 return it->second;
435
436 _attrib_ids[name] = _attrib_list.size();
437 _attrib_list.push_back(std::unique_ptr<Attribute>(new T(*this, dummy_args...)));
438 return _attrib_list.size() - 1;
439 }
440
444 inline unsigned int attribID(const std::string & name)
445 {
446 auto it = _attrib_ids.find(name);
447 if (it != _attrib_ids.end())
448 return it->second;
449 mooseError("no ID exists for unregistered attribute '", name, "'");
450 }
451
454 void add(std::shared_ptr<MooseObject> obj);
455
459 void update(MooseObject * obj);
464 void update(MooseObject * obj, const Attribute & extra);
467 Query query() { return Query(*this); }
471 std::size_t count(const std::vector<std::unique_ptr<Attribute>> & conds);
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 std::vector<T *> & queryInto(int query_id, std::vector<T *> & results, bool show_all = false)
488 {
489 std::lock_guard<std::mutex> lock(_obj_cache_mutex);
490 auto & objs = query(query_id);
491 results.clear();
492 results.reserve(objs.size());
493 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 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 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 if (show_all || obj->enabled())
519 results.push_back(cast_obj);
520 }
521 return results;
522 }
523
524private:
526 int prepare(std::vector<std::unique_ptr<Attribute>> conds);
527
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;
552};
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
Definition MooseError.h:311
unsigned int count
Definition MortarUtils.C:53
bool operator==(const std::unique_ptr< Attribute > &lhs, const std::unique_ptr< Attribute > &rhs)
TheWarehouse uses this operator function for indexing and caching queries.
This attribute describes sorting state.
AttribSorted & operator=(AttribSorted &&)=default
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.
void setFrom(const Key &k)
AttribSorted(AttribSorted &&)=default
AttribSorted(const AttribSorted &)=default
AttribSorted & operator=(const AttribSorted &)=default
clonefunc(AttribSorted)
AttribSorted(TheWarehouse &w)
AttribSorted(TheWarehouse &w, bool is_sorted)
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.
virtual void initFrom(const MooseObject *obj) override
initFrom reads and stores the desired meta-data from obj for later matching comparisons.
Attribute is an abstract class that can be implemented in order to track custom metadata about MooseO...
unsigned int id() const
returns the unique attribute ID associated with all attributes that have the same (mose derived) clas...
bool operator!=(const Attribute &other) const
virtual std::unique_ptr< Attribute > clone() const =0
clone creates and returns and identical (deep) copy of this attribute - i.e.
virtual std::size_t hash() const =0
This function must return a deterministic value that is uniquely determined by the data the attribute...
virtual ~Attribute()
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.
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.
virtual void initFrom(const MooseObject *obj)=0
initFrom reads and stores the desired meta-data from obj for later matching comparisons.
bool operator==(const Attribute &other) const
Every object that can be built by the factory should be derived from this class.
Definition MooseObject.h:31
QueryCache is a convenient way to construct and pass around (possible partially constructed) warehous...
std::vector< std::unique_ptr< Attribute > > _attribs
std::vector< std::unique_ptr< Attribute > > attributes() const
attribs returns a copy of the constructed Attribute list for the query in its current state.
std::size_t numAttribs() const
Gets the number of attributes associated with the cached query.
QueryCache(TheWarehouse &w)
Creates a new query operating on the given warehouse w.
std::size_t count()
count returns the number of results that match the query (this requires actually running the query).
QueryCache(const QueryCache &other)
QueryCache & operator=(const T &q)
Copy constructor from another Query.
QueryCache & condition(Args &&... args)
Adds a new condition to the query.
QueryCache clone() const
clone creates and returns an independent copy of the query in its current state.
std::tuple< AttribType< Attribs >... > AttribTuple
std::tuple< KeyType< Attribs >... > KeyTuple
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.
std::map< std::pair< bool, KeyTuple >, std::size_t > _cache
std::vector< T * > & queryInto(std::vector< T * > &results, Args &&... args)
queryInto executes the query and stores the results in the given vector.
TheWarehouse & warehouse() const
std::vector< T * > & queryIntoUnsorted(std::vector< T * > &results, Args &&... args)
queryInto executes the query and stores the results in the given vector.
QueryCache & operator=(const QueryCache &other)
void setKeysInner(K &k, Args &... args)
void setAttribsInner(K k, Args &... args)
TheWarehouse is a container for MooseObjects that allows querying/filtering over various customizeabl...
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).
std::unordered_map< std::string, unsigned int > _attrib_ids
std::mutex _query_cache_mutex
std::mutex _obj_mutex
Query query()
query creates and returns an initialized a query object for querying objects from the warehouse.
std::vector< std::shared_ptr< MooseObject > > _objects
unsigned int attribID(const std::string &name)
Returns a unique ID associated with the given attribute name - i.e.
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...
std::size_t count(const std::vector< std::unique_ptr< Attribute > > &conds)
count returns the number of objects that match the provided query conditions.
std::unordered_map< MooseObject *, std::size_t > _obj_ids
void readAttribs(const MooseObject *obj, std::vector< std::unique_ptr< Attribute > > &attribs)
void update(MooseObject *obj)
update updates the metadata/attribute-info stored for the given object obj that must already exists i...
std::vector< std::vector< MooseObject * > > _obj_cache
QueryCache<> Query
std::unique_ptr< WarehouseStorage > _store
std::mutex _obj_cache_mutex
unsigned int registerAttribute(const std::string &name, Args... dummy_args)
registers a new "tracked" attribute of type T for the warehouse.
std::unordered_map< std::vector< std::unique_ptr< Attribute > >, int > _query_cache
std::vector< T * > & queryInto(const std::vector< std::unique_ptr< Attribute > > &conds, std::vector< T * > &results)
queryInto takes the given conditions (i.e.
std::size_t queryID(const std::vector< std::unique_ptr< Attribute > > &conds)
std::vector< std::unique_ptr< Attribute > > _attrib_list
typename T::Key KeyType
std::vector< T * > & queryInto(int query_id, std::vector< T * > &results, bool show_all=false)
void hash_combine(std::size_t &)
Used for hash function specialization for Attribute objects.
std::size_t operator()(const Attribute &attrib) const
std::size_t operator()(const std::vector< std::unique_ptr< Attribute > > &attribs) const