OSSIA
Open Scenario System for Interactive Application
callback_container.hpp
Go to the documentation of this file.
1 #pragma once
2 #include <ossia/detail/config.hpp>
3 
4 #include <ossia/detail/mutex.hpp>
5 
6 #if defined(__cpp_exceptions)
7 #include <exception>
8 #endif
9 #include <list>
10 #include <mutex>
11 
16 namespace ossia
17 {
18 
19 #if defined(__cpp_exceptions)
25 struct OSSIA_EXPORT invalid_callback_error final : public std::exception
26 {
27  ~invalid_callback_error() override;
28  invalid_callback_error();
29  const char* what() const noexcept override;
30 };
31 #endif
32 
33 template <typename T>
46 {
47  using mutex = OSSIA_CALLBACK_CONTAINER_MUTEX;
48  using lock_guard = std::lock_guard<mutex>;
49 
50 public:
51  callback_container() = default;
53  {
54  lock_guard lck{other.m_mutx};
55  m_callbacks = other.m_callbacks;
56  }
57  callback_container(callback_container&& other) noexcept
58  {
59  lock_guard lck{other.m_mutx};
60  m_callbacks = std::move(other.m_callbacks);
61  }
62  callback_container& operator=(const callback_container& other)
63  {
64  lock_guard lck{other.m_mutx};
65  m_callbacks = other.m_callbacks;
66  return *this;
67  }
68  callback_container& operator=(callback_container&& other) noexcept
69  {
70  lock_guard lck{other.m_mutx};
71  m_callbacks = std::move(other.m_callbacks);
72  return *this;
73  }
74 
75  virtual ~callback_container() = default;
76 
82  using impl = std::list<T>;
83  using iterator = typename impl::iterator;
84 
90  iterator add_callback(T&& callback)
91  {
92  if(callback)
93  {
94  lock_guard lck{m_mutx};
95  auto it = m_callbacks.insert(m_callbacks.begin(), std::move(callback));
96  if(m_callbacks.size() == 1)
97  on_first_callback_added();
98  return it;
99  }
100  else
101  {
102 #if defined(__cpp_exceptions)
103  throw invalid_callback_error{};
104 #else
105  return {};
106 #endif
107  }
108  }
109 
114  void remove_callback(iterator it)
115  {
116  lock_guard lck{m_mutx};
117  if(m_callbacks.size() == 1)
118  on_removing_last_callback();
119 
120  m_callbacks.erase(it);
121  }
122 
126  void replace_callback(iterator it, T&& cb)
127  {
128  lock_guard lck{m_mutx};
129  *m_callbacks.erase(it, it) = std::move(cb);
130  }
131 
132  void replace_callbacks(impl&& cbs)
133  {
134  lock_guard lck{m_mutx};
135  m_callbacks = std::move(cbs);
136  }
137 
138  class disabled_callback
139  {
140  public:
141  explicit disabled_callback(callback_container& self)
142  : self{self}
143  , old_callbacks{self.m_callbacks}
144  {
145  }
146 
147  ~disabled_callback() { self.replace_callbacks(std::move(old_callbacks)); }
148 
149  private:
150  callback_container& self;
151  callback_container::impl old_callbacks;
152  };
153 
154  disabled_callback disable_callback(iterator it)
155  {
156  lock_guard lck{m_mutx};
157  disabled_callback dis{*this};
158 
159  // TODO should we also call on_removing_last_blah ?
160  // I don't think so : it's supposed to be a short operation
161  m_callbacks.erase(it);
162  return dis;
163  }
164 
169  std::size_t callback_count() const
170  {
171  lock_guard lck{m_mutx};
172  return m_callbacks.size();
173  }
174 
179  bool callbacks_empty() const
180  {
181  lock_guard lck{m_mutx};
182  return m_callbacks.empty();
183  }
184 
189  template <typename... Args>
190  void send(Args&&... args)
191  {
192  lock_guard lck{m_mutx};
193  for(auto& callback : m_callbacks)
194  {
195  if(callback)
196  callback(std::forward<Args>(args)...);
197  }
198  }
199 
204  {
205  lock_guard lck{m_mutx};
206  if(!m_callbacks.empty())
207  on_removing_last_callback();
208  m_callbacks.clear();
209  }
210 
211 protected:
222  virtual void on_first_callback_added() { }
223 
229  virtual void on_removing_last_callback() { }
230 
231  //private:
232 public:
233  impl m_callbacks TS_GUARDED_BY(m_mutx);
234  mutable mutex m_mutx;
235 };
236 
237 }
The callback_container class.
Definition: callback_container.hpp:46
void callbacks_clear()
clear Clears callbacks.
Definition: callback_container.hpp:203
virtual void on_removing_last_callback()
on_removing_last_callback
Definition: callback_container.hpp:229
bool callbacks_empty() const
callbacks_empty
Definition: callback_container.hpp:179
void replace_callback(iterator it, T &&cb)
Replaces an existing callback with another function.
Definition: callback_container.hpp:126
std::list< T > impl
impl How the callbackas are stored. A list is used since iterators to other callbacks must not be inv...
Definition: callback_container.hpp:82
virtual void on_first_callback_added()
on_first_callback_added
Definition: callback_container.hpp:222
std::size_t callback_count() const
callback_count
Definition: callback_container.hpp:169
void remove_callback(iterator it)
remove_callback Removes a callback identified by an iterator.
Definition: callback_container.hpp:114
iterator add_callback(T &&callback)
add_callback Add a new callback.
Definition: callback_container.hpp:90
void send(Args &&... args)
send Trigger all callbacks
Definition: callback_container.hpp:190
Definition: git_info.h:7