client-cpp  0.7.0
KaaObservable.hpp
Go to the documentation of this file.
1 /*
2  * Copyright 2014 CyberVision, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef KAA_OBSERVER_KAAOBSERVABLE_HPP_
18 #define KAA_OBSERVER_KAAOBSERVABLE_HPP_
19 
20 #include <functional>
21 #include <unordered_map>
22 #include <unordered_set>
23 #include <memory>
24 #include <utility>
25 
26 #include "kaa/KaaThread.hpp"
27 
28 namespace kaa {
29 
30 template<class Signature, class Key, class Function = std::function<Signature>>
32 {
33 public:
34  KaaObservable() : isNotifying_(false) { }
36 
37  bool addCallback(const Key& key, const Function& f)
38  {
39  if (isNotifying_) {
40  KAA_MUTEX_UNIQUE_DECLARE(lock, modificationGuard_);
41  auto it = slots_.find(key);
42  if (it != slots_.end() && !it->second.isRemoved()) {
43  return false;
44  }
45  slotsToRemove_.erase(key);
46  slotsToAdd_.insert(std::make_pair(key, CallbackWrapper(f)));
47  return true;
48  } else {
49  KAA_MUTEX_UNIQUE_DECLARE(lock, mainGuard_);
50  return slots_.insert(std::make_pair(key, CallbackWrapper(f))).second;
51  }
52  }
53 
54  void removeCallback(const Key& key)
55  {
56  if (isNotifying_) {
57  KAA_MUTEX_UNIQUE_DECLARE(lock, modificationGuard_);
58  slotsToAdd_.erase(key);
59  slotsToRemove_.insert(key);
60 
61  auto it = slots_.find(key);
62  if (it != slots_.end()) {
63  it->second.remove();
64  }
65  } else {
66  KAA_MUTEX_UNIQUE_DECLARE(lock, mainGuard_);
67  slots_.erase(key);
68  }
69  }
70 
71  template <typename... Args>
72  void operator()(Args&&... args)
73  {
74  isNotifying_ = true;
75  KAA_MUTEX_UNIQUE_DECLARE(lock, mainGuard_);
76  for (auto& pair : slots_) {
77  pair.second(std::forward<Args>(args)...);
78  }
79  isNotifying_ = false;
80  KAA_MUTEX_UNIQUE_DECLARE(modLock, modificationGuard_);
81 
82  for (auto it = slotsToAdd_.begin(); it != slotsToAdd_.end(); ++it) {
83  slots_[it->first] = it->second;
84  }
85  slotsToAdd_.clear();
86 
87  for (auto key : slotsToRemove_) {
88  slots_.erase(key);
89  }
90  slotsToRemove_.clear();
91  }
92 
93  bool isEmpty()
94  {
95  KAA_MUTEX_UNIQUE_DECLARE(lock, mainGuard_);
96  KAA_MUTEX_UNIQUE_DECLARE(modLock, modificationGuard_);
97  return slots_.empty() && slotsToAdd_.empty();
98  }
99 
100 private:
101  class CallbackWrapper
102  {
103  public:
104  CallbackWrapper() : isRemoved_(false) { }
105  CallbackWrapper(const Function& f) : callback_(f), isRemoved_(false) { }
106  CallbackWrapper(const CallbackWrapper& o) : callback_(o.callback_), isRemoved_((bool) o.isRemoved_) { }
107  CallbackWrapper(CallbackWrapper&& o) : callback_(std::move(o.callback_)), isRemoved_((bool) o.isRemoved_) { }
108  CallbackWrapper& operator=(const CallbackWrapper& o) { callback_ = o.callback_; isRemoved_ = (bool) o.isRemoved_; return *this; }
109  CallbackWrapper& operator=(CallbackWrapper&& o) { callback_ = std::move(o.callback_); isRemoved_ = (bool) o.isRemoved_; return *this; }
110 
111  template <typename... Args>
112  void operator()(Args&&... args)
113  {
114  if (!isRemoved_) {
115  callback_(std::forward<Args>(args)...);
116  }
117  }
118 
119  bool isRemoved() const { return isRemoved_; }
120  void remove() { isRemoved_ = true; }
121 
122  private:
123  Function callback_;
124  bool_type isRemoved_;
125  };
126 
127  std::unordered_map<Key, CallbackWrapper> slots_;
128  std::unordered_map<Key, CallbackWrapper> slotsToAdd_;
129  std::unordered_set<Key> slotsToRemove_;
130 
131  bool_type isNotifying_;
132 
133  KAA_MUTEX_DECLARE(mainGuard_);
134  KAA_MUTEX_DECLARE(modificationGuard_);
135 };
136 
137 }
138 
139 
140 #endif /* KAA_OBSERVER_KAAOBSERVABLE_HPP_ */
void operator()(Args &&...args)
void removeCallback(const Key &key)
#define KAA_MUTEX_UNIQUE_DECLARE(name, mtx)
Definition: KaaThread.hpp:78
bool bool_type
Definition: KaaThread.hpp:81
bool addCallback(const Key &key, const Function &f)