observable_object.h
Go to the documentation of this file.
1 
2 /*
3  * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License").
6  * You may not use this file except in compliance with the License.
7  * A copy of the License is located at
8  *
9  * http://aws.amazon.com/apache2.0
10  *
11  * or in the "license" file accompanying this file. This file is distributed
12  * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
13  * express or implied. See the License for the specific language governing
14  * permissions and limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <atomic>
20 #include <functional>
21 #include <iterator>
22 #include <list>
23 #include <memory>
24 #include <mutex>
25 
32 template<typename T>
33 class ObservableObject { // think about extending std::atomic
34 public:
39  // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
40  ObservableObject<T>(const T initialValue) {
41  value_.store(initialValue);
42  }
46  virtual ~ObservableObject<T>() {
48  }
53  virtual T getValue() {
54  return value_.load();
55  }
56 
61  virtual void setValue(const T &v) {
62 
63  // todo: we should set the value iff the value changed
64 
65  // todo validate value before storing
66  value_.store(v);
67  // todo if validated then broadcast
68  {
69  std::lock_guard<std::recursive_mutex> lk(listener_mutex_);
70  broadcastToListeners(v); // todo flag to broadcast on a new thread (if so desired)
71  }
72  }
79  virtual bool addListener(const std::function<void(const T&)> & listener) {
80  std::lock_guard<std::recursive_mutex> lk(listener_mutex_);
81 
82  try {
83  // provide the current value to the listener, don't wait for an event
84  listener(value_.load());
85  } catch(...) {
86  // something bad happened, remove the faulty listener
87  return false;
88  }
89  // the listener handled the new value without exception, add
90  listeners_.push_back(listener);
91  return true;
92  }
93 
97  void clearListeners() {
98  std::lock_guard<std::recursive_mutex> lk(listener_mutex_);
99  listeners_.clear();
100  }
101 
106  virtual size_t getNumberOfListeners() {
107  return listeners_.size();
108  }
109 
110 protected:
111 
118  virtual void broadcastToListeners(const T &currentValue) {
119  std::lock_guard<std::recursive_mutex> lk(listener_mutex_);
120 
121  for (auto i = listeners_.begin(); i != listeners_.end();) {
122  try {
123  auto callback = *i; // currently all listeners will block each other
124  callback(currentValue);
125  ++i;
126  } catch(...) {
127  // something bad happened, remove the faulty listener
128  i = listeners_.erase(i);
129  }
130  }
131  }
132 
133  // todo validate
134 
135 private:
136  std::recursive_mutex listener_mutex_;
137  std::atomic<T> value_;
138  std::list<std::function<void(T)>> listeners_;
139  // todo can have a list of validators
140 };
virtual bool addListener(const std::function< void(const T &)> &listener)
virtual size_t getNumberOfListeners()
virtual void setValue(const T &v)
std::list< std::function< void(T)> > listeners_
virtual void broadcastToListeners(const T &currentValue)
virtual T getValue()
std::recursive_mutex listener_mutex_
std::atomic< T > value_


dataflow_lite
Author(s): AWS RoboMaker
autogenerated on Fri May 7 2021 02:18:22