From e68b6c970e6b248df84a454d4f535316eed4e887 Mon Sep 17 00:00:00 2001 From: Taylor Brandstetter Date: Thu, 5 Oct 2017 09:13:55 -0700 Subject: [PATCH] Adding back sigslot::repeater. This time, with variadic template args, and unit tests! NOPRESUBMIT=True Bug: None Change-Id: I2669cf5b24ab511eef8c01866748c1424b04abe1 Reviewed-on: https://webrtc-review.googlesource.com/4300 Commit-Queue: Taylor Brandstetter Reviewed-by: Niels Moller Cr-Commit-Position: refs/heads/master@{#20171} --- rtc_base/BUILD.gn | 1 + rtc_base/sigslot_unittest.cc | 35 +++++++++++++++++++++- rtc_base/sigslotrepeater.h | 56 ++++++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 rtc_base/sigslotrepeater.h diff --git a/rtc_base/BUILD.gn b/rtc_base/BUILD.gn index 8c3000e0d0..8d93870931 100644 --- a/rtc_base/BUILD.gn +++ b/rtc_base/BUILD.gn @@ -554,6 +554,7 @@ rtc_static_library("rtc_base_generic") { "signalthread.h", "sigslot.cc", "sigslot.h", + "sigslotrepeater.h", "socket.h", "socketadapters.cc", "socketadapters.h", diff --git a/rtc_base/sigslot_unittest.cc b/rtc_base/sigslot_unittest.cc index b5cab9366c..e60d301323 100644 --- a/rtc_base/sigslot_unittest.cc +++ b/rtc_base/sigslot_unittest.cc @@ -9,8 +9,8 @@ */ #include "rtc_base/sigslot.h" - #include "rtc_base/gunit.h" +#include "rtc_base/sigslotrepeater.h" // This function, when passed a has_slots or signalx, will break the build if // its threading requirement is not single threaded @@ -355,3 +355,36 @@ TEST(SigslotTest, CallDisconnectAllWhileSignalFiring) { EXPECT_EQ(1, receiver1.signal_count()); EXPECT_EQ(0, receiver2.signal_count()); } + +// Basic test that a sigslot repeater works. +TEST(SigslotRepeaterTest, RepeatsSignalsAfterRepeatCalled) { + sigslot::signal<> signal; + sigslot::repeater<> repeater; + repeater.repeat(signal); + // Note that receiver is connected to the repeater, not directly to the + // source signal. + SigslotReceiver<> receiver; + receiver.Connect(&repeater); + // The repeater should repeat the signal, causing the receiver to see it. + signal(); + EXPECT_EQ(1, receiver.signal_count()); + // Repeat another signal for good measure. + signal(); + EXPECT_EQ(2, receiver.signal_count()); +} + +// After calling "stop", a repeater should stop repeating signals. +TEST(SigslotRepeaterTest, StopsRepeatingSignalsAfterStopCalled) { + // Same setup as above test. + sigslot::signal<> signal; + sigslot::repeater<> repeater; + repeater.repeat(signal); + SigslotReceiver<> receiver; + receiver.Connect(&repeater); + signal(); + ASSERT_EQ(1, receiver.signal_count()); + // Now call stop. The next signal should NOT propagate to the receiver. + repeater.stop(signal); + signal(); + EXPECT_EQ(1, receiver.signal_count()); +} diff --git a/rtc_base/sigslotrepeater.h b/rtc_base/sigslotrepeater.h new file mode 100644 index 0000000000..ca4485457e --- /dev/null +++ b/rtc_base/sigslotrepeater.h @@ -0,0 +1,56 @@ +/* + * Copyright 2017 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef RTC_BASE_SIGSLOTREPEATER_H__ +#define RTC_BASE_SIGSLOTREPEATER_H__ + +// repeaters are both signals and slots, which are designed as intermediate +// pass-throughs for signals and slots which don't know about each other (for +// modularity or encapsulation). This eliminates the need to declare a signal +// handler whose sole purpose is to fire another signal. The repeater connects +// to the originating signal using the 'repeat' method. When the repeated +// signal fires, the repeater will also fire. +// +// TODO(deadbeef): Actually use this, after we decide on some style points on +// using signals, so it doesn't get deleted again. + +#include "rtc_base/sigslot.h" + +namespace sigslot { + +template +class repeater_with_thread_policy + : public signal_with_thread_policy, + public has_slots { + private: + // These typedefs are just to make the code below more readable. Code using + // repeaters shouldn't need to reference these types directly. + typedef signal_with_thread_policy base_type; + typedef repeater_with_thread_policy this_type; + + public: + repeater_with_thread_policy() {} + repeater_with_thread_policy(const this_type& s) : base_type(s) {} + + void reemit(Args... args) { base_type::emit(args...); } + void repeat(base_type& s) { s.connect(this, &this_type::reemit); } + void stop(base_type& s) { s.disconnect(this); } +}; + +// Alias with default thread policy. Needed because both default arguments +// and variadic template arguments must go at the end of the list, so we +// can't have both at once. +template +using repeater = + repeater_with_thread_policy; + +} // namespace sigslot + +#endif // RTC_BASE_SIGSLOTREPEATER_H__