GetFEM  5.4.2
dal_static_stored_objects.cc
1 /*===========================================================================
2 
3  Copyright (C) 2002-2020 Yves Renard
4 
5  This file is a part of GetFEM
6 
7  GetFEM is free software; you can redistribute it and/or modify it
8  under the terms of the GNU Lesser General Public License as published
9  by the Free Software Foundation; either version 3 of the License, or
10  (at your option) any later version along with the GCC Runtime Library
11  Exception either version 3.1 or (at your option) any later version.
12  This program is distributed in the hope that it will be useful, but
13  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15  License and GCC Runtime Library Exception for more details.
16  You should have received a copy of the GNU Lesser General Public License
17  along with this program; if not, write to the Free Software Foundation,
18  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19 
20 ===========================================================================*/
21 
22 
24 #include "getfem/dal_singleton.h"
25 #include <map>
26 #include <list>
27 #include <set>
28 #include <algorithm>
29 #include <deque>
30 
31 
32 namespace dal {
33 
34  // 0 = only undestroyed, 1 = Normal, 2 very noisy,
35 #define DAL_STORED_OBJECT_DEBUG_NOISY 2
36 
37 #if DAL_STORED_OBJECT_DEBUG
38 
39  static bool dal_static_stored_tab_valid__ = true;
40 
41  #define STORED_ASSERT(test, message) GMM_ASSERT1(test, message);
42  #define ON_STORED_DEBUG(expression) expression;
43 
44  static std::map <const static_stored_object *, std::string> _created_objects;
45  static std::map <const static_stored_object *, std::string> _added_objects;
46  static std::map <const static_stored_object *, std::string> _deleted_objects;
47 
48 
49  void stored_debug_created(const static_stored_object *o,
50  const std::string &name) {
51  if (dal_static_stored_tab_valid__) {
52  _created_objects[o] = name;
53 # if DAL_STORED_OBJECT_DEBUG_NOISY > 1
54  cout << "Created " << name << " : " << o << endl;
55 # endif
56  }
57  }
58  void stored_debug_added(const static_stored_object *o) {
59  if (dal_static_stored_tab_valid__) {
60  auto it = _created_objects.find(o);
61  if (it == _created_objects.end()) {
62  _added_objects[o] = "";
63 # if DAL_STORED_OBJECT_DEBUG_NOISY > 0
64  cout << "Adding an unknown object " << o << " of type "
65  << typeid(*o).name() << " add DAL_STORED_OBJECT_DEBUG_CREATED"
66  "(o, name) in its constructor" << endl;
67 # endif
68  } else {
69  _added_objects[o] = it->second;
70  _created_objects.erase(it);
71 # if DAL_STORED_OBJECT_DEBUG_NOISY > 1
72  cout << "Added " << it->second << " : " << o << endl;
73 # endif
74  }
75  if (_deleted_objects.size()) {
76  cout << endl << "Number of stored objects: " << _added_objects.size()
77  << endl << "Number of unstored created objects: "
78  << _created_objects.size() << endl
79  << "Number of undestroyed object: "
80  << _deleted_objects.size() << endl;
81  for (auto &x : _deleted_objects)
82  cout << "UNDESTROYED OBJECT " << x.second << " : " << x.first << endl;
83  }
84  }
85  }
86 
87  void stored_debug_deleted(const static_stored_object *o) {
88  if (dal_static_stored_tab_valid__) {
89  auto it = _added_objects.find(o);
90  if (it == _added_objects.end()) {
91  cout << "Deleting an unknown object ! " << o << endl;
92  _deleted_objects[o] = "";
93  } else {
94  _deleted_objects[o] = it->second;
95  _added_objects.erase(it);
96 # if DAL_STORED_OBJECT_DEBUG_NOISY > 1
97  cout << "Deleted " << it->second << " : " << o << endl;
98 # endif
99  }
100  }
101  }
102 
103  void stored_debug_destroyed(const static_stored_object *o,
104  const std::string &name) {
105  if (dal_static_stored_tab_valid__) {
106  auto it = _deleted_objects.find(o);
107  if (it == _deleted_objects.end()) {
108  it = _created_objects.find(o);
109  if (it == _created_objects.end()) {
110  it = _added_objects.find(o);
111  if (it == _added_objects.end()) {
112  cout << "Destroy an unknown object ! " << o << " name given : "
113  << name << endl;
114  } else {
115  _added_objects.erase(it);
116  cout << "Destroy a non deleted object !! " << o << " name given : "
117  << name << endl;
118  }
119  } else {
120 # if DAL_STORED_OBJECT_DEBUG_NOISY > 1
121  cout << "Destroy an unadded object " << it->second << " : "
122  << o << endl;
123 # endif
124  _created_objects.erase(it);
125  }
126  } else {
127 # if DAL_STORED_OBJECT_DEBUG_NOISY > 1
128  cout << "Destroy " << it->second << " : " << o << " name given : "
129  << name << endl;
130 # endif
131  _deleted_objects.erase(it);
132  }
133 
134  }
135  }
136 
137 #else
138  #define STORED_ASSERT(test, message)
139  #define ON_STORED_DEBUG(expression)
140 #endif
141 
142  // Gives a pointer to a key of an object from its pointer, while looking in the storage of
143  // a specific thread
144  pstatic_stored_object_key key_of_stored_object(pstatic_stored_object o, size_t thread){
145  auto& stored_keys = singleton<stored_object_tab>::instance(thread).stored_keys_;
146  STORED_ASSERT(dal_static_stored_tab_valid__, "Too late to do that");
147  auto it = stored_keys.find(o);
148  if (it != stored_keys.end()) return it->second;
149  return nullptr;
150  }
151 
152  // gives a key of the stored object while looking in the storage of other threads
153  pstatic_stored_object_key key_of_stored_object_other_threads(pstatic_stored_object o){
154  for(size_t thread = 0; thread != singleton<stored_object_tab>::num_threads(); ++thread)
155  {
156  if (thread == singleton<stored_object_tab>::this_thread()) continue;
157  auto key = key_of_stored_object(o,thread);
158  if (key) return key;
159  }
160  return nullptr;
161  }
162 
163  pstatic_stored_object_key key_of_stored_object(pstatic_stored_object o){
164  auto key = key_of_stored_object(o, singleton<stored_object_tab>::this_thread());
165  if (key) return key;
167  key_of_stored_object_other_threads(o) : nullptr;
168  return nullptr;
169  }
170 
171  bool exists_stored_object(pstatic_stored_object o){
172  auto& stored_keys = singleton<stored_object_tab>::instance().stored_keys_;
173  ON_STORED_DEBUG(if (!dal_static_stored_tab_valid__) return false)
174  return (stored_keys.find(o) != stored_keys.end());
175  }
176 
177  pstatic_stored_object search_stored_object(pstatic_stored_object_key k){
178  auto& stored_objects = singleton<stored_object_tab>::instance();
179  ON_STORED_DEBUG(if (!dal_static_stored_tab_valid__) return nullptr)
180  return stored_objects.search_stored_object(k);
181  }
182 
183  pstatic_stored_object search_stored_object_on_all_threads(pstatic_stored_object_key k){
184  auto& stored_objects = singleton<stored_object_tab>::instance();
185  ON_STORED_DEBUG(if (!dal_static_stored_tab_valid__) return nullptr)
186  auto p = stored_objects.search_stored_object(k);
187  if (p) return p;
188  if (singleton<stored_object_tab>::num_threads() == 1) return nullptr;
189  for(size_t thread = 0; thread < singleton<stored_object_tab>::num_threads(); ++thread){
190  if (thread == singleton<stored_object_tab>::this_thread()) continue;
191  auto& other_objects = singleton<stored_object_tab>::instance(thread);
192  p = other_objects.search_stored_object(k);
193  if (p) return p;
194  }
195  return nullptr;
196  }
197 
198  std::pair<stored_object_tab::iterator, stored_object_tab::iterator>
199  iterators_of_object(pstatic_stored_object o){
200  for(size_t thread = 0; thread != singleton<stored_object_tab>::num_threads(); ++thread){
201  auto& stored_objects = singleton<stored_object_tab>::instance(thread);
202  ON_STORED_DEBUG(if (!dal_static_stored_tab_valid__) continue;)
203  auto it = stored_objects.iterator_of_object_(o);
204  if (it != stored_objects.end()) return {it, stored_objects.end()};
205  }
208  }
209 
210 
212  for(size_t thread = 0; thread != singleton<stored_object_tab>::num_threads(); ++thread){
213  auto& stored_objects = singleton<stored_object_tab>::instance(thread);
214  ON_STORED_DEBUG(if (!dal_static_stored_tab_valid__) continue;)
215  auto& stored_keys = stored_objects.stored_keys_;
216 
217  GMM_ASSERT1(stored_objects.size() == stored_keys.size(),
218  "keys and objects tables don't match");
219  for (auto &&pair : stored_keys){
220  auto itos = iterators_of_object(pair.first);
221  GMM_ASSERT1(itos.first != itos.second, "Key without object is found");
222  }
223  for (auto &&pair : stored_objects){
224  auto itos = iterators_of_object(pair.second.p);
225  GMM_ASSERT1(itos.first != itos.second, "Object has key but cannot be found");
226  }
227  }
228  }
229 
230  void add_dependency(pstatic_stored_object o1,
231  pstatic_stored_object o2) {
232  bool dep_added = false;
233  for(size_t thread = 0; thread != singleton<stored_object_tab>::num_threads(); ++thread){
234  auto& stored_objects = singleton<stored_object_tab>::instance(thread);
235  ON_STORED_DEBUG(if (!dal_static_stored_tab_valid__) return)
236  if ((dep_added = stored_objects.add_dependency_(o1,o2))) break;
237  }
238  GMM_ASSERT1(dep_added, "Failed to add dependency between " << o1
239  << " of type " << typeid(*o1).name() << " and " << o2
240  << " of type " << typeid(*o2).name() << ". ");
241 
242  bool dependent_added = false;
243  for(size_t thread = 0; thread != singleton<stored_object_tab>::num_threads(); ++thread){
244  auto& stored_objects = singleton<stored_object_tab>::instance(thread);
245  if ((dependent_added = stored_objects.add_dependent_(o1,o2))) break;
246  }
247  GMM_ASSERT1(dependent_added, "Failed to add dependent between " << o1
248  << " of type " << typeid(*o1).name() << " and " << o2
249  << " of type " << typeid(*o2).name() << ". ");
250  }
251 
252 
253 
254  /*remove a dependency (from storages of all threads).
255  Return true if o2 has no more dependent object. */
256  bool del_dependency(pstatic_stored_object o1, pstatic_stored_object o2){
257  bool dep_deleted = false;
258  for(size_t thread = 0; thread != singleton<stored_object_tab>::num_threads(); ++thread){
259  auto& stored_objects = singleton<stored_object_tab>::instance(thread);
260  ON_STORED_DEBUG(if (!dal_static_stored_tab_valid__) return false)
261  if ((dep_deleted = stored_objects.del_dependency_(o1,o2))) break;
262  }
263  GMM_ASSERT1(dep_deleted, "Failed to delete dependency between " << o1 << " of type "
264  << typeid(*o1).name() << " and " << o2 << " of type "
265  << typeid(*o2).name() << ". ");
266 
267  bool dependent_deleted = false;
268  bool dependent_empty = false;
269  for(size_t thread = 0; thread != singleton<stored_object_tab>::num_threads(); ++thread){
270  auto& stored_objects = singleton<stored_object_tab>::instance(thread);
271  dependent_deleted = stored_objects.del_dependent_(o1,o2);
272  if (dependent_deleted){
273  dependent_empty = stored_objects.has_dependent_objects(o2);
274  break;
275  }
276  }
277  GMM_ASSERT1(dependent_deleted, "Failed to delete dependent between " << o1 << " of type "
278  << typeid(*o1).name() << " and " << o2 << " of type "
279  << typeid(*o2).name() << ". ");
280 
281  return dependent_empty;
282  }
283 
284  void add_stored_object(pstatic_stored_object_key k, pstatic_stored_object o,
285  permanence perm) {
286  STORED_ASSERT(dal_static_stored_tab_valid__, "Too late to add an object");
287  auto& stored_objects = singleton<stored_object_tab>::instance();
288  stored_objects.add_stored_object(k,o,perm);
289  }
290 
291  void basic_delete(std::list<pstatic_stored_object> &to_delete){
292  auto& stored_objects_this_thread = singleton<stored_object_tab>::instance();
293 
294  ON_STORED_DEBUG(if (!dal_static_stored_tab_valid__) return)
295  stored_objects_this_thread.basic_delete_(to_delete);
296 
297  if (!to_delete.empty()){ //need to delete from other threads
298  for(size_t thread = 0; thread != singleton<stored_object_tab>::num_threads(); ++thread){
299  if (thread == singleton<stored_object_tab>::this_thread()) continue;
300  auto& stored_objects = singleton<stored_object_tab>::instance(thread);
301  stored_objects.basic_delete_(to_delete);
302  if (to_delete.empty()) break;
303  }
304  }
306  if (!to_delete.empty()) GMM_WARNING1("Not all objects were deleted");
307  }
308  else{GMM_ASSERT1(to_delete.empty(), "Could not delete objects");}
309  }
310 
311  void del_stored_objects(std::list<pstatic_stored_object> &to_delete,
312  bool ignore_unstored) {
313 
314  GLOBAL_OMP_GUARD
315 
316  ON_STORED_DEBUG(if (dal_static_stored_tab_valid__) return);
317 
318  std::list<pstatic_stored_object>::iterator it, itnext;
319  for (it = to_delete.begin(); it != to_delete.end(); it = itnext) {
320  itnext = it; itnext++;
321 
322  auto itos = iterators_of_object(*it);
323  if (itos.first == itos.second) {
324  if (ignore_unstored) to_delete.erase(it);
325  else if (getfem::me_is_multithreaded_now()) {
326  GMM_WARNING1("This object is (already?) not stored : "<< it->get()
327  << " typename: " << typeid(*it->get()).name()
328  << "(which could happen in multithreaded code and is OK)");
329  } else {
330  GMM_ASSERT1(false, "This object is not stored : " << it->get()
331  << " typename: " << typeid(*it->get()).name());
332  }
333  }
334  else itos.first->second.valid = false;
335  }
336 
337  for (auto &&pobj : to_delete) {
338  if (pobj) {
339  auto itos = iterators_of_object(pobj);
340  GMM_ASSERT1(itos.first != itos.second, "An object disapeared !");
341  itos.first->second.valid = false;
342  auto second_dep = itos.first->second.dependencies;
343  for (const auto &pdep : second_dep) {
344  if (del_dependency(pobj, pdep)) {
345  auto itods = iterators_of_object(pdep);
346  if (itods.first->second.perm == AUTODELETE_STATIC_OBJECT
347  && itods.first->second.valid) {
348  itods.first->second.valid = false;
349  to_delete.push_back(pdep);
350  }
351  }
352  }
353  for (auto &&pdep : itos.first->second.dependent_object) {
354  auto itods = iterators_of_object(pdep);
355  if (itods.first != itods.second) {
356  GMM_ASSERT1(itods.first->second.perm != PERMANENT_STATIC_OBJECT,
357  "Trying to delete a permanent object " << pdep);
358  if (itods.first->second.valid) {
359  itods.first->second.valid = false;
360  to_delete.push_back(itods.first->second.p);
361  }
362  }
363  }
364  }
365  }
366  basic_delete(to_delete);
367  }
368 
369  void del_stored_object(const pstatic_stored_object &o, bool ignore_unstored){
370  std::list<pstatic_stored_object> to_delete;
371  to_delete.push_back(o);
372  del_stored_objects(to_delete, ignore_unstored);
373  }
374 
375 
376  void del_stored_objects(permanence perm){
377  std::list<pstatic_stored_object> to_delete;
378  for(size_t thread = 0; thread != singleton<stored_object_tab>::num_threads(); ++thread){
379  auto& stored_objects = singleton<stored_object_tab>::instance(thread);
380  ON_STORED_DEBUG(if (!dal_static_stored_tab_valid__) continue;)
381  if (perm == PERMANENT_STATIC_OBJECT) perm = STRONG_STATIC_OBJECT;
382  for (auto &&pair : stored_objects){
383  if (pair.second.perm >= perm) to_delete.push_back(pair.second.p);
384  }
385  }
386  del_stored_objects(to_delete, false);
387  }
388 
389  void list_stored_objects(std::ostream &ost){
390  for(size_t thread = 0; thread != singleton<stored_object_tab>::num_threads(); ++thread){
391  auto& stored_keys = singleton<stored_object_tab>::instance(thread).stored_keys_;
392  ON_STORED_DEBUG(if (!dal_static_stored_tab_valid__) continue;)
393  if (stored_keys.begin() == stored_keys.end())
394  ost << "No static stored objects" << endl;
395  else ost << "Static stored objects" << endl;
396  for (const auto &t : stored_keys)
397  ost << "Object: " << t.first << " typename: "
398  << typeid(*(t.first)).name() << endl;
399  }
400  }
401 
402  size_t nb_stored_objects(void){
403  long num_objects = 0;
404  for(size_t thread = 0; thread != singleton<stored_object_tab>::num_threads(); ++thread){
405  auto& stored_keys = singleton<stored_object_tab>::instance(thread).stored_keys_;
406  ON_STORED_DEBUG(if (!dal_static_stored_tab_valid__) continue;)
407  num_objects += stored_keys.size();
408  }
409  return num_objects;
410  }
411 
412 /**
413  STATIC_STORED_TAB -------------------------------------------------------
414 */
417  locks_{}, stored_keys_{}{
418  ON_STORED_DEBUG(dal_static_stored_tab_valid__ = true;)
419  }
420 
421  stored_object_tab::~stored_object_tab(){
422  ON_STORED_DEBUG(dal_static_stored_tab_valid__ = false;)
423  }
424 
425  pstatic_stored_object
426  stored_object_tab::search_stored_object(pstatic_stored_object_key k) const{
427  auto guard = locks_.get_lock();
428  auto it = find(enr_static_stored_object_key(k));
429  return (it != end()) ? it->second.p : nullptr;
430  }
431 
432  bool stored_object_tab::add_dependency_(pstatic_stored_object o1,
433  pstatic_stored_object o2){
434  auto guard = locks_.get_lock();
435  auto it = stored_keys_.find(o1);
436  if (it == stored_keys_.end()) return false;
437  auto ito1 = find(it->second);
438  GMM_ASSERT1(ito1 != end(), "Object has a key, but cannot be found");
439  ito1->second.dependencies.insert(o2);
440  return true;
441  }
442 
443  void stored_object_tab::add_stored_object(pstatic_stored_object_key k,
444  pstatic_stored_object o, permanence perm){
445  DAL_STORED_OBJECT_DEBUG_ADDED(o.get());
446  auto guard = locks_.get_lock();
447  GMM_ASSERT1(stored_keys_.find(o) == stored_keys_.end(),
448  "This object has already been stored, possibly with another key");
449  stored_keys_[o] = k;
450  insert(std::make_pair(enr_static_stored_object_key(k),
451  enr_static_stored_object(o, perm)));
453  GMM_ASSERT2(stored_keys_.size() == size() && t != size_t(-1),
454  "stored_keys are not consistent with stored_object tab");
455  }
456 
457  bool stored_object_tab::add_dependent_(pstatic_stored_object o1,
458  pstatic_stored_object o2){
459  auto guard = locks_.get_lock();
460  auto it = stored_keys_.find(o2);
461  if (it == stored_keys_.end()) return false;
462  auto ito2 = find(it->second);
463  GMM_ASSERT1(ito2 != end(), "Object has a key, but cannot be found");
464  ito2->second.dependent_object.insert(o1);
465  return true;
466  }
467 
468  bool stored_object_tab::del_dependency_(pstatic_stored_object o1,
469  pstatic_stored_object o2){
470  auto guard = locks_.get_lock();
471  auto it1 = stored_keys_.find(o1);
472  if (it1 == stored_keys_.end()) return false;
473  auto ito1 = find(it1->second);
474  GMM_ASSERT1(ito1 != end(), "Object has a key, but cannot be found");
475  ito1->second.dependencies.erase(o2);
476  return true;
477  }
478 
479  stored_object_tab::iterator stored_object_tab
480  ::iterator_of_object_(pstatic_stored_object o){
481  auto itk = stored_keys_.find(o);
482  if (itk == stored_keys_.end()) return end();
483  auto ito = find(itk->second);
484  GMM_ASSERT1(ito != end(), "Object has a key, but is not stored");
485  return ito;
486  }
487 
488  bool stored_object_tab::del_dependent_(pstatic_stored_object o1,
489  pstatic_stored_object o2){
490  auto guard = locks_.get_lock();
491  auto it2 = stored_keys_.find(o2);
492  if (it2 == stored_keys_.end()) return false;
493  auto ito2 = find(it2->second);
494  GMM_ASSERT1(ito2 != end(), "Object has a key, but cannot be found");
495  ito2->second.dependent_object.erase(o1);
496  return true;
497  }
498 
499  bool stored_object_tab::exists_stored_object(pstatic_stored_object o) const{
500  auto guard = locks_.get_lock();
501  return (stored_keys_.find(o) != stored_keys_.end());
502  }
503 
504  bool stored_object_tab::has_dependent_objects(pstatic_stored_object o) const{
505  auto guard = locks_.get_lock();
506  auto it = stored_keys_.find(o);
507  GMM_ASSERT1(it != stored_keys_.end(), "Object is not stored");
508  auto ito = find(it->second);
509  GMM_ASSERT1(ito != end(), "Object has a key, but cannot be found");
510  return ito->second.dependent_object.empty();
511  }
512 
513  void stored_object_tab::basic_delete_(std::list<pstatic_stored_object> &to_delete){
514  auto guard = locks_.get_lock();
515  for (auto it = to_delete.begin(); it != to_delete.end();){
516  DAL_STORED_OBJECT_DEBUG_DELETED(it->get());
517  auto itk = stored_keys_.find(*it);
518  auto ito = end();
519  if (itk != stored_keys_.end()){
520  ito = find(itk->second);
521  stored_keys_.erase(itk);
522  }
523  if (ito != end()){
524  erase(ito);
525  it = to_delete.erase(it);
526  } else ++it;
527  }
528  }
529 
530 }/* end of namespace dal */
dal::singleton::instance
static T & instance()
Instance from the current thread.
Definition: dal_singleton.h:165
getfem::me_is_multithreaded_now
bool me_is_multithreaded_now()
is the program running in the parallel section
Definition: getfem_omp.cc:106
dal::enr_static_stored_object_key
Pointer to a key with a coherent order.
Definition: dal_static_stored_objects.h:310
dal::singleton::this_thread
static size_type this_thread()
this thread number according to the threading policy of the singleton
Definition: dal_singleton.h:187
dal_singleton.h
A simple singleton implementation.
dal
Dynamic Array Library.
Definition: dal_backtrace.cc:29
dal::del_stored_object
void del_stored_object(const pstatic_stored_object &o, bool ignore_unstored)
Delete an object and the object which depend on it.
Definition: dal_static_stored_objects.cc:369
dal::del_dependency
bool del_dependency(pstatic_stored_object o1, pstatic_stored_object o2)
remove a dependency.
Definition: dal_static_stored_objects.cc:256
dal::singleton::num_threads
static size_type num_threads()
number of threads this singleton is distributed on.
Definition: dal_singleton.h:182
dal::enr_static_stored_object
Pointer to an object with the dependencies.
Definition: dal_static_stored_objects.h:292
dal::stored_object_tab::stored_object_tab
stored_object_tab()
STATIC_STORED_TAB ----------------------------------------------------—.
Definition: dal_static_stored_objects.cc:415
dal::search_stored_object
pstatic_stored_object search_stored_object(pstatic_stored_object_key k)
Gives a pointer to an object from a key pointer.
Definition: dal_static_stored_objects.cc:177
dal::nb_stored_objects
size_t nb_stored_objects(void)
Return the number of stored objects (for debugging purpose).
Definition: dal_static_stored_objects.cc:402
dal::list_stored_objects
void list_stored_objects(std::ostream &ost)
Show a list of stored objects (for debugging purpose).
Definition: dal_static_stored_objects.cc:389
dal_static_stored_objects.h
Stores interdependent getfem objects.
dal::exists_stored_object
bool exists_stored_object(pstatic_stored_object o)
Test if an object is stored.
Definition: dal_static_stored_objects.cc:171
dal::add_stored_object
void add_stored_object(pstatic_stored_object_key k, pstatic_stored_object o, permanence perm)
Add an object with two optional dependencies.
Definition: dal_static_stored_objects.cc:284
dal::del_stored_objects
void del_stored_objects(std::list< pstatic_stored_object > &to_delete, bool ignore_unstored)
Delete a list of objects and their dependencies.
Definition: dal_static_stored_objects.cc:311
dal::test_stored_objects
void test_stored_objects(void)
Test the validity of the whole global storage.
Definition: dal_static_stored_objects.cc:211
dal::add_dependency
void add_dependency(pstatic_stored_object o1, pstatic_stored_object o2)
Add a dependency, object o1 will depend on object o2.
Definition: dal_static_stored_objects.cc:230