GCC Code Coverage Report


Directory: ./
File: pdcom5/include/pdcom5/Subscriber.h
Date: 2024-11-17 04:08:36
Exec Total Coverage
Lines: 8 8 100.0%
Branches: 0 0 -%

Line Branch Exec Source
1 /*****************************************************************************
2 *
3 * Copyright (C) 2021 Richard Hacker (lerichi at gmx dot net),
4 * Florian Pose (fp at igh dot de),
5 * Bjarne von Horn (vh at igh dot de).
6 *
7 * This file is part of the PdCom library.
8 *
9 * The PdCom library is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or (at your
12 * option) any later version.
13 *
14 * The PdCom library is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
17 * License for more .
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with the PdCom library. If not, see <http://www.gnu.org/licenses/>.
21 *
22 ****************************************************************************/
23
24 /** @file */
25
26 #ifndef PDCOM5_SUBSCRIBER_H
27 #define PDCOM5_SUBSCRIBER_H
28
29 #include <chrono>
30 #include <functional>
31 #include <pdcom5/Exception.h>
32 #include <pdcom5_export.h>
33
34 namespace PdCom {
35
36 namespace impl {
37 class Subscription;
38 }
39
40 class Subscription;
41
42 /// Tag for event-based subscription.
43 constexpr struct event_mode_tag
44 {
45 } event_mode;
46
47 /// Tag for poll-based subscription.
48 constexpr struct poll_mode_tag
49 {
50 } poll_mode;
51
52 /** Transmission mode for subscriptions.
53 *
54 * This class specifies whether a Subscriber should get new values
55 * periodically, event-based or by polling only. Therefore, it is passed to
56 * the Subscribers' constructor. All Subscriptions registered with that
57 * subscriber will share the given transmission mode.
58 */
59 class PDCOM5_PUBLIC Transmission
60 {
61 double interval_;
62
63 static constexpr double checkInterval(double d)
64 {
65 return d <= 0 ? throw PdCom::InvalidArgument(
66 "period must be greater than zero")
67 : d;
68 }
69
70 public:
71 300 constexpr double getInterval() const noexcept { return interval_; }
72 template <typename T, typename R>
73 constexpr Transmission(std::chrono::duration<T, R> d) :
74 interval_(checkInterval(
75 std::chrono::duration_cast<std::chrono::duration<double>>(d)
76 .count()))
77 {}
78 165 constexpr Transmission(event_mode_tag) noexcept : interval_(0) {}
79 84 constexpr Transmission(poll_mode_tag) noexcept : interval_(-1) {}
80 245 bool operator==(const Transmission &o) const noexcept
81 {
82 245 return o.interval_ == interval_;
83 }
84
85 static constexpr Transmission fromDouble(double d)
86 {
87 return d == 0
88 ? Transmission(event_mode)
89 : (d == -1 ? Transmission(poll_mode)
90 : Transmission(std::chrono::duration<double>(d)));
91 }
92 };
93
94 /** Base class for receiving notifications.
95 *
96 * This class is in charge of passing notifications from the library to client
97 * code. Make sure that the subscriber outlives all assigned subscriptions.
98 * Otherwise use-after-free bugs will occur, so be careful.
99 *
100 * The Subscriber class is also used to group subscriptions with the same
101 * transmission mode. The newValues method is called everytime, after all
102 * active subscriptions got their values updated for one realtime cycle.
103 *
104 * \example advanced_example.cpp
105 */
106 class PDCOM5_PUBLIC Subscriber
107 {
108 Transmission td_;
109 friend class impl::Subscription;
110
111 public:
112 explicit Subscriber(const Transmission &td) noexcept : td_(td) {}
113 Subscriber(Subscriber const &) = delete;
114 Subscriber(Subscriber &&) = delete;
115 Subscriber &operator=(Subscriber const &) = delete;
116 Subscriber &operator=(Subscriber &&) = delete;
117
118 344 const Transmission &getTransmission() const noexcept { return td_; }
119
120 private:
121 /** Callback for an updated subscription state.
122 * @param subscription Subscription which was updated.
123 */
124 virtual void stateChanged(PdCom::Subscription const &subscription) = 0;
125
126 /** Callback for new values.
127 *
128 * The epoch of \p time_ns depends on the clock selected in pdserv.
129 *
130 * Called after all active subscriptions got their values updated for one
131 * realtime cycle.
132 *
133 * @param time_ns Time since epoch in nanoseconds.
134 */
135 virtual void newValues(std::chrono::nanoseconds time_ns) = 0;
136
137 protected:
138 ~Subscriber() = default;
139 };
140
141 } // namespace PdCom
142
143 namespace std {
144
145 /** Hash implementation for PdCom::Transmission.
146 *
147 * Allows to use PdCom::Transmission as a key in std::unordered_map.
148 */
149 template <>
150 struct hash<PdCom::Transmission>
151 {
152 156 size_t operator()(PdCom::Transmission t) const
153 noexcept(__cplusplus >= 201703L)
154 {
155 156 return std::hash<double>()(t.getInterval());
156 }
157 };
158
159 } // namespace std
160
161 #endif // PDCOM5_SUBSCRIBER_H
162