SST 12.1.0
Structural Simulation Toolkit
sharedSet.h
1// Copyright 2009-2022 NTESS. Under the terms
2// of Contract DE-NA0003525 with NTESS, the U.S.
3// Government retains certain rights in this software.
4//
5// Copyright (c) 2009-2022, NTESS
6// All rights reserved.
7//
8// This file is part of the SST software package. For license
9// information, see the LICENSE file in the top level directory of the
10// distribution.
11
12#ifndef SST_CORE_SHARED_SHAREDSET_H
13#define SST_CORE_SHARED_SHAREDSET_H
14
15#include "sst/core/shared/sharedObject.h"
16#include "sst/core/sst_types.h"
17
18#include <set>
19
20namespace SST {
21namespace Shared {
22
23/**
24 SharedSet class. The class is templated to allow for an array
25 of any non-pointer type. The type must be serializable.
26 */
27template <typename valT>
28class SharedSet : public SharedObject
29{
30 static_assert(!std::is_pointer<valT>::value, "Cannot use a pointer type as value with SharedSet");
31
32 // Forward declaration. Defined below
33 class Data;
34
35public:
36 SharedSet() : SharedObject(), published(false), data(nullptr) {}
37
39 {
40 // data does not need to be deleted since the
41 // SharedObjectManager owns the pointer
42 }
43
44 /**
45 Initialize the SharedSet.
46
47 @param obj_name Name of the object. This name is how the
48 object is uniquely identified across ranks.
49
50 @param verify_mode Specifies how multiply written data should
51 be verified. Since the underlying set knows if the data has
52 already been written, FE_VERIFY and INIT_VERIFY simply use this
53 built-in mechanism to know when an item has previously been
54 written. When these modes are enabled, multiply written data
55 must match what was written before. When NO_VERIFY is passed,
56 no verification will occur. This is mostly useful when you can
57 guarantee that multiple elements won't write the same value and
58 you want to do in-place modifications as you initialize.
59 VERIFY_UNINITIALIZED is a reserved value and should not be
60 passed.
61
62 @return returns the number of instances that have intialized
63 themselve before this instance on this MPI rank.
64 */
65 int initialize(const std::string& obj_name, verify_type v_type)
66 {
67 if ( data ) {
68 Private::getSimulationOutput().fatal(
69 CALL_INFO, 1, "ERROR: called initialize() of SharedSet %s more than once\n", obj_name.c_str());
70 }
71
72 data = manager.getSharedObjectData<Data>(obj_name);
73 int ret = incShareCount(data);
74 data->setVerify(v_type);
75 return ret;
76 }
77
78 /*** Typedefs and functions to mimic parts of the vector API ***/
79 typedef typename std::set<valT>::const_iterator const_iterator;
80 typedef typename std::set<valT>::const_reverse_iterator const_reverse_iterator;
81
82 /**
83 Get the size of the set.
84
85 @return size of the set
86 */
87 inline size_t size() const { return data->getSize(); }
88
89 /**
90 Tests if the set is empty.
91
92 @return true if set is empty, false otherwise
93 */
94 inline bool empty() const { return data->set.empty(); }
95
96 /**
97 Counts elements with a specific value. Becuase this is not a
98 multiset, it will either return 1 or 0.
99
100 @return Count of elements with specified value
101 */
102 size_t count(const valT& k) const { return data->set.count(k); }
103
104 /**
105 Get const_iterator to beginning of underlying set
106 */
107 const_iterator begin() const { return data->set.cbegin(); }
108
109 /**
110 Get const_iterator to end of underlying set
111 */
112 const_iterator end() const { return data->set.cend(); }
113
114 /**
115 Get const_reverse_iterator to beginning of underlying set
116 */
117 const_reverse_iterator rbegin() const { return data->set.crbegin(); }
118
119 /**
120 Get const_reverse_iterator to end of underlying set
121 */
122 const_reverse_iterator rend() const { return data->set.crend(); }
123
124 /**
125 Indicate that the calling element has written all the data it
126 plans to write. Writing to the set through this instance
127 after publish() is called will create an error.
128 */
129 void publish()
130 {
131 if ( published ) return;
132 published = true;
133 incPublishCount(data);
134 }
135
136 /**
137 Check whether all instances of this SharedSet have called
138 publish(). NOTE: Is is possible that this could return true
139 one round, but false the next if a new instance of the
140 SharedSet was initialized but not published after the last
141 call.
142 */
143 bool isFullyPublished() { return data->isFullyPublished(); }
144
145 /**
146 Insert data to the set. This function is thread-safe, as a
147 mutex is used to ensure only one insert at a time.
148
149 @param val value of the insert
150 */
151 inline void insert(const valT& value)
152 {
153 if ( published ) {
154 Private::getSimulationOutput().fatal(
155 CALL_INFO, 1, "ERROR: insert into SharedSet %s after publish() was called\n", data->getName().c_str());
156 }
157 return data->write(value);
158 }
159
160 /**
161 Searches the SharedSet for an element equivalent to value and
162 returns a const iterator to it if found, otherwise it returns
163 an iterator to SharedSet::end.
164
165 @param value value to search for
166
167 NOTE: This function does not use a mutex, so it is possible to
168 get invalid results if another thread is simulateously writing
169 to the set. However, after the init() phase of simulation is
170 complete (in setup() and beyond), this is always a safe
171 operation. If reading during init() and you can't guarantee
172 that all elements have already written all elements to the
173 SharedSet, use mutex_find() to guarantee thread safety.
174
175 @return read-only iterator to data referenced by value
176 */
177 inline const_iterator find(const valT& value) const { return data->find(value); }
178
179 /**
180 Searches the SharedSet for an element equivalent to value and
181 returns a const iterator to it if found, otherwise it returns
182 an iterator to SharedSet::end. This version of find is always thread safe (@see
183 find()).
184
185 @param value value to search for
186
187 @return read-only iterator to data reference by value
188 */
189 inline const valT& mutex_find(const valT& value) const { return data->mutex_read(value); }
190
191private:
192 bool published;
193 Data* data;
194
195 class Data : public SharedObjectData
196 {
197
198 // Forward declaration. Defined below
199 class ChangeSet;
200
201 public:
202 std::set<valT> set;
203 ChangeSet* change_set;
204
205 verify_type verify;
206
207 Data(const std::string& name) : SharedObjectData(name), change_set(nullptr), verify(VERIFY_UNINITIALIZED)
208 {
209 if ( Private::getSimulation()->getNumRanks().rank > 1 ) { change_set = new ChangeSet(name); }
210 }
211
212 ~Data() { delete change_set; }
213
214 void setVerify(verify_type v_type)
215 {
216 if ( v_type != verify && verify != VERIFY_UNINITIALIZED ) {
217 Private::getSimulationOutput().fatal(
218 CALL_INFO, 1, "ERROR: Type different verify_types specified for SharedSet %s\n", name.c_str());
219 }
220 verify = v_type;
221 if ( change_set ) change_set->setVerify(v_type);
222 }
223
224 size_t getSize() const
225 {
226 std::lock_guard<std::mutex> lock(mtx);
227 return set.size();
228 }
229
230 void update_write(const valT& value)
231 {
232 // Don't need to mutex because this is only ever called
233 // from one thread at a time, with barrier before and
234 // after, or from write(), which does mutex.
235 auto success = set.insert(value);
236 if ( !success.second ) {
237 // Wrote to a value that already existed
238 if ( verify != NO_VERIFY && !(value == *(success.first)) ) {
239 Private::getSimulationOutput().fatal(
240 CALL_INFO, 1, "ERROR: wrote two non-equal values to same set item in SharedSet %s\n",
241 name.c_str());
242 }
243 }
244 }
245
246 void write(const valT& value)
247 {
248 // std::lock_guard<std::mutex> lock(mtx);
249 check_lock_for_write("SharedSet");
250 update_write(value);
251 if ( change_set ) change_set->addChange(value);
252 }
253
254 // Inline the read since it may be called often during run().
255 // This read is not protected from data races in the case
256 // where the set may be simulataeously written by another
257 // thread. If there is a danger of simultaneous access
258 // during init, use the mutex_read function until after the
259 // init phase.
260 inline const_iterator find(const valT& value) { return set.find(value); }
261
262 // Mutexed read for use if you are resizing the array as you go
263 inline const valT& mutex_find(const valT& value)
264 {
265 std::lock_guard<std::mutex> lock(mtx);
266 auto ret = set.find(value);
267 return ret;
268 }
269
270 // Functions inherited from SharedObjectData
271 virtual SharedObjectChangeSet* getChangeSet() override { return change_set; }
272 virtual void resetChangeSet() override { change_set->clear(); }
273
274 private:
275 class ChangeSet : public SharedObjectChangeSet
276 {
277
278 std::set<valT> changes;
279 verify_type verify;
280
281 void serialize_order(SST::Core::Serialization::serializer& ser) override
282 {
283 SharedObjectChangeSet::serialize_order(ser);
284 ser& changes;
285 ser& verify;
286 }
287
289
290 public:
291 // For serialization
292 ChangeSet() : SharedObjectChangeSet(), verify(VERIFY_UNINITIALIZED) {}
293 ChangeSet(const std::string& name) : SharedObjectChangeSet(name), verify(VERIFY_UNINITIALIZED) {}
294
295 void addChange(const valT& value) { changes.insert(value); }
296
297 void setVerify(verify_type v_type) { verify = v_type; }
298
299 void applyChanges(SharedObjectDataManager* manager) override
300 {
301 auto data = manager->getSharedObjectData<Data>(getName());
302 data->setVerify(verify);
303 for ( auto x : changes ) {
304 data->update_write(x);
305 }
306 }
307
308 void clear() override { changes.clear(); }
309 };
310 };
311};
312
313} // namespace Shared
314} // namespace SST
315
316#endif // SST_CORE_SHARED_SHAREDSET_H
This class is basically a wrapper for objects to declare the order in which their members should be s...
Definition: serializer.h:35
const std::string & getName()
Get the name of the shared data the changeset should be applied to.
Definition: sharedObject.h:71
virtual void applyChanges(SharedObjectDataManager *UNUSED(manager))=0
Apply the changes to the name shared data.
Base class for holding SharedObject data.
Definition: sharedObject.h:87
void lock()
Called by the core when writing to shared regions is no longer allowed.
Definition: sharedObject.h:185
Definition: sharedObject.h:260
verify_type
Enum of verify types.
Definition: sharedObject.h:266
SharedSet class.
Definition: sharedSet.h:29
const_reverse_iterator rbegin() const
Get const_reverse_iterator to beginning of underlying set.
Definition: sharedSet.h:117
int initialize(const std::string &obj_name, verify_type v_type)
Initialize the SharedSet.
Definition: sharedSet.h:65
const_iterator end() const
Get const_iterator to end of underlying set.
Definition: sharedSet.h:112
const_iterator find(const valT &value) const
Searches the SharedSet for an element equivalent to value and returns a const iterator to it if found...
Definition: sharedSet.h:177
bool isFullyPublished()
Check whether all instances of this SharedSet have called publish().
Definition: sharedSet.h:143
const_reverse_iterator rend() const
Get const_reverse_iterator to end of underlying set.
Definition: sharedSet.h:122
void publish()
Indicate that the calling element has written all the data it plans to write.
Definition: sharedSet.h:129
void insert(const valT &value)
Insert data to the set.
Definition: sharedSet.h:151
const valT & mutex_find(const valT &value) const
Searches the SharedSet for an element equivalent to value and returns a const iterator to it if found...
Definition: sharedSet.h:189
bool empty() const
Tests if the set is empty.
Definition: sharedSet.h:94
const_iterator begin() const
Get const_iterator to beginning of underlying set.
Definition: sharedSet.h:107
size_t count(const valT &k) const
Counts elements with a specific value.
Definition: sharedSet.h:102
size_t size() const
Get the size of the set.
Definition: sharedSet.h:87