profiler  0.0
WeakSingleton.h
1 #ifndef PROFILER_SRC_MOLPRO_PROFILER_TREE_SINGLE_H
2 #define PROFILER_SRC_MOLPRO_PROFILER_TREE_SINGLE_H
3 
4 #include "Profiler.h"
5 
6 #include <algorithm>
7 #include <cassert>
8 #include <list>
9 #include <memory>
10 #include <string>
11 #include <mutex>
12 
13 namespace molpro {
14 namespace profiler {
15 
16 // FIXME improve description
20 template <class Object>
21 struct WeakSingleton {
22 
23  using key_t = std::tuple<std::string, std::weak_ptr<Object>, Object*>;
24 
29  template <typename... T>
30  static std::shared_ptr<Object> single(const std::string& key, T&&... constructor_args) {
31  std::lock_guard<decltype(WeakSingleton::s_reg_lock)> lock(s_reg_lock);
32  std::shared_ptr<Object> result = nullptr;
33  auto& reg = registry();
34  auto it = std::find_if(begin(reg), end(reg), [&key](const key_t& el) { return std::get<0>(el) == key; });
35  if (it != reg.end())
36  result = std::get<1>(*it).lock();
37  if (!result) {
38  result = std::make_shared<Object>(std::forward<T>(constructor_args)...);
39  reg.emplace_back(key_t{key, result, result.get()});
40  }
41  return result;
42  }
43 
45  static std::shared_ptr<Object> single() {
46  std::lock_guard<decltype(WeakSingleton::s_reg_lock)> lock(s_reg_lock);
47  auto& reg = registry();
48  std::shared_ptr<Object> instance = reg.empty() ? nullptr : std::get<1>(reg.back()).lock();
49  if (not instance) { // default zero-depth instance
50  auto result = Profiler::single("default");
51  result->set_max_depth(0);
52  // It is our job to keep the default instance alive by always retaining a shared_ptr
53  // to it. This way, callers don't have to manage the default instance's lifetime.
54  default_instance_saver() = result;
55  return result;
56  }
57  return instance;
58  }
59 
61  static void erase(Object* obj) {
62  std::lock_guard<decltype(WeakSingleton::s_reg_lock)> lock(s_reg_lock);
63  auto& reg = registry();
64  auto it = std::find_if(begin(reg), end(reg), [obj](const key_t& el) { return std::get<2>(el) == obj; });
65  if (it != reg.end())
66  reg.erase(it);
67  }
68 
70  static void erase(const std::string& key) {
71  std::lock_guard<decltype(WeakSingleton::s_reg_lock)> lock(s_reg_lock);
72  auto& reg = registry();
73  auto it = std::find_if(begin(reg), end(reg), [&key](const key_t& el) { return std::get<0>(el) == key; });
74  if (it != reg.end())
75  reg.erase(it);
76  }
77 
79  static void clear() {
80  std::lock_guard<decltype(WeakSingleton::s_reg_lock)> lock(s_reg_lock);
81  registry().clear();
82  }
83 
84 private:
85  static std::recursive_mutex s_reg_lock;
86 
89  static std::list<key_t>& registry() {
90  static std::list<key_t> reg;
91  return reg;
92  }
93 
95  static std::shared_ptr<Object>& default_instance_saver() {
96  static std::shared_ptr<Object> saver;
97  return saver;
98  }
99 };
100 
101 template <class Object>
102 std::recursive_mutex WeakSingleton<Object>::s_reg_lock;
103 
104 
105 } // namespace profiler
106 } // namespace molpro
107 #endif // PROFILER_SRC_MOLPRO_PROFILER_TREE_SINGLE_H
static std::shared_ptr< Profiler > single()
Access the last registered Profiler.
Definition: Profiler.cpp:27
Definition: Profiler.h:5
Implements the mechanism for the weak singleton pattern.
Definition: WeakSingleton.h:21
static void erase(Object *obj)
Remove object from the register. This should be called in the destructor of class that exposes this p...
Definition: WeakSingleton.h:61
static void erase(const std::string &key)
Remove object registered under the name key.
Definition: WeakSingleton.h:70
std::tuple< std::string, std::weak_ptr< Object >, Object * > key_t
Definition: WeakSingleton.h:23
static std::shared_ptr< Object > single(const std::string &key, T &&... constructor_args)
Creates an instance of Object or returns an already registered instance.
Definition: WeakSingleton.h:30
static void clear()
Remove all registered objects.
Definition: WeakSingleton.h:79
static std::shared_ptr< Object > single()
Access the last registered object.
Definition: WeakSingleton.h:45