1 //
2 // Copyright 2016 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // signal_utils:
7 // Helper classes for tracking dependent state changes between objects.
8 // These changes are signaled to the dependent class via channels.
9 // See design document:
10 // https://docs.google.com/document/d/15Edfotqg6_l1skTEL8ADQudF_oIdNa7i8Po43k6jMd4/
11
12 #ifndef LIBANGLE_SIGNAL_UTILS_H_
13 #define LIBANGLE_SIGNAL_UTILS_H_
14
15 #include <set>
16
17 #include "common/angleutils.h"
18 #include "common/debug.h"
19
20 namespace angle
21 {
22
23 // Interface that the depending class inherits from.
24 template <typename ChannelID = uint32_t, typename... MessageT>
25 class SignalReceiver
26 {
27 public:
28 virtual ~SignalReceiver() = default;
29 virtual void signal(ChannelID channelID, MessageT... message) = 0;
30 };
31
32 template <typename ChannelID, typename... MessageT>
33 class ChannelBinding;
34
35 // The host class owns the channel. It uses the channel to fire signals to the receiver.
36 template <typename ChannelID = uint32_t, typename... MessageT>
37 class BroadcastChannel final : NonCopyable
38 {
39 public:
40 BroadcastChannel();
41 ~BroadcastChannel();
42
43 void signal(MessageT... message) const;
44
45 void reset();
46
47 bool empty() const;
48
49 private:
50 // Only the ChannelBinding class should add or remove receivers.
51 friend class ChannelBinding<ChannelID, MessageT...>;
52 void addReceiver(ChannelBinding<ChannelID, MessageT...> *receiver);
53 void removeReceiver(ChannelBinding<ChannelID, MessageT...> *receiver);
54
55 std::vector<ChannelBinding<ChannelID, MessageT...> *> mReceivers;
56 };
57
58 template <typename ChannelID, typename... MessageT>
BroadcastChannel()59 BroadcastChannel<ChannelID, MessageT...>::BroadcastChannel()
60 {
61 }
62
63 template <typename ChannelID, typename... MessageT>
~BroadcastChannel()64 BroadcastChannel<ChannelID, MessageT...>::~BroadcastChannel()
65 {
66 reset();
67 }
68
69 template <typename ChannelID, typename... MessageT>
addReceiver(ChannelBinding<ChannelID,MessageT...> * receiver)70 void BroadcastChannel<ChannelID, MessageT...>::addReceiver(
71 ChannelBinding<ChannelID, MessageT...> *receiver)
72 {
73 ASSERT(std::find(mReceivers.begin(), mReceivers.end(), receiver) == mReceivers.end());
74 mReceivers.push_back(receiver);
75 }
76
77 template <typename ChannelID, typename... MessageT>
removeReceiver(ChannelBinding<ChannelID,MessageT...> * receiver)78 void BroadcastChannel<ChannelID, MessageT...>::removeReceiver(
79 ChannelBinding<ChannelID, MessageT...> *receiver)
80 {
81 auto iter = std::find(mReceivers.begin(), mReceivers.end(), receiver);
82 ASSERT(iter != mReceivers.end());
83 mReceivers.erase(iter);
84 }
85
86 template <typename ChannelID, typename... MessageT>
signal(MessageT...message)87 void BroadcastChannel<ChannelID, MessageT...>::signal(MessageT... message) const
88 {
89 if (mReceivers.empty())
90 return;
91
92 for (const auto *receiver : mReceivers)
93 {
94 receiver->signal(message...);
95 }
96 }
97
98 template <typename ChannelID, typename... MessageT>
reset()99 void BroadcastChannel<ChannelID, MessageT...>::reset()
100 {
101 for (auto receiver : mReceivers)
102 {
103 receiver->onChannelClosed();
104 }
105 mReceivers.clear();
106 }
107
108 template <typename ChannelID, typename... MessageT>
empty()109 bool BroadcastChannel<ChannelID, MessageT...>::empty() const
110 {
111 return mReceivers.empty();
112 }
113
114 // The dependent class keeps bindings to the host's BroadcastChannel.
115 template <typename ChannelID = uint32_t, typename... MessageT>
116 class ChannelBinding final
117 {
118 public:
119 ChannelBinding(SignalReceiver<ChannelID, MessageT...> *receiver, ChannelID channelID);
120 ~ChannelBinding();
121 ChannelBinding(const ChannelBinding &other) = default;
122 ChannelBinding &operator=(const ChannelBinding &other) = default;
123
124 void bind(BroadcastChannel<ChannelID, MessageT...> *channel);
125 void reset();
126 void signal(MessageT... message) const;
127 void onChannelClosed();
128
129 private:
130 BroadcastChannel<ChannelID, MessageT...> *mChannel;
131 SignalReceiver<ChannelID, MessageT...> *mReceiver;
132 ChannelID mChannelID;
133 };
134
135 template <typename ChannelID, typename... MessageT>
ChannelBinding(SignalReceiver<ChannelID,MessageT...> * receiver,ChannelID channelID)136 ChannelBinding<ChannelID, MessageT...>::ChannelBinding(
137 SignalReceiver<ChannelID, MessageT...> *receiver,
138 ChannelID channelID)
139 : mChannel(nullptr), mReceiver(receiver), mChannelID(channelID)
140 {
141 ASSERT(receiver);
142 }
143
144 template <typename ChannelID, typename... MessageT>
~ChannelBinding()145 ChannelBinding<ChannelID, MessageT...>::~ChannelBinding()
146 {
147 reset();
148 }
149
150 template <typename ChannelID, typename... MessageT>
bind(BroadcastChannel<ChannelID,MessageT...> * channel)151 void ChannelBinding<ChannelID, MessageT...>::bind(BroadcastChannel<ChannelID, MessageT...> *channel)
152 {
153 ASSERT(mReceiver);
154 if (mChannel)
155 {
156 mChannel->removeReceiver(this);
157 }
158
159 mChannel = channel;
160
161 if (mChannel)
162 {
163 mChannel->addReceiver(this);
164 }
165 }
166
167 template <typename ChannelID, typename... MessageT>
reset()168 void ChannelBinding<ChannelID, MessageT...>::reset()
169 {
170 bind(nullptr);
171 }
172
173 template <typename ChannelID, typename... MessageT>
signal(MessageT...message)174 void ChannelBinding<ChannelID, MessageT...>::signal(MessageT... message) const
175 {
176 mReceiver->signal(mChannelID, message...);
177 }
178
179 template <typename ChannelID, typename... MessageT>
onChannelClosed()180 void ChannelBinding<ChannelID, MessageT...>::onChannelClosed()
181 {
182 mChannel = nullptr;
183 }
184
185 } // namespace angle
186
187 #endif // LIBANGLE_SIGNAL_UTILS_H_
188