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 <unordered_map>
13 : #include <mutex>
14 : #include <deque>
15 :
16 : #include "MooseError.h"
17 :
18 : template <class Key, class Item, class KeyHash = std::hash<Key>>
19 : class GeneralRegistry
20 : {
21 : public:
22 : GeneralRegistry(const std::string & name);
23 :
24 : /**
25 : * @returns The number of registered items
26 : */
27 : std::size_t size() const;
28 :
29 : /**
30 : * @returns The ID assocated with the key \p key
31 : */
32 : std::size_t id(const Key & key) const;
33 :
34 : /**
35 : * @returns Whether or not the key \p key is registered
36 : */
37 : bool keyExists(const Key & key) const;
38 : /**
39 : * @returns Whether or not the id \p id is registered
40 : */
41 : bool idExists(const std::size_t id) const;
42 :
43 : /**
44 : * @returns The item associated with the key \p key (thread safe)
45 : */
46 : const Item & item(const std::size_t id) const;
47 :
48 : protected:
49 : /**
50 : * @returns The item associated with the key \p key (not thread safe)
51 : */
52 : const Item & itemNonLocking(const std::size_t id) const;
53 :
54 : /**
55 : * Registers an item with key \p key if said key does not exist.
56 : *
57 : * @param key The key
58 : * @param create_item Lambda called to create an item if the key
59 : * does not exist. Takes a single argument std::size_t which is the
60 : # new ID and should return an Item
61 : * @returns The ID of the item
62 : */
63 : template <typename CreateItem>
64 : std::size_t registerItem(const Key & key, CreateItem & create_item);
65 :
66 : /// The name of this registry; used in error handling
67 : const std::string _name;
68 :
69 : /// Map of keys to IDs
70 : std::unordered_map<Key, std::size_t, KeyHash> _key_to_id;
71 : /// Vector of IDs to Items
72 : std::deque<Item> _id_to_item;
73 :
74 : /// Mutex for locking access to _key_to_id
75 : /// NOTE: These can be changed to shared_mutexes once we get C++17
76 : mutable std::mutex _key_to_id_mutex;
77 : /// Mutex for locking access to _id_to_item
78 : /// NOTE: These can be changed to shared_mutexes once we get C++17
79 : mutable std::mutex _id_to_item_mutex;
80 : };
81 :
82 : template <class Key, class Item, class KeyHash>
83 102346 : GeneralRegistry<Key, Item, KeyHash>::GeneralRegistry(const std::string & name) : _name(name)
84 : {
85 102346 : }
86 :
87 : template <class Key, class Item, class KeyHash>
88 : std::size_t
89 103063 : GeneralRegistry<Key, Item, KeyHash>::size() const
90 : {
91 103063 : std::lock_guard<std::mutex> lock(_id_to_item_mutex);
92 206126 : return _id_to_item.size();
93 103063 : }
94 :
95 : template <class Key, class Item, class KeyHash>
96 : std::size_t
97 99917297 : GeneralRegistry<Key, Item, KeyHash>::id(const Key & key) const
98 : {
99 99917297 : std::lock_guard<std::mutex> lock(_key_to_id_mutex);
100 99917297 : const auto it = _key_to_id.find(key);
101 99917297 : if (it == _key_to_id.end())
102 4 : mooseError(_name, ": Key '", key, "' is not registered");
103 199834586 : return it->second;
104 99917293 : }
105 :
106 : template <class Key, class Item, class KeyHash>
107 : bool
108 91086433 : GeneralRegistry<Key, Item, KeyHash>::keyExists(const Key & key) const
109 : {
110 91086433 : std::lock_guard<std::mutex> lock(_key_to_id_mutex);
111 182172866 : return _key_to_id.count(key);
112 91086433 : }
113 :
114 : template <class Key, class Item, class KeyHash>
115 : bool
116 : GeneralRegistry<Key, Item, KeyHash>::idExists(const std::size_t id) const
117 : {
118 : std::lock_guard<std::mutex> lock(_id_to_item_mutex);
119 : return id < _id_to_item.size();
120 : }
121 :
122 : template <class Key, class Item, class KeyHash>
123 : const Item &
124 6235193 : GeneralRegistry<Key, Item, KeyHash>::item(const std::size_t id) const
125 : {
126 6235193 : std::lock_guard<std::mutex> lock(_id_to_item_mutex);
127 12470382 : return itemNonLocking(id);
128 6235189 : }
129 :
130 : template <class Key, class Item, class KeyHash>
131 : const Item &
132 165033845 : GeneralRegistry<Key, Item, KeyHash>::itemNonLocking(const std::size_t id) const
133 : {
134 165033845 : if (id >= _id_to_item.size())
135 4 : mooseError(_name, ": ID '", id, "' is not registered");
136 165033841 : return _id_to_item[id];
137 : }
138 :
139 : template <class Key, class Item, class KeyHash>
140 : template <typename CreateItem>
141 : std::size_t
142 8529780 : GeneralRegistry<Key, Item, KeyHash>::registerItem(const Key & key, CreateItem & create_item)
143 : {
144 8529780 : std::lock_guard<std::mutex> lock_key(_key_to_id_mutex);
145 :
146 : // Is it already registered?
147 8529780 : const auto it = _key_to_id.find(key);
148 8529780 : if (it != _key_to_id.end())
149 1904933 : return it->second;
150 :
151 : // It's not registered
152 6624847 : std::lock_guard<std::mutex> lock_id(_id_to_item_mutex);
153 6624847 : const auto id = _id_to_item.size();
154 6624847 : _key_to_id.emplace(key, id);
155 6624847 : _id_to_item.emplace_back(std::move(create_item(id)));
156 6624847 : return id;
157 8529780 : }
|