client-cpp  0.6.1
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 
25 #include "kaa/KaaThread.hpp"
26 
27 namespace kaa {
28 
29 template<class Signature, class Key, class Function = std::function<Signature>>
31 {
32 public:
33  KaaObservable() : isNotifying_(false) { }
35 
36  bool addCallback(const Key& key, const Function& f)
37  {
38  if (isNotifying_) {
39  KAA_MUTEX_UNIQUE_DECLARE(lock, modificationGuard_);
40  auto it = slots_.find(key);
41  if (it != slots_.end() && !it->second.isRemoved()) {
42  return false;
43  }
44  slotsToRemove_.erase(key);
45  slotsToAdd_.insert(std::make_pair(key, CallbackWrapper(f)));
46  return true;
47  } else {
48  KAA_MUTEX_UNIQUE_DECLARE(lock, mainGuard_);
49  return slots_.insert(std::make_pair(key, CallbackWrapper(f))).second;
50  }
51  }
52 
53  void removeCallback(const Key& key)
54  {
55  if (isNotifying_) {
56  KAA_MUTEX_UNIQUE_DECLARE(lock, modificationGuard_);
57  slotsToAdd_.erase(key);
58  slotsToRemove_.insert(key);
59 
60  auto it = slots_.find(key);
61  if (it != slots_.end()) {
62  it->second.remove();
63  }
64  } else {
65  KAA_MUTEX_UNIQUE_DECLARE(lock, mainGuard_);
66  slots_.erase(key);
67  }
68  }
69 
70  template <typename... Args>
71  void operator()(Args&... args)
72  {
73  isNotifying_ = true;
74  KAA_MUTEX_UNIQUE_DECLARE(lock, mainGuard_);
75  for (auto& pair : slots_) {
76  pair.second(args...);
77  }
78  isNotifying_ = false;
79  KAA_MUTEX_UNIQUE_DECLARE(modLock, modificationGuard_);
80 
81  for (auto it = slotsToAdd_.begin(); it != slotsToAdd_.end(); ++it) {
82  slots_[it->first] = it->second;
83  }
84  slotsToAdd_.clear();
85 
86  for (auto key : slotsToRemove_) {
87  slots_.erase(key);
88  }
89  slotsToRemove_.clear();
90  }
91 
92 private:
93  class CallbackWrapper
94  {
95  public:
96  CallbackWrapper() : isRemoved_(false) { }
97  CallbackWrapper(const Function& f) : callback_(f), isRemoved_(false) { }
98  CallbackWrapper(const CallbackWrapper& o) : callback_(o.callback_), isRemoved_((bool) o.isRemoved_) { }
99  CallbackWrapper& operator=(const CallbackWrapper& o) { callback_ = o.callback_; isRemoved_ = (bool) o.isRemoved_; return *this; }
100 
101  template <typename... Args>
102  void operator()(Args&... args)
103  {
104  if (!isRemoved_) {
105  callback_(args...);
106  }
107  }
108 
109  bool isRemoved() const { return isRemoved_; }
110  void remove() { isRemoved_ = true; }
111 
112  private:
113  Function callback_;
114  bool_type isRemoved_;
115  };
116 
117  std::unordered_map<Key, CallbackWrapper> slots_;
118  std::unordered_map<Key, CallbackWrapper> slotsToAdd_;
119  std::unordered_set<Key> slotsToRemove_;
120 
121  bool_type isNotifying_;
122 
123  KAA_MUTEX_DECLARE(mainGuard_);
124  KAA_MUTEX_DECLARE(modificationGuard_);
125 };
126 
127 }
128 
129 
130 #endif /* KAA_OBSERVER_KAAOBSERVABLE_HPP_ */
void removeCallback(const Key &key)
#define KAA_MUTEX_UNIQUE_DECLARE(name, mtx)
Definition: KaaThread.hpp:75
void operator()(Args &...args)
bool bool_type
Definition: KaaThread.hpp:78
bool addCallback(const Key &key, const Function &f)