SST  13.0.0
StructuralSimulationToolkit
sharedSet.h
1 // Copyright 2009-2023 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-2023, 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 
20 namespace SST {
21 namespace 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  */
27 template <typename valT>
28 class 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 
35 public:
36  SharedSet() : SharedObject(), published(false), data(nullptr) {}
37 
38  ~SharedSet()
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 
191 private:
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::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 
288  ImplementSerializable(SST::Shared::SharedSet<valT>::Data::ChangeSet);
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:34
Definition: sharedObject.h:260
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
SharedSet class.
Definition: sharedSet.h:28
void lock()
Called by the core when writing to shared regions is no longer allowed.
Definition: sharedObject.h:186
const std::string & getName()
Get the name of the shared data the changeset should be applied to.
Definition: sharedObject.h:72
bool empty() const
Tests if the set is empty.
Definition: sharedSet.h:94
const_reverse_iterator rend() const
Get const_reverse_iterator to end of underlying set.
Definition: sharedSet.h:122
Definition: action.cc:18
const_iterator begin() const
Get const_iterator to beginning of underlying set.
Definition: sharedSet.h:107
verify_type
Enum of verify types.
Definition: sharedObject.h:267
bool isFullyPublished()
Check whether all instances of this SharedSet have called publish().
Definition: sharedSet.h:143
const_iterator end() const
Get const_iterator to end of underlying set.
Definition: sharedSet.h:112
void publish()
Indicate that the calling element has written all the data it plans to write.
Definition: sharedSet.h:129
virtual void applyChanges(SharedObjectDataManager *UNUSED(manager))=0
Apply the changes to the name shared data.
int initialize(const std::string &obj_name, verify_type v_type)
Initialize the SharedSet.
Definition: sharedSet.h:65
void insert(const valT &value)
Insert data to the set.
Definition: sharedSet.h:151
Base class for holding SharedObject data.
Definition: sharedObject.h:87
const_reverse_iterator rbegin() const
Get const_reverse_iterator to beginning of underlying set.
Definition: sharedSet.h:117
size_t size() const
Get the size of the set.
Definition: sharedSet.h:87
size_t count(const valT &k) const
Counts elements with a specific value.
Definition: sharedSet.h:102
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