DSPatch v.11.4.1
Loading...
Searching...
No Matches
SignalBus.h
1/******************************************************************************
2DSPatch - The Refreshingly Simple C++ Dataflow Framework
3Copyright (c) 2024, Marcus Tomlinson
4
5BSD 2-Clause License
6
7Redistribution and use in source and binary forms, with or without
8modification, are permitted provided that the following conditions are met:
9
101. Redistributions of source code must retain the above copyright notice, this
11 list of conditions and the following disclaimer.
12
132. Redistributions in binary form must reproduce the above copyright notice,
14 this list of conditions and the following disclaimer in the documentation
15 and/or other materials provided with the distribution.
16
17THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
21FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27******************************************************************************/
28
29#pragma once
30
31#include "../fast_any/any.h"
32
33#include <vector>
34
35namespace DSPatch
36{
37
39
52class SignalBus final
53{
54public:
55 SignalBus( const SignalBus& ) = delete;
56 SignalBus& operator=( const SignalBus& ) = delete;
57
58 SignalBus();
60 ~SignalBus();
61
62 void SetSignalCount( int signalCount );
63 int GetSignalCount() const;
64
65 fast_any::any* GetSignal( int signalIndex );
66
67 bool HasValue( int signalIndex ) const;
68
69 template <typename ValueType>
70 ValueType* GetValue( int signalIndex ) const;
71
72 template <typename ValueType>
73 void SetValue( int signalIndex, const ValueType& newValue );
74
75 template <typename ValueType>
76 void MoveValue( int signalIndex, ValueType&& newValue );
77
78 void SetSignal( int toSignalIndex, const fast_any::any& fromSignal );
79 void MoveSignal( int toSignalIndex, fast_any::any& fromSignal );
80
81 void ClearValue( int signalIndex );
82 void ClearAllValues();
83
84 fast_any::type_info GetType( int signalIndex ) const;
85
86private:
87 std::vector<fast_any::any> _signals;
88};
89
90inline SignalBus::SignalBus() = default;
91
92inline SignalBus::SignalBus( SignalBus&& rhs )
93 : _signals( std::move( rhs._signals ) )
94{
95}
96
97inline SignalBus::~SignalBus() = default;
98
99inline void SignalBus::SetSignalCount( int signalCount )
100{
101 _signals.resize( signalCount );
102}
103
104inline int SignalBus::GetSignalCount() const
105{
106 return (int)_signals.size();
107}
108
109inline fast_any::any* SignalBus::GetSignal( int signalIndex )
110{
111 // You might be thinking: Why the raw pointer return here?
112
113 // This is for usability and performance reasons. Usability, because a pointer allows the user
114 // to manipulate the contained value externally. Performance, because returning a smart pointer
115 // means having to store the value as a smart pointer too - this adds yet another level of
116 // indirection to the value, as well as some reference counting overhead. These Get() and Set()
117 // methods are VERY frequently called, so doing as little as possible with the data here is best.
118
119 return &_signals[signalIndex];
120}
121
122inline bool SignalBus::HasValue( int signalIndex ) const
123{
124 return _signals[signalIndex].has_value();
125}
126
127template <typename ValueType>
128inline ValueType* SignalBus::GetValue( int signalIndex ) const
129{
130 // You might be thinking: Why the raw pointer return here?
131
132 // See: GetSignal().
133
134 return _signals[signalIndex].as<ValueType>();
135}
136
137template <typename ValueType>
138inline void SignalBus::SetValue( int signalIndex, const ValueType& newValue )
139{
140 _signals[signalIndex].emplace<ValueType>( newValue );
141}
142
143template <typename ValueType>
144inline void SignalBus::MoveValue( int signalIndex, ValueType&& newValue )
145{
146 _signals[signalIndex].emplace<ValueType>( std::forward<ValueType>( newValue ) );
147}
148
149inline void SignalBus::SetSignal( int toSignalIndex, const fast_any::any& fromSignal )
150{
151 _signals[toSignalIndex].emplace( fromSignal );
152}
153
154inline void SignalBus::MoveSignal( int toSignalIndex, fast_any::any& fromSignal )
155{
156 // You might be thinking: Why swap and not move here?
157
158 // This is a really nifty little optimisation actually. When we move a signal value from an
159 // output to an input (or vice-versa within a component) we move its type_info along with it.
160 // If you look at any::emplace(), you'll see that type_info is really useful in determining
161 // whether we need to delete and copy (re)construct our contained value, or can simply copy
162 // assign. To avoid the former as much as possible, a swap is done between source and target
163 // signals such that, between these two points, just two value holders need to be constructed,
164 // and shared back and forth from then on.
165
166 _signals[toSignalIndex].swap( fromSignal );
167}
168
169inline void SignalBus::ClearValue( int signalIndex )
170{
171 _signals[signalIndex].reset();
172}
173
174inline void SignalBus::ClearAllValues()
175{
176 for ( auto& signal : _signals )
177 {
178 signal.reset();
179 }
180}
181
182inline fast_any::type_info SignalBus::GetType( int signalIndex ) const
183{
184 return _signals[signalIndex].type();
185}
186
187} // namespace DSPatch
Signal container.
Definition SignalBus.h:53