GCC Code Coverage Report


Directory: ./
File: include/na64util/observer.hh
Date: 2025-09-01 06:19:01
Exec Total Coverage
Lines: 20 25 80.0%
Functions: 19 24 79.2%
Branches: 7 8 87.5%

Line Branch Exec Source
1 #pragma once
2
3 #include "na64util/str-fmt.hh"
4 #include "na64util/observer.hh"
5 #include "na64util/pair-hash.hh"
6
7 #include <unordered_map>
8 #include <unordered_set>
9 #include <typeindex>
10
11 namespace na64dp {
12
13 namespace error {
14 /// Exception thrown if type of an observable value does not correspond to any
15 /// observable in obserbles set
16 class UnknownObservableType : public std::runtime_error {
17 private:
18 const std::type_info & _typeInfo;
19 public:
20 3 UnknownObservableType( const std::type_info & ti ) throw()
21 3 : std::runtime_error(
22 6 util::format( "No observable of type \"%s\" in set."
23 , ti.name() ).c_str()
24 )
25 6 , _typeInfo(ti) {}
26 const std::type_info & type_info() const throw() { return _typeInfo; }
27 };
28
29 /// Exception thrown on double association attempt
30 class DuplicatingObservableType : public std::runtime_error {
31 private:
32 const std::type_info & _typeInfo;
33 public:
34 DuplicatingObservableType( const std::type_info & ti ) throw()
35 : std::runtime_error(
36 util::format( "Observable of type \"%s\" exists in set."
37 , ti.name() ).c_str()
38 )
39 , _typeInfo(ti) {}
40 const std::type_info & type_info() const throw() { return _typeInfo; }
41 };
42 }
43
44 namespace util {
45
46 /// Template implementation of observer pattern for certain type of messages
47 template<typename T>
48 class Observable {
49 public:
50 /// Observer (subscriber) interface
51 struct iObserver {
52 virtual void handle_update( const T & ) = 0;
53 };
54 private:
55 /// A set of observers to be notified on change
56 std::unordered_set<iObserver *> _observers;
57 public:
58 /// Injects dependance (binds observer)
59 35 virtual bool bind_observer( iObserver & dep )
60
1/1
✓ Branch 1 taken 23 times.
35 { return _observers.insert(&dep).second; }
61 /// Removes dependence (unbinds observer)
62 27 virtual void unbind_observer( iObserver & dep )
63
1/1
✓ Branch 1 taken 19 times.
27 { _observers.erase(&dep); }
64 /// Notifies all the observers
65 23 virtual void notify_observers( const T & d )
66
3/3
✓ Branch 4 taken 11 times.
✓ Branch 8 taken 11 times.
✓ Branch 9 taken 12 times.
43 { for( auto p : _observers ) p->handle_update( d ); }
67 /// Returns number of bound observers
68 25 virtual size_t n_observers() const { return _observers.size(); }
69 };
70
71 /** Implements a set of observable values indexed by their type (RTTI used)
72 *
73 * The idea is to dynamically dispatch changes among observers for certain
74 * type. No additional filtration is provided at this level.
75 */
76 class Observables {
77 public:
78 struct CommonObservable {};
79 template<typename T> struct ConcreteObservable : public CommonObservable
80 , public Observable<T> {};
81 protected:
82 /// Indexes observables by their `std::type_index`
83 std::unordered_map<std::type_index, CommonObservable *> _observables;
84 public:
85 /// Adds new observable instance to set
86 template<typename T> void
87 4 add_observable( ConcreteObservable<T> & observable ) {
88
1/1
✓ Branch 2 taken 2 times.
4 auto ir = _observables.emplace( std::type_index(typeid(T)), &observable );
89
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
4 if( ! ir.second ) {
90 throw error::DuplicatingObservableType( typeid(T) );
91 }
92 4 }
93
94 /// Returns observable instance reference when parameterized by type of the
95 /// observable variable
96 template<typename T> ConcreteObservable<T> &
97 7 get_observable() {
98 7 auto it = _observables.find( std::type_index(typeid(T)) );
99 7 if( _observables.end() == it ) {
100 3 throw error::UnknownObservableType( typeid(T) );
101 }
102 8 return static_cast<ConcreteObservable<T> &>(*(it->second));
103 }
104 };
105
106 }
107 }
108
109