BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bdlmt_signaler.h
Go to the documentation of this file.
1/// @file bdlmt_signaler.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bdlmt_signaler.h -*-C++-*-
8#ifndef INCLUDED_BDLMT_SIGNALER
9#define INCLUDED_BDLMT_SIGNALER
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bdlmt_signaler bdlmt_signaler
15/// @brief Provide an implementation of a managed signals and slots system.
16/// @addtogroup bdl
17/// @{
18/// @addtogroup bdlmt
19/// @{
20/// @addtogroup bdlmt_signaler
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bdlmt_signaler-purpose"> Purpose</a>
25/// * <a href="#bdlmt_signaler-classes"> Classes </a>
26/// * <a href="#bdlmt_signaler-description"> Description </a>
27/// * <a href="#bdlmt_signaler-slot-object-requirements"> Slot Object Requirements </a>
28/// * <a href="#bdlmt_signaler-call-groups"> Call Groups </a>
29/// * <a href="#bdlmt_signaler-concurrency-and-order-of-execution"> Concurrency and Order of Execution </a>
30/// * <a href="#bdlmt_signaler-slots-lifetime"> Slots Lifetime </a>
31/// * <a href="#bdlmt_signaler-comparison-of-signalerconnections"> Comparison of SignalerConnections </a>
32/// * <a href="#bdlmt_signaler-thread-safety"> Thread Safety </a>
33/// * <a href="#bdlmt_signaler-usage"> Usage </a>
34/// * <a href="#bdlmt_signaler-example-1-basic-usege"> Example 1: Basic Usege </a>
35///
36/// # Purpose {#bdlmt_signaler-purpose}
37/// Provide an implementation of a managed signals and slots system.
38///
39/// # Classes {#bdlmt_signaler-classes}
40///
41/// - bdlmt::Signaler: a signaler
42/// - bdlmt::SignalerConnection: signaler/slot connection
43/// - bdlmt::SignalerConnectionGuard: RAII signaler/slot connection
44///
45/// # Description {#bdlmt_signaler-description}
46/// This component provides the template class
47/// `bdlmt::Signaler<t_PROT>`, an implementation of a managed signal and slots
48/// system for the void returning function prototype `t_PROT`. Each signaler
49/// represents a callback with multiple targets (called "slots") which are
50/// invoked in a known order when the signaler is invoked (called being
51/// "emitted").
52///
53/// A slot being connected to a signaler is represented by a
54/// `bdlmt::SignalerConnection` which can be used to disconnect that connection
55/// at any time, but can also be discarded if managing the lifetime of the
56/// individual connection is not needed. A guard to disconnect a slot on its
57/// destruction is available in `bdlmt::SignalerConnectionGuard`.
58///
59/// Signalers and the slots connected to them are all managed. Any connections
60/// will be automatically disconnected when a `bdlmt::Signaler` is destroyed, or
61/// when explicitly disconnected, and all internally allocated resources will be
62/// destroyed when no more references to them remain. This enables the user to
63/// make signaler/slot connections and emit signals without expanding effort on
64/// managing the lifetimes of any of the involved objects.
65///
66/// ## Slot Object Requirements {#bdlmt_signaler-slot-object-requirements}
67///
68///
69/// Slots connected to a signaler `bdlmt::Signaler<t_PROT>` must be callable and
70/// copyable objects that may be passed to the constructor of
71/// `bsl::function<t_PROT>`. I.e. a slot must be callable with the same
72/// arguments as `t_PROT`, and if a slot returns a value it will be discarded.
73///
74/// ## Call Groups {#bdlmt_signaler-call-groups}
75///
76///
77/// Slots are free to have side effects, which means that some slots may have to
78/// be called before others even if they are not connected in that order.
79/// `bdlmt::Signaler` allows slots to be placed into groups that are ordered in
80/// some way. Group values are integers, and are ordered by the `integer <`
81/// relation. By default, all connected slots have the group value set to 0.
82///
83/// ## Concurrency and Order of Execution {#bdlmt_signaler-concurrency-and-order-of-execution}
84///
85///
86/// Within a single thread of execution slots are always executed in the order
87/// defined by their respective groups and, within groups, by the order they
88/// were connected to the signaler. If the signaler's call operator is invoked
89/// concurrently from multiple threads, slots may also be executed concurrently.
90///
91/// ## Slots Lifetime {#bdlmt_signaler-slots-lifetime}
92///
93///
94/// Internally, `bdlmt::Signaler` stores copies of connected slot objects. The
95/// copy of the slot object is destroyed after the slot is disconnected from the
96/// signaler, or after the signaler is destroyed, but the exact moment is
97/// unspecified. It is only guaranteed that the lifetime of such object will
98/// not exceed the collective lifetime of the signaler and all connection
99/// objects associated with to that signaler.
100///
101/// ## Comparison of SignalerConnections {#bdlmt_signaler-comparison-of-signalerconnections}
102///
103///
104/// Ordering comparisons of `bdlmt::SignalerConnection`s are transitive and are
105/// provided to facilitate their being stored in an associative container. The
106/// ordering of a `bdlmt::SignalerConnection` does not change when it is
107/// disconnected.
108///
109/// In equality comparisons, two default constructed connections compare
110/// equivalent and a default constructed connection is never equivalent to a
111/// connection to a slot. If a connection is not default constructed, it is
112/// equivalent only to another connection that refers to the same slot.
113///
114/// ## Thread Safety {#bdlmt_signaler-thread-safety}
115///
116///
117/// `bdlmt::Signaler` is **fully thread-safe**, meaning that multiple threads
118/// may use their own instances of the class or use a shared instance without
119/// further synchronization.
120///
121/// With the exception of assignment operators, `swap()`, `reset()` and
122/// `release()` member functions, `bdlmt::SignalerConnection` and
123/// `bdlmt::SignalerConnectionGuard` are thread-safe, meaning that multiple
124/// threads may use their own instances of the class or use a shared instance
125/// without further synchronization.
126///
127/// It is safe to access or modify two distinct connection objects
128/// simultaneously, each from a separate thread, even if they represent the same
129/// slot connection.
130///
131/// ## Usage {#bdlmt_signaler-usage}
132///
133///
134/// This section illustrates intended use of this component.
135///
136/// ### Example 1: Basic Usege {#bdlmt_signaler-example-1-basic-usege}
137///
138///
139/// Suppose we want to implement a GUI button class that allows users to
140/// keep track of its `press` events.
141///
142/// First, we declare the `class`:
143/// @code
144/// /// A pretend GUI button.
145/// class Button {
146///
147/// // DATA
148/// int d_numPresses;
149///
150/// public:
151/// // TYPES
152///
153/// /// Slot argument is the number of times the button has been pressed.
154/// typedef bsl::function<void(int)> OnPressSlotType;
155///
156/// private:
157/// // PRIVATE DATA
158///
159/// /// Signaler argument is the number of times the button has been
160/// /// pressed.
161/// bdlmt::Signaler<void(int)> d_onPress;
162///
163/// public:
164/// // CREATORS
165///
166/// /// Construct a `Button` object.
167/// Button();
168///
169/// // MANIPULATORS
170///
171/// /// Connect the specified `slot` to this button.
172/// bdlmt::SignalerConnection onPressConnect(const OnPressSlotType& slot);
173///
174/// /// Simulate user pressing on GUI button.
175/// void press();
176/// };
177/// @endcode
178/// Then, we define its methods:
179/// @code
180/// // CREATORS
181/// Button::Button()
182/// : d_numPresses(0)
183/// {
184/// }
185///
186/// // MANIPULATORS
187/// bdlmt::SignalerConnection Button::onPressConnect(
188/// const OnPressSlotType& slot)
189/// {
190/// return d_onPress.connect(slot);
191/// }
192///
193/// void Button::press()
194/// {
195/// d_onPress(++d_numPresses);
196/// }
197/// @endcode
198/// Next, we provide an event handler callback printing its argument, which the
199/// class will pass the number of times the button has been pressed:
200/// @code
201/// void showPresses(int numPresses)
202/// {
203/// bsl::cout << "Button pressed " << numPresses << " times.\n";
204/// }
205/// @endcode
206/// Then, in `main`, create a button and subscribe to its events.
207/// @code
208/// u::Button button;
209/// bdlmt::SignalerConnection connection = button.onPressConnect(
210/// &u::showPresses);
211/// @endcode
212/// Next the button is "pressed", we will receive a notification.
213/// @code
214/// button.press();
215/// @endcode
216/// Now, we see the following message:
217/// @code
218/// Button pressed 1 times.
219/// @endcode
220/// Finally, unsubscribe from button's events when we don't want to receive
221/// notifications anymore. (If we didn't call `disconnect`, `button` would
222/// clean up all the allocated resources when it went out of scope):
223/// @code
224/// connection.disconnect();
225/// @endcode
226/// @}
227/** @} */
228/** @} */
229
230/** @addtogroup bdl
231 * @{
232 */
233/** @addtogroup bdlmt
234 * @{
235 */
236/** @addtogroup bdlmt_signaler
237 * @{
238 */
239
240#include <bdlscm_version.h>
241#include <bdlcc_skiplist.h>
242
243#include <bslma_default.h>
245
246#include <bslmf_allocatorargt.h>
247#include <bslmf_forwardingtype.h>
251#include <bslmf_movableref.h>
253#include <bslmf_typelist.h>
254#include <bslmf_util.h> // 'forward(V)'
255
257#include <bslmt_readlockguard.h>
258#include <bslmt_writelockguard.h>
259
260#include <bsls_annotation.h>
261#include <bsls_assert.h>
262#include <bsls_atomic.h>
264#include <bsls_keyword.h>
265#include <bsls_types.h>
266#include <bsls_util.h> // 'forward<T>(V)'
267
268#include <bsl_cstddef.h> // 'bsl::size_t'
269#include <bsl_functional.h>
270#include <bsl_memory.h>
271#include <bsl_utility.h> // 'bsl::pair'
272
273#include <bslma_allocator.h>
274
275
276
277// FORWARD DECLARATION
278
279namespace bdlmt {
280
281template <class>
282class Signaler_Node;
283class SignalerConnection;
284
285 // ==================
286 // struct Signaler_NA
287 // ==================
288
289/// Provides a "Not an Argument" tag type.
290///
291/// See @ref bdlmt_signaler
293};
294
295 // ===========================
296 // class Signaler_ArgumentType
297 // ===========================
298
299/// For a function prototype `t_PROT` of up to 9 arguments, provide types
300/// `ForwardingTypeN` which is the most convenient way to forward the `Nth`
301/// argument.
302/// * as the type of argument N itself (in the case of some fundamental types)
303/// * as a const reference (if `TypeN` is large and either by value or by
304/// const reference), or
305/// * as a reference to a modifiable object, if that's how the argument was
306/// passed in the first place.
307///
308/// \note Note that nothing is passed as an rvalue reference, since if there are
309/// multiple slots (usually the case), the argument will be moved from by the
310/// first one and then unsuitable to be used by the ones following.
311///
312/// Also provide `ForwardingNotArg` the type that forwards `Signaler_NotArg`.
313///
314/// See @ref bdlmt_signaler
315template <class t_PROT>
317
318 private:
319 // PRIVATE TYPES
321
322 template <int t_NUM>
323 struct Forward {
324 // PUBLIC TYPES
326 TypeOrDefault ArgType;
327
328 typedef typename bslmf::ForwardingType<ArgType>::Type Type;
329 };
330
331 public:
332 // PUBLIC TYPES
335
336 typedef typename Forward<1>::Type ForwardingType1;
337 typedef typename Forward<2>::Type ForwardingType2;
338 typedef typename Forward<3>::Type ForwardingType3;
339 typedef typename Forward<4>::Type ForwardingType4;
340 typedef typename Forward<5>::Type ForwardingType5;
341 typedef typename Forward<6>::Type ForwardingType6;
342 typedef typename Forward<7>::Type ForwardingType7;
343 typedef typename Forward<8>::Type ForwardingType8;
344 typedef typename Forward<9>::Type ForwardingType9;
345};
346
347 // =========================
348 // struct Signaler_Invocable
349 // =========================
350
351/// Provides a call operator for the derived class `bdlmt::Signaler`, such that
352/// its call signature is identical to that of `t_PROT`.
353///
354/// See @ref bdlmt_signaler
355template <class t_SIGNALER, class t_PROT>
357};
358
359template <class t_SIGNALER>
360struct Signaler_Invocable<t_SIGNALER, void()> {
361 // ACCESSOR
362
363 /// Call the functions held in all slot holders, in the order of group
364 /// numbers and with the ordering within one group being the order in which
365 /// connections were made, passing the number and type of arguments passed
366 /// to this function.
367 void operator()() const;
368};
369
370template <class t_SIGNALER, class t_ARG1>
371struct Signaler_Invocable<t_SIGNALER, void(t_ARG1)> {
372 // ACCESSOR
373
374 /// Call the functions held in all slot holders, in the order of group
375 /// numbers and with the ordering within one group being the order in which
376 /// connections were made, passing the number and type of arguments passed
377 /// to this function.
378 void operator()(t_ARG1) const;
379};
380
381template <class t_SIGNALER, class t_ARG1, class t_ARG2>
382struct Signaler_Invocable<t_SIGNALER, void(t_ARG1, t_ARG2)> {
383 // ACCESSOR
384
385 /// Call the functions held in all slot holders, in the order of group
386 /// numbers and with the ordering within one group being the order in which
387 /// connections were made, passing the number and type of arguments passed
388 /// to this function.
389 void operator()(t_ARG1, t_ARG2) const;
390};
391
392template <class t_SIGNALER, class t_ARG1, class t_ARG2, class t_ARG3>
393struct Signaler_Invocable<t_SIGNALER, void(t_ARG1, t_ARG2, t_ARG3)> {
394 // ACCESSOR
395
396 /// Call the functions held in all slot holders, in the order of group
397 /// numbers and with the ordering within one group being the order in which
398 /// connections were made, passing the number and type of arguments passed
399 /// to this function.
400 void operator()(t_ARG1, t_ARG2, t_ARG3) const;
401};
402
403template <class t_SIGNALER,
404 class t_ARG1,
405 class t_ARG2,
406 class t_ARG3,
407 class t_ARG4>
408struct Signaler_Invocable<t_SIGNALER, void(t_ARG1, t_ARG2, t_ARG3, t_ARG4)> {
409 // ACCESSOR
410
411 /// Call the functions held in all slot holders, in the order of group
412 /// numbers and with the ordering within one group being the order in which
413 /// connections were made, passing the number and type of arguments passed
414 /// to this function.
415 void operator()(t_ARG1, t_ARG2, t_ARG3, t_ARG4) const;
416};
417
418template <class t_SIGNALER,
419 class t_ARG1,
420 class t_ARG2,
421 class t_ARG3,
422 class t_ARG4,
423 class t_ARG5>
424struct Signaler_Invocable<t_SIGNALER,
425 void(t_ARG1, t_ARG2, t_ARG3, t_ARG4, t_ARG5)> {
426 // ACCESSOR
427
428 /// Call the functions held in all slot holders, in the order of group
429 /// numbers and with the ordering within one group being the order in which
430 /// connections were made, passing the number and type of arguments passed
431 /// to this function.
432 void operator()(t_ARG1, t_ARG2, t_ARG3, t_ARG4, t_ARG5) const;
433};
434
435template <class t_SIGNALER,
436 class t_ARG1,
437 class t_ARG2,
438 class t_ARG3,
439 class t_ARG4,
440 class t_ARG5,
441 class t_ARG6>
443 t_SIGNALER,
444 void(t_ARG1, t_ARG2, t_ARG3, t_ARG4, t_ARG5, t_ARG6)> {
445 // ACCESSOR
446
447 /// Call the functions held in all slot holders, in the order of group
448 /// numbers and with the ordering within one group being the order in which
449 /// connections were made, passing the number and type of arguments passed
450 /// to this function.
451 void operator()(t_ARG1, t_ARG2, t_ARG3, t_ARG4, t_ARG5, t_ARG6) const;
452};
453
454template <class t_SIGNALER,
455 class t_ARG1,
456 class t_ARG2,
457 class t_ARG3,
458 class t_ARG4,
459 class t_ARG5,
460 class t_ARG6,
461 class t_ARG7>
463 t_SIGNALER,
464 void(t_ARG1, t_ARG2, t_ARG3, t_ARG4, t_ARG5, t_ARG6, t_ARG7)> {
465 // ACCESSOR
466
467 /// Call the functions held in all slot holders, in the order of group
468 /// numbers and with the ordering within one group being the order in which
469 /// connections were made, passing the number and type of arguments passed
470 /// to this function.
471 void operator()(t_ARG1,
472 t_ARG2,
473 t_ARG3,
474 t_ARG4,
475 t_ARG5,
476 t_ARG6,
477 t_ARG7) const;
478};
479
480template <class t_SIGNALER,
481 class t_ARG1,
482 class t_ARG2,
483 class t_ARG3,
484 class t_ARG4,
485 class t_ARG5,
486 class t_ARG6,
487 class t_ARG7,
488 class t_ARG8>
490 t_SIGNALER,
491 void(t_ARG1, t_ARG2, t_ARG3, t_ARG4, t_ARG5, t_ARG6, t_ARG7, t_ARG8)> {
492 // ACCESSOR
493
494 /// Call the functions held in all slot holders, in the order of group
495 /// numbers and with the ordering within one group being the order in which
496 /// connections were made, passing the number and type of arguments passed
497 /// to this function.
498 void operator()(t_ARG1,
499 t_ARG2,
500 t_ARG3,
501 t_ARG4,
502 t_ARG5,
503 t_ARG6,
504 t_ARG7,
505 t_ARG8) const;
506};
507
508template <class t_SIGNALER,
509 class t_ARG1,
510 class t_ARG2,
511 class t_ARG3,
512 class t_ARG4,
513 class t_ARG5,
514 class t_ARG6,
515 class t_ARG7,
516 class t_ARG8,
517 class t_ARG9>
518struct Signaler_Invocable<t_SIGNALER,
519 void(t_ARG1,
520 t_ARG2,
521 t_ARG3,
522 t_ARG4,
523 t_ARG5,
524 t_ARG6,
525 t_ARG7,
526 t_ARG8,
527 t_ARG9)> {
528 // ACCESSOR
529
530 /// Call the functions held in all slot holders, in the order of group
531 /// numbers and with the ordering within one group being the order in which
532 /// connections were made, passing the number and type of arguments passed
533 /// to this function.
534 void operator()(t_ARG1,
535 t_ARG2,
536 t_ARG3,
537 t_ARG4,
538 t_ARG5,
539 t_ARG6,
540 t_ARG7,
541 t_ARG8,
542 t_ARG9) const;
543};
544
545 // ============================
546 // class Signaler_SlotNode_Base
547 // ============================
548
549/// Provide a non-template protocol base class for `Signaler_SlotNode` so
550/// `SignalerConnection` objects, which are not templated, can refer to and
551/// manipulate `Signaler_SlotNode` objects.
552///
553/// See @ref bdlmt_signaler
555
556 protected:
557 // PROTECTED CREATORS
558
559 /// Virtual d'tor.
561
562 public:
563 // MANIPULATORS
564
565 /// Disconnect this slot and return without waiting. If the slot was
566 /// already disconnected, this function has no effect. Throws nothing.
567 ///
568 /// \note Note that it is guaranteed that this slot will not be called by a
569 /// signal on the same signaler that begins after this function completes.
571
572 /// Disconnect this slot and block the calling thread pending the
573 /// completion of signals being emitted on the signaler by any other
574 /// threads. If the slot was already disconnected, this function has no effect on the slot. Throws nothing.
575 ///
576 /// \pre The behavior is undefined if this function is called from a slot on the same signaler.
577 ///
578 /// \note Note that it is
579 /// guaranteed that this slot will not be called by a signal on the same
580 /// signaler that begins after this function completes, whether `wait` is
581 /// `true` or not.
583
584 // ACCESSOR
585
586 /// Return `true` if this slot is connected to its associated signaler, and
587 /// `false` otherwise.
588 virtual bool isConnected() const = 0;
589};
590
591 // =======================
592 // class Signaler_SlotNode
593 // =======================
594
595/// Dynamically-allocated container for one slot, containing a function object
596/// that can be called by a signaler. Owned by a shared pointer in a skip list
597/// container in the `Signaler_Node`. Also referred to by weak pointers from
598/// `SignalerConnection` objects.
599///
600/// See @ref bdlmt_signaler
601template <class t_PROT>
603
604 private:
605 // PRIVATE TYPES
607 typedef typename ArgumentType::ForwardingNotArg ForwardingNotArg;
609
610 public:
611 // PUBLIC TYPE
612
613 /// Defines a "key" used to index slots in an associative collection. The
614 /// first element of the pair is the slot call group; the second is the
615 /// slot ID.
617
618 private:
619 // PRIVATE DATA
620
621 // Slot key containing the call group and the slot ID. Used when notifying
622 // the signaler about disconnection.
623 SlotMapKey d_slotMapKey;
624
625 // Set to `true` on construction, and to `false` on disconnection. Used
626 // for preventing calling a slot after it has been disconnected.
627 bsls::AtomicBool d_isConnected;
628
629 // Weak reference to the associated signaler node.
630 bsl::weak_ptr<SignalerNode> d_signalerNodePtr;
631
632 // The target callback.
634
635 private:
636 // NOT IMPLEMENTED
639 Signaler_SlotNode& operator=(const Signaler_SlotNode&)
641
642 private:
643 // PRIVATE ACCESSORS
644
645 /// Dispatch function to be called by the `invoke` function, the first
646 /// argument is an `integral_constant` containing the number of specified
647 /// arguments `argN` that follow it. Each function takes 9 arguments in
648 /// addition to the integral constant, but the last ones of type
649 /// `ForwardingNotArg` are not used.
650 void doInvoke(bsl::integral_constant<int, 0>, // arguments count tag
651 ForwardingNotArg,
652 ForwardingNotArg,
653 ForwardingNotArg,
654 ForwardingNotArg,
655 ForwardingNotArg,
656 ForwardingNotArg,
657 ForwardingNotArg,
658 ForwardingNotArg,
659 ForwardingNotArg) const;
660 void doInvoke(bsl::integral_constant<int, 1>, // arguments count tag
661 typename ArgumentType::ForwardingType1 arg1,
662 ForwardingNotArg,
663 ForwardingNotArg,
664 ForwardingNotArg,
665 ForwardingNotArg,
666 ForwardingNotArg,
667 ForwardingNotArg,
668 ForwardingNotArg,
669 ForwardingNotArg) const;
670 void doInvoke(bsl::integral_constant<int, 2>, // arguments count tag
671 typename ArgumentType::ForwardingType1 arg1,
672 typename ArgumentType::ForwardingType2 arg2,
673 ForwardingNotArg,
674 ForwardingNotArg,
675 ForwardingNotArg,
676 ForwardingNotArg,
677 ForwardingNotArg,
678 ForwardingNotArg,
679 ForwardingNotArg) const;
680 void doInvoke(bsl::integral_constant<int, 3>, // arguments count tag
681 typename ArgumentType::ForwardingType1 arg1,
682 typename ArgumentType::ForwardingType2 arg2,
683 typename ArgumentType::ForwardingType3 arg3,
684 ForwardingNotArg,
685 ForwardingNotArg,
686 ForwardingNotArg,
687 ForwardingNotArg,
688 ForwardingNotArg,
689 ForwardingNotArg) const;
690 void doInvoke(bsl::integral_constant<int, 4>, // arguments count tag
691 typename ArgumentType::ForwardingType1 arg1,
692 typename ArgumentType::ForwardingType2 arg2,
693 typename ArgumentType::ForwardingType3 arg3,
694 typename ArgumentType::ForwardingType4 arg4,
695 ForwardingNotArg,
696 ForwardingNotArg,
697 ForwardingNotArg,
698 ForwardingNotArg,
699 ForwardingNotArg) const;
700 void doInvoke(bsl::integral_constant<int, 5>, // arguments count tag
701 typename ArgumentType::ForwardingType1 arg1,
702 typename ArgumentType::ForwardingType2 arg2,
703 typename ArgumentType::ForwardingType3 arg3,
704 typename ArgumentType::ForwardingType4 arg4,
705 typename ArgumentType::ForwardingType5 arg5,
706 ForwardingNotArg,
707 ForwardingNotArg,
708 ForwardingNotArg,
709 ForwardingNotArg) const;
710 void doInvoke(bsl::integral_constant<int, 6>, // arguments count tag
711 typename ArgumentType::ForwardingType1 arg1,
712 typename ArgumentType::ForwardingType2 arg2,
713 typename ArgumentType::ForwardingType3 arg3,
714 typename ArgumentType::ForwardingType4 arg4,
715 typename ArgumentType::ForwardingType5 arg5,
716 typename ArgumentType::ForwardingType6 arg6,
717 ForwardingNotArg,
718 ForwardingNotArg,
719 ForwardingNotArg) const;
720 void doInvoke(bsl::integral_constant<int, 7>, // arguments count tag
721 typename ArgumentType::ForwardingType1 arg1,
722 typename ArgumentType::ForwardingType2 arg2,
723 typename ArgumentType::ForwardingType3 arg3,
724 typename ArgumentType::ForwardingType4 arg4,
725 typename ArgumentType::ForwardingType5 arg5,
726 typename ArgumentType::ForwardingType6 arg6,
727 typename ArgumentType::ForwardingType7 arg7,
728 ForwardingNotArg,
729 ForwardingNotArg) const;
730 void doInvoke(bsl::integral_constant<int, 8>,
731 typename ArgumentType::ForwardingType1 arg1,
732 typename ArgumentType::ForwardingType2 arg2,
733 typename ArgumentType::ForwardingType3 arg3,
734 typename ArgumentType::ForwardingType4 arg4,
735 typename ArgumentType::ForwardingType5 arg5,
736 typename ArgumentType::ForwardingType6 arg6,
737 typename ArgumentType::ForwardingType7 arg7,
738 typename ArgumentType::ForwardingType8 arg8,
739 ForwardingNotArg) const;
740 void doInvoke(bsl::integral_constant<int, 9>,
741 typename ArgumentType::ForwardingType1 arg1,
742 typename ArgumentType::ForwardingType2 arg2,
743 typename ArgumentType::ForwardingType3 arg3,
744 typename ArgumentType::ForwardingType4 arg4,
745 typename ArgumentType::ForwardingType5 arg5,
746 typename ArgumentType::ForwardingType6 arg6,
747 typename ArgumentType::ForwardingType7 arg7,
748 typename ArgumentType::ForwardingType8 arg8,
749 typename ArgumentType::ForwardingType9 arg9) const;
750
751 public:
752 // CREATORS
753
754 /// Create a `Signaler_SlotNode` object associated with signaler node at
755 /// the specified `signalerNodePtr` using the specified `slotMapKey` and
756 /// with the specified `slot` callable object. Specify an `allocator` used
757 /// to supply memory.
758 template <class t_FUNC>
760 const bsl::weak_ptr<SignalerNode>& signalerNodePtr,
762 SlotMapKey slotMapKey,
763 bslma::Allocator *allocator);
764
765 /// Destroy this object.
767
768 public:
769 // MANIPULATOR
770
771 /// Disconnect this slot and return without waiting. If the slot was
772 /// already disconnected, this function has no effect. Throws nothing.
773 ///
774 /// \note Note that it is guaranteed that this slot will not be called by a
775 /// signal on the same signaler that begins after this function completes.
777
778 /// Disconnect this slot and block the calling thread pending the
779 /// completion of signals being emitted on the signaler by any other
780 /// threads. If the slot was already disconnected, this function has no effect on the slot. Throws nothing.
781 ///
782 /// \pre The behavior is undefined if this function is called from a slot on the same signaler.
783 ///
784 /// \note Note that it is
785 /// guaranteed that this slot will not be called by a signal on the same
786 /// signaler that begins after this function completes, whether `wait` is
787 /// `true` or not.
789
790 /// Notify this slot that is was disconnected from its associated signaler.
791 /// Throws nothing. After this function completes, `isConnected()` returns
792 /// `false`.
793 void notifyDisconnected() BSLS_KEYWORD_NOEXCEPT;
794
795 // ACCESSORS
796
797 /// Invoke the stored callback `c`, as if by `c(args...)`, where
798 /// `args...` are the specified arguments `arg1`, `arg2`, `arg3`, etc.,
799 /// except that the actual number of arguments passed to `c` is equal to
800 /// the number of arguments for `t_PROT`. If this slot is disconnected,
801 /// this function has no effect.
802 void invoke(typename ArgumentType::ForwardingType1 arg1,
803 typename ArgumentType::ForwardingType2 arg2,
804 typename ArgumentType::ForwardingType3 arg3,
805 typename ArgumentType::ForwardingType4 arg4,
806 typename ArgumentType::ForwardingType5 arg5,
807 typename ArgumentType::ForwardingType6 arg6,
808 typename ArgumentType::ForwardingType7 arg7,
809 typename ArgumentType::ForwardingType8 arg8,
810 typename ArgumentType::ForwardingType9 arg9) const;
811
812 /// Return `true` if this slot is connected to its associated signaler, and
813 /// `false` otherwise.
815};
816
817 // ===================
818 // class Signaler_Node
819 // ===================
820
821/// Provides the implementation of a signaler. This object has a 1-1
822/// relationship with the `Signaler`, which has a shared pointer to it. This
823/// allows other objects to refer to it via shared and weak pointers. This
824/// allows `SignalerConnection` objects to outlive the `Signaler -
825/// Signaler_Node` pair, since they can test or lock weak pointers to see if
826/// the `Signaler_Node` still exists when they are trying to disconnect
827/// themselves.
828template <class t_PROT>
830: public bsl::enable_shared_from_this<Signaler_Node<t_PROT> > {
831
832 private:
833 // PRIVATE TYPES
835 typedef typename SlotNode::SlotMapKey SlotMapKey;
837
838 typedef bdlcc::SkipList<SlotMapKey, // [GROUP, ID] pair
840 typedef typename KeyToSlotMap::PairHandle SlotPairHandle;
841
842 private:
843 // PRIVATE DATA
844
845 // The purpose of this mutex is to implement the waiting behavior of
846 // diconnects in `wait` mode.
847 mutable bslmt::ReaderWriterMutex d_signalerMutex;
848
849 // Thread-safe collection containing slots indexed (and ordered) by their
850 // respective keys.
851 KeyToSlotMap d_slotMap;
852
853 // For supplying `second` members of the `SlotMapKey` values that are
854 // unique to a signaler.
855 bsls::AtomicUint d_keyId;
856
857 private:
858 // NOT IMPLEMENTED
861
862 public:
863 // CREATORS
864
865 /// Create a `Signaler_Node` object having no connected slots. Specify an `allocator` used to supply memory.
866 ///
867 /// \note Note that the supplied allocator
868 /// must remain valid until all connection objects associated with this
869 /// signaler are destroyed.
870 explicit
872
873 public:
874 // MANIPULATORS
875
876 /// Implements `Signaler::connect`. Connect the specified `slot`, a
877 /// callable object which must meet the `Slot Object Requirements`
878 /// described in the component documentation, to this signaler. Specify
879 /// a `group` used to order slots upon invocation. Return an instance
880 /// of `SignalerConnection` representing the created connection. This function meets the strong exception guarantee.
881 ///
882 /// \note Note that the
883 /// connected slot may be called by a signal emitted from another thread
884 /// before this function completes. Also note that it is unspecified
885 /// whether connecting a slot while the signaler is emitting will result in the slot being called immediately.
886 ///
887 /// \note Note that `t_FUNC` may have a
888 /// return type other than `void`, but in that case, when the slot is
889 /// called, the return value will be discarded.
890 template <class t_FUNC>
891 SignalerConnection connect(
893 int group);
894
895 /// Implements `Signaler::disconnectAllSlots()`. Disconnect all slots,
896 /// if any, connected to this signaler. Any signals emitted on the
897 /// corresponding signaler that happen after this call to disconnect
898 /// completes will not call any slots that were connected prior to this call. Throws nothing.
899 ///
900 /// \note Note that this function does not block the
901 /// calling thread pending completion of ongoing signals emitted on the
902 /// signaler. Also note that it is unspecified how many slots, if any,
903 /// will be called by any invocation on the signaler that begins before
904 /// this function completes. Also note that if a slot is connected to
905 /// this signaler during a call to this function, it is unspecified
906 /// whether that slot will be disconnected.
907 void disconnectAllSlots() BSLS_KEYWORD_NOEXCEPT;
908
909 /// Implements `Signaler::disconnectAllSlotsAndWait`. Disconnect all
910 /// slots, if any, connected to this signaler. Any signals emitted on
911 /// the corresponding signaler that happens after this call to
912 /// disconnect completes will not call any slots that were connected
913 /// prior to this call. This function blocks the calling thread pending
914 /// completion of all ongoing signals being emitted on the signaler. Throws nothing.
915 ///
916 /// \pre The behavior is undefined if this method is called from a slot connected to the signaler.
917 ///
918 /// \note Note that it is unspecified
919 /// how many slots, if any, will be called by any invocation on the
920 /// signaler that begins before this function completes. Also note that
921 /// if a slot is connected to this signaler during a call to this
922 /// function, it is unspecified whether that slot will be disconnected.
923 void disconnectAllSlotsAndWait() BSLS_KEYWORD_NOEXCEPT;
924
925 /// Implements `Signaler::disconnectGroup()`. Disconnect all slots, if
926 /// any, connected to this signaler in the specified `group`. Any
927 /// signal emitted on the corresponding signaler that happens after this
928 /// call to disconnect completes will not call any slots in `group` that were connected prior to this call. Throws nothing.
929 ///
930 /// \note Note that this
931 /// function does not block the calling thread pending completion of
932 /// ongoing signals emitted on the signaler. Also note that it is
933 /// unspecified how many affected slots, if any, will be signalled to by
934 /// any invocation on the signaler that begins before this function
935 /// completes. Also note that if a slot in `group` is connected to this
936 /// signaler during a call to this function, it is unspecified whether
937 /// that slot will be disconnected.
938 void disconnectGroup(int group) BSLS_KEYWORD_NOEXCEPT;
939
940 /// Implements `Signaler::disconnectGroupAndWait()`. Disconnect all
941 /// slots, if any, connected to this signaler in the specified `group`.
942 /// Any signal emitted on the corresponding signaler that happens after
943 /// this call to disconnect completes will not call any slots in `group`
944 /// that were connected prior to this call. This function blocks the
945 /// calling thread pending completion of ongoing signals being emitted on the signaler. Throws nothing.
946 ///
947 /// \pre The behavior is undefined if this
948 /// method is called from a slot connected to the signaler.
949 ///
950 /// \note Note that it is unspecified how many affected slots, if any, will be signaled
951 /// to by any emission on the signaler that begins before this function
952 /// completes. Also note that if a slot in `group` is connected to this
953 /// signaler during a call to this function, it is unspecified whether
954 /// that slot will be disconnected.
955 void disconnectGroupAndWait(int group) BSLS_KEYWORD_NOEXCEPT;
956
957 /// Notify this signaler that a slot with the specified `slotMapKey` was
958 /// disconnected. Throws nothing.
959 void notifyDisconnected(SlotMapKey slotMapKey) BSLS_KEYWORD_NOEXCEPT;
960
961 /// Block until all signals currently being emitted on the signaler have
962 /// completed.
963 void synchronizeWait() BSLS_KEYWORD_NOEXCEPT;
964
965 public:
966 // ACCESSORS
967
968 /// Called by `Signaler_Invocable`s call operators, passing the
969 /// specified `arg1`, `arg2`, `arg3`, `arg4`, `arg5`, `arg6`, `arg7`,
970 /// `arg8` and `arg9` on to the slots.
971 void invoke(typename ArgumentType::ForwardingType1 arg1,
972 typename ArgumentType::ForwardingType2 arg2,
973 typename ArgumentType::ForwardingType3 arg3,
974 typename ArgumentType::ForwardingType4 arg4,
975 typename ArgumentType::ForwardingType5 arg5,
976 typename ArgumentType::ForwardingType6 arg6,
977 typename ArgumentType::ForwardingType7 arg7,
978 typename ArgumentType::ForwardingType8 arg8,
979 typename ArgumentType::ForwardingType9 arg9) const;
980
981 /// Implements `Signaler::slotCount()`. Return the number of slots connected to this signaler.
982 ///
983 /// \note Note that in multithreaded environment,
984 /// the value returned by `slotCount()` is approximate.
985 bsl::size_t slotCount() const;
986};
987
988 // ==============
989 // class Signaler
990 // ==============
991
992/// This class template provides a thread-safe signaler that executes
993/// connected slots when invoked via its call operator. `t_PROT` is a
994/// function signature and must have a return type of `void`. The callable
995/// objects assigned to the slots may have return types other than `void`,
996/// in which case their return values will be discarded.
997///
998/// See @ref bdlmt_signaler
999template <class t_PROT>
1000class Signaler : public Signaler_Invocable<Signaler<t_PROT>, t_PROT> {
1001
1002 public:
1003 // TYPES
1004 typedef void ResultType; // Defines the result type of 'operator()'. If
1005 // 't_PROT' has a result type that is not 'void',
1006 // the return values of the calls to the slots
1007 // are discarded.
1008
1009 private:
1010 // PRIVATE DATA
1012
1013 // FRIENDS
1014 friend struct Signaler_Invocable<Signaler<t_PROT>, t_PROT>;
1015
1016 public:
1017 // TRAITS
1019
1020 private:
1021 // NOT IMPLEMENTED
1023 Signaler& operator=(const Signaler&) BSLS_KEYWORD_DELETED;
1024
1025 public:
1026 // CREATORS
1027
1028 /// Create a `Signaler` object having no connected slots. Optionally
1029 /// specify a `basicAllocator` used to supply memory. If
1030 /// `basicAllocator` is 0, the currently installed default allocator is used.
1031 ///
1032 /// \note Note that the supplied allocator must remain valid until all
1033 /// connection objects associated with this signaler are destroyed.
1034 explicit
1035 Signaler(bslma::Allocator *basicAllocator = 0);
1036
1037 /// Destroy this object. Call `disconnectAllSlots()`.
1038 ///
1039 /// \pre The behavior is undefined if this function is invoked from a slot connected to this
1040 /// signaler.
1041 ~Signaler();
1042
1043 public:
1044 // MANIPULATORS
1045
1046 /// Connect the specified `slot`, a callable object which must meet the
1047 /// `Slot Object Requirements` described in the component documentation,
1048 /// to this signaler. Optionally specify a `group` used to order slots
1049 /// upon invocation. Return an instance of `SignalerConnection`
1050 /// representing the created connection. This function meets the strong exception guarantee.
1051 ///
1052 /// \note Note that the connected slot may be called by
1053 /// a signal emitted from another thread before this function completes.
1054 /// Also note that it is unspecified whether connecting a slot while the
1055 /// signaler is emitting will result in the slot being called immediately.
1056 ///
1057 /// \note Note that `t_FUNC` may have a return type other than
1058 /// `void`, but in that case, when the slot is called, the return value
1059 /// will be discarded.
1060 template <class t_FUNC>
1061 SignalerConnection connect(
1063 int group = 0);
1064
1065 /// Disconnect all slots, if any, connected to this signaler. Any
1066 /// signals emitted on the corresponding signaler that happen after this
1067 /// call to disconnect completes will not call any slots that were connected prior to this call. Throws nothing.
1068 ///
1069 /// \note Note that this
1070 /// function does not block the calling thread pending completion of
1071 /// ongoing signals emitted on the signaler. Also note that it is
1072 /// unspecified how many slots, if any, will be called by any invocation
1073 /// on the signaler that begins before this function completes. Also
1074 /// note that if a slot is connected to this signaler during a call to
1075 /// this function, it is unspecified whether that slot will be
1076 /// disconnected.
1077 void disconnectAllSlots() BSLS_KEYWORD_NOEXCEPT;
1078
1079 /// Disconnect all slots, if any, connected to this signaler. Any
1080 /// signals emitted on the corresponding signaler that happens after
1081 /// this call to disconnect completes will not call any slots that were
1082 /// connected prior to this call. This function blocks the calling
1083 /// thread pending completion of all ongoing signals being emitted on the signaler. Throws nothing.
1084 ///
1085 /// \pre The behavior is undefined if this
1086 /// method is called from a slot connected to the signaler.
1087 ///
1088 /// \note Note that it is unspecified how many slots, if any, will be called by any
1089 /// invocation on the signaler that begins before this function
1090 /// completes. Also note that if a slot is connected to this signaler
1091 /// during a call to this function, it is unspecified whether that slot
1092 /// will be disconnected.
1093 void disconnectAllSlotsAndWait() BSLS_KEYWORD_NOEXCEPT;
1094
1095 /// Disconnect all slots, if any, connected to this signaler in the
1096 /// specified `group`. Any signal emitted on the corresponding signaler
1097 /// that happens after this call to disconnect completes will not call
1098 /// any slots in `group` that were connected prior to this call. Throws nothing.
1099 ///
1100 /// \note Note that this function does not block the calling thread
1101 /// pending completion of ongoing signals emitted on the signaler. Also
1102 /// note that it is unspecified how many affected slots, if any, will be
1103 /// signalled to by any invocation on the signaler that begins before
1104 /// this function completes. Also note that if a slot in `group` is
1105 /// connected to this signaler during a call to this function, it is
1106 /// unspecified whether that slot will be disconnected.
1107 void disconnectGroup(int group) BSLS_KEYWORD_NOEXCEPT;
1108
1109 /// Disconnect all slots, if any, connected to this signaler in the
1110 /// specified `group`. Any signal emitted on the corresponding signaler
1111 /// that happens after this call to disconnect completes will not call
1112 /// any slots in `group` that were connected prior to this call. This
1113 /// function blocks the calling thread pending completion of ongoing
1114 /// signals being emitted on the signaler. Throws nothing.
1115 ///
1116 /// \pre The behavior is undefined if this method is called from a slot connected to the signaler.
1117 ///
1118 /// \note Note that it is unspecified how many affected
1119 /// slots, if any, will be signaled to by any emission on the signaler
1120 /// that begins before this function completes. Also note that if a
1121 /// slot in `group` is connected to this signaler during a call to this
1122 /// function, it is unspecified whether that slot will be disconnected.
1123 void disconnectGroupAndWait(int group) BSLS_KEYWORD_NOEXCEPT;
1124
1125 public:
1126 // ACCESSORS
1127
1128 // 'bdlmt::Signaler_Invocable', from which this 'class' inherits, provides
1129 // a call operator that, in C++11, would be defined and behave exactly this
1130 // way, except that the number of arguments is limited to
1131 // 9, where 'ARGS...' are the arguments of 't_PROT'. Sequentially emit
1132 // the signal, sequentially calling each slot connected to this signaler as
1133 // if by 'f_i(args...)', where 'f_i' is the i-th connected slot. The
1134 // behavior is undefined if this function is invoked from a slot connected
1135 // to this signaler. Note that signals emitted to slots are ordered by
1136 // their respective groups, and within groups, by the order in which they
1137 // were connected. Also note that the call operator does not forward
1138 // rvalue references. That is done explicitly to prevent invocation
1139 // arguments from being moved to the first slot, leaving them "empty" for
1140 // all subsequent slots. Also note that if a slot is connected by a called
1141 // slot and the group of the new slots is less than the group of the called
1142 // slot, the new slot will not be called, otherwise it will. If a slot
1143 // that has not been visited in a traversal is disconnected by a call to
1144 // any of the 'disconnect*' methods, the disconnected slot will not be
1145 // called in the traversal. Also note that if execution of a slot throws
1146 // an exception, the emission sequence is interrupted and the exception is
1147 // propagated to the caller of the signaler immediately.
1148 // void operator()(ARGS... args) const;
1149 //
1150
1151 /// Return the number of slots connected to this signaler.
1152 ///
1153 /// \note Note that the value returned by `slotCount()` is approximate if the signaler
1154 /// is being simultaneously manipulated by other threads.
1155 bsl::size_t slotCount() const;
1156};
1157
1158 // ========================
1159 // class SignalerConnection
1160 // ========================
1161
1162/// This `class` represents a connection between a signaler and a slot. It
1163/// is a lightweight object that has the ability to query whether the
1164/// signaler and slot are currently connected, and to disconnect the slot from the signaler.
1165///
1166/// \note Note that, unless otherwise specified, it is safe to
1167/// invoke any method of `SignalerConnection` from the context of its
1168/// associated slot, or any other slot.
1169///
1170/// See @ref bdlmt_signaler
1172
1173 private:
1174 // PRIVATE TYPES
1176
1177 private:
1178 // PRIVATE DATA
1179
1180 // Weak pointer to the associated slot.
1181 bsl::weak_ptr<SlotNode_Base> d_slotNodeBasePtr;
1182
1183 // FRIENDS
1184 template <class>
1185 friend class Signaler_Node;
1186 friend bool operator<( const SignalerConnection&,
1187 const SignalerConnection&);
1188 friend bool operator==(const SignalerConnection&,
1189 const SignalerConnection&);
1190
1191 public:
1192 // TRAITS
1195
1196 private:
1197 // PRIVATE CREATORS
1198
1199 /// Create `SignalerConnection` object weakly linked to the specified
1200 /// `slotNodeBasePtr`.
1201 explicit
1204
1205 public:
1206 // CREATORS
1207
1208 /// Create a `SignalerConnection` object having no associated slot.
1210
1211 /// Create a `SignalerConnection` object that refers to and assumes
1212 /// management of the same slot (if any) as the specified `original`
1213 /// object. Throws nothing.
1216
1217 /// Create a `SignalerConnection` object that refers to and assumes
1218 /// management of the same slot (if any) as the specified `original`
1219 /// object, and reset `original` to a default-constructed state. Throws
1220 /// nothing.
1223
1224 // MANIPULATORS
1225
1226 /// Make this connection refer to and assume management of the same slot
1227 /// (if any) as the specified `rhs` connection. Return `*this`.
1230
1231 /// Make this connection refer to and assume management of the same slot
1232 /// (if any) as the specified `rhs` connection, and reset `rhs` to a
1233 /// default-constructed state. Return `*this`. Throws nothing.
1236
1237 /// Disassociate this connection object from its associated slot, if any,
1238 /// and reset `*this` to a default-constructed state. Throws nothing.
1240
1241 /// Swap the contents of `*this` and the specified `other`. Throws
1242 /// nothing.
1243 void swap(SignalerConnection& other) BSLS_KEYWORD_NOEXCEPT;
1244
1245 public:
1246 // ACCESSORS
1247
1248 /// Disconnect the associated slot. If the slot was already disconnected,
1249 /// this function has no effect. This function returns immediately without
1250 /// waiting on any calls to the signaler that may be in progress. Any
1251 /// signal emitted on the corresponding signaler that happens after this
1252 /// call to `disconnect` completes will not emit to the slot. Throws nothing.
1253 ///
1254 /// \note Note that it is unspecified if any signal that is emitted
1255 /// before this function completes will call the slot.
1256 void disconnect() const BSLS_KEYWORD_NOEXCEPT;
1257
1258 /// Disconnect the associated slot. If the slot was already disconnected,
1259 /// this function has no effect. This function blocks the calling thread
1260 /// pending completion of signals emitted on the signaler by any thread,
1261 /// even if the slot was disconnected prior to this call. Any signal
1262 /// emitted on the corresponding signaler that happens after this call to
1263 /// `disconnect` completes will not emit to the slot. Throws nothing.
1264 ///
1265 /// \pre The behavior is undefined if this method is called from any slot.
1266 ///
1267 /// \note Note that it is unspecified if any signal emitted on the signaler that
1268 /// begins before this function completes will call the slot.
1269 void disconnectAndWait() const BSLS_KEYWORD_NOEXCEPT;
1270
1271 /// Return `true` if the associated slot is connected to the signaler
1272 /// `*this` was obtained from, and `false` otherwise. If `*this` does not
1273 /// have an associated slot (i.e., was default-constructed), return
1274 /// `false`.
1275 bool isConnected() const;
1276};
1277
1278 // =============================
1279 // class SignalerConnectionGuard
1280 // =============================
1281
1282/// This guard type `has a` `SignalerConnection`, through which it can manage a
1283/// slot, and when it is destroyed or assigned to it will disconnect that slot.
1284/// It also contains a boolean `waitOnDisconnect` attribute, which determines
1285/// whether `disconnect` or `disconnectAndWait` is used to disconnect the slot.
1286/// The `waitOnDisconnect` attribute is set in constructors from a
1287/// `SignalerConnection` and propagated when move constructing or move
1288/// assigning a guard to a different guard.
1289///
1290/// See @ref bdlmt_signaler
1292
1293 // PRIVATE DATA
1294 SignalerConnection d_connection;
1295
1296 bool d_waitOnDisconnect; // determines whether
1297 // `disconnect` or
1298 // `disconnectAndWait` is called
1299 // on `d_connection` at
1300 // destruction or assignment
1301
1302 private:
1303 // NOT IMPLEMENTED
1308
1309 public:
1310 // TRAITS
1313
1314 public:
1315 // CREATORS
1316
1317 /// Create a `SignalerConnectionGuard` object having no associated slot
1318 /// with `waitOnDisconnect` set to `false`.
1320
1321 /// Create a `SignalerConnectionGuard` object that refers to and assumes
1322 /// management of the same slot, if any, as the specified `connection`
1323 /// object. Upon destruction or assignment, the optionally specified
1324 /// `waitOnDisconnect` determines whether `disconnect` or
1325 /// `disconnectAndWait` will be called on the slot managed by this object,
1326 /// if any.
1327 explicit
1329 const SignalerConnection& connection,
1330 bool waitOnDisconnect = false);
1331
1332 /// Create a `SignalerConnectionGuard` that refers to the same slot, if
1333 /// any, as the specified `connection`, which is left in an unspecified
1334 /// state. Optionally specify `waitOnDisconnect` indicating whether
1335 /// `disconnect` or `disconnectAndWait` will be called on the slot, if any,
1336 /// managed by this object upon destruction or assignment. Throws nothing.
1337 explicit
1339 SignalerConnection> connection,
1340 bool waitOnDisconnect = false) BSLS_KEYWORD_NOEXCEPT;
1341
1342 /// Create a `SignalerConnectionGuard` that manages the same slot, if any,
1343 /// as the specified `original`, which is left in the default-constructed
1344 /// state. Copy the `waitOnDisconnect` state from `original`, indicating
1345 /// whether `disconnect()` or `disconnectAndWait()` will be called on the
1346 /// slot, if any, contained in this object upon destruction or assignment.
1347 /// Throws nothing.
1349 original) BSLS_KEYWORD_NOEXCEPT;
1350
1351 /// Destroy this object. If a slot is being managed by this object, call
1352 /// `disconnect` or `disconnectAndWait` on it, depending upon the value of
1353 /// `waitOnDisconnect`.
1355
1356 // MANIPULATORS
1357
1358 /// If there is a currently managed slot, call `disconnect` or
1359 /// `disconnectAndWait` on it, depending on the value of the
1360 /// `waitOnDisconnect` state. Make this connection refer to the same slot,
1361 /// if any, as the specified `rhs`, leaving `rhs` in the
1362 /// default-constructed state. Use the `waitOnDisconnect` state of `rhs`,
1363 /// indicating whether `disconnect()` or `disconnectAndWait()` will be
1364 /// called on the slot managed by this object upon destruction or
1365 /// assignment. Return `*this`. Throws nothing.
1367 operator=(bslmf::MovableRef<SignalerConnectionGuard> rhs)
1369
1370 /// Disassociate this guard from its associated slot, if any, and reset
1371 /// `*this` to a default-constructed state. Return a connection object
1372 /// referring to the slot, if any, that this guard was associated with
1373 /// prior to this call. Throws nothing.
1375
1376 /// Swap the contents of `*this` and the specified `other`. Throws
1377 /// nothing.
1379
1380 public:
1381 // ACCESSORS
1382
1383 /// Return a const reference to the connection held by this object. Throws
1384 /// nothing.
1385 const SignalerConnection& connection() const BSLS_KEYWORD_NOEXCEPT;
1386
1387 /// Return a `bool` that indicates the value that determines whether the
1388 /// slot, if any, managed by this object will be disconnected using
1389 /// `disconnect` or `disconnectAndWait`. Throws nothing.
1390 bool waitOnDisconnect() const BSLS_KEYWORD_NOEXCEPT;
1391};
1392
1393// FREE OPERATORS
1394
1395/// Return `true` if the specified `lhs` and `rhs` referring to the same slot
1396/// and `false` otherwise.
1397bool operator==(const SignalerConnection& lhs,
1398 const SignalerConnection& rhs);
1399
1400/// Return `false` if the specified `lhs` and `rhs` referring to the same slot
1401/// and `true` otherwise.
1402bool operator!=(const SignalerConnection& lhs,
1403 const SignalerConnection& rhs);
1404
1405/// Return `true` if the specified `lhs` is less than the specified `rhs` and
1406/// `false` otherwise.
1407bool operator<(const SignalerConnection& lhs,
1408 const SignalerConnection& rhs);
1409
1410/// Return `true` if the specified `lhs` is grater than the specified `rhs` and
1411/// `false` otherwise.
1412bool operator>(const SignalerConnection& lhs,
1413 const SignalerConnection& rhs);
1414
1415/// Return `true` if the specified `lhs` is less than or equal to the specified
1416/// `rhs` and `false` otherwise.
1417bool operator<=(const SignalerConnection& lhs,
1418 const SignalerConnection& rhs);
1419
1420/// Return `true` if the specified `lhs` is greater than or equal to the
1421/// specified `rhs` and `false` otherwise.
1422bool operator>=(const SignalerConnection& lhs,
1423 const SignalerConnection& rhs);
1424
1425// FREE FUNCTIONS
1426
1427/// Swap the contents of the specified `a` and `b`. Throws nothing.
1428void swap(SignalerConnection& a,
1430
1431/// Swap the contents of the specified `a` and `b`. Throws nothing.
1432void swap(SignalerConnectionGuard& a,
1434
1435// ============================================================================
1436// INLINE DEFINITIONS
1437// ============================================================================
1438
1439 // -------------------------
1440 // struct Signaler_Invocable
1441 // -------------------------
1442
1443template <class t_SIGNALER>
1444inline
1445void Signaler_Invocable<t_SIGNALER, void()>::operator()() const
1446{
1447 static_cast<const t_SIGNALER *>(this)->d_signalerNodePtr->invoke(
1456 Signaler_NotArg());
1457}
1458
1459template <class t_SIGNALER, class t_ARG1>
1460inline
1461void Signaler_Invocable<t_SIGNALER, void(t_ARG1)>::operator()(
1462 t_ARG1 arg1) const
1463{
1464 static_cast<const t_SIGNALER *>(this)->d_signalerNodePtr->invoke(
1473 Signaler_NotArg());
1474}
1475
1476template <class t_SIGNALER, class t_ARG1, class t_ARG2>
1477inline
1478void Signaler_Invocable<t_SIGNALER, void(t_ARG1, t_ARG2)>::operator()(
1479 t_ARG1 arg1,
1480 t_ARG2 arg2) const
1481{
1482 static_cast<const t_SIGNALER *>(this)->d_signalerNodePtr->invoke(
1491 Signaler_NotArg());
1492}
1493
1494template <class t_SIGNALER, class t_ARG1, class t_ARG2, class t_ARG3>
1495inline
1496void Signaler_Invocable<t_SIGNALER, void(t_ARG1, t_ARG2, t_ARG3)>::operator()(
1497 t_ARG1 arg1,
1498 t_ARG2 arg2,
1499 t_ARG3 arg3) const
1500{
1501 static_cast<const t_SIGNALER *>(this)->d_signalerNodePtr->invoke(
1510 Signaler_NotArg());
1511}
1512
1513template <class t_SIGNALER, class t_ARG1,
1514 class t_ARG2,
1515 class t_ARG3,
1516 class t_ARG4>
1517inline
1518void Signaler_Invocable<t_SIGNALER, void(t_ARG1,
1519 t_ARG2,
1520 t_ARG3,
1521 t_ARG4)>::operator()(
1522 t_ARG1 arg1,
1523 t_ARG2 arg2,
1524 t_ARG3 arg3,
1525 t_ARG4 arg4) const
1526{
1527 static_cast<const t_SIGNALER *>(this)->d_signalerNodePtr->invoke(
1536 Signaler_NotArg());
1537}
1538
1539template <class t_SIGNALER, class t_ARG1,
1540 class t_ARG2,
1541 class t_ARG3,
1542 class t_ARG4,
1543 class t_ARG5>
1544inline
1545void Signaler_Invocable<t_SIGNALER, void(t_ARG1,
1546 t_ARG2,
1547 t_ARG3,
1548 t_ARG4,
1549 t_ARG5)>::
1550 operator()(t_ARG1 arg1,
1551 t_ARG2 arg2,
1552 t_ARG3 arg3,
1553 t_ARG4 arg4,
1554 t_ARG5 arg5) const
1555{
1556 static_cast<const t_SIGNALER *>(this)->d_signalerNodePtr->invoke(
1565 Signaler_NotArg());
1566}
1567
1568template <class t_SIGNALER, class t_ARG1,
1569 class t_ARG2,
1570 class t_ARG3,
1571 class t_ARG4,
1572 class t_ARG5,
1573 class t_ARG6>
1574inline
1575void Signaler_Invocable<t_SIGNALER, void(t_ARG1,
1576 t_ARG2,
1577 t_ARG3,
1578 t_ARG4,
1579 t_ARG5,
1580 t_ARG6)>::
1581 operator()(t_ARG1 arg1,
1582 t_ARG2 arg2,
1583 t_ARG3 arg3,
1584 t_ARG4 arg4,
1585 t_ARG5 arg5,
1586 t_ARG6 arg6) const
1587{
1588 static_cast<const t_SIGNALER *>(this)->d_signalerNodePtr->invoke(
1597 Signaler_NotArg());
1598}
1599
1600template <class t_SIGNALER, class t_ARG1,
1601 class t_ARG2,
1602 class t_ARG3,
1603 class t_ARG4,
1604 class t_ARG5,
1605 class t_ARG6,
1606 class t_ARG7>
1607inline
1608void Signaler_Invocable<t_SIGNALER,
1609 void(t_ARG1,
1610 t_ARG2,
1611 t_ARG3,
1612 t_ARG4,
1613 t_ARG5,
1614 t_ARG6,
1615 t_ARG7)>::operator()(t_ARG1 arg1,
1616 t_ARG2 arg2,
1617 t_ARG3 arg3,
1618 t_ARG4 arg4,
1619 t_ARG5 arg5,
1620 t_ARG6 arg6,
1621 t_ARG7 arg7) const
1622{
1623 static_cast<const t_SIGNALER *>(this)->d_signalerNodePtr->invoke(
1632 Signaler_NotArg());
1633}
1634
1635template <class t_SIGNALER, class t_ARG1,
1636 class t_ARG2,
1637 class t_ARG3,
1638 class t_ARG4,
1639 class t_ARG5,
1640 class t_ARG6,
1641 class t_ARG7,
1642 class t_ARG8>
1643inline
1644void Signaler_Invocable<t_SIGNALER,
1645 void(t_ARG1,
1646 t_ARG2,
1647 t_ARG3,
1648 t_ARG4,
1649 t_ARG5,
1650 t_ARG6,
1651 t_ARG7,
1652 t_ARG8)>::operator()(t_ARG1 arg1,
1653 t_ARG2 arg2,
1654 t_ARG3 arg3,
1655 t_ARG4 arg4,
1656 t_ARG5 arg5,
1657 t_ARG6 arg6,
1658 t_ARG7 arg7,
1659 t_ARG8 arg8) const
1660{
1661 static_cast<const t_SIGNALER *>(this)->d_signalerNodePtr->invoke(
1670 Signaler_NotArg());
1671}
1672
1673template <class t_SIGNALER, class t_ARG1,
1674 class t_ARG2,
1675 class t_ARG3,
1676 class t_ARG4,
1677 class t_ARG5,
1678 class t_ARG6,
1679 class t_ARG7,
1680 class t_ARG8,
1681 class t_ARG9>
1682inline
1683void
1684Signaler_Invocable<t_SIGNALER, void(
1685 t_ARG1,
1686 t_ARG2,
1687 t_ARG3,
1688 t_ARG4,
1689 t_ARG5,
1690 t_ARG6,
1691 t_ARG7,
1692 t_ARG8,
1693 t_ARG9)>::operator()(t_ARG1 arg1,
1694 t_ARG2 arg2,
1695 t_ARG3 arg3,
1696 t_ARG4 arg4,
1697 t_ARG5 arg5,
1698 t_ARG6 arg6,
1699 t_ARG7 arg7,
1700 t_ARG8 arg8,
1701 t_ARG9 arg9) const
1702{
1703 static_cast<const t_SIGNALER *>(this)->d_signalerNodePtr->invoke(
1713}
1714
1715 // -----------------------
1716 // class Signaler_SlotNode
1717 // -----------------------
1718
1719// PRIVATE ACCESSORS
1720template <class t_PROT>
1721inline
1723 ForwardingNotArg,
1724 ForwardingNotArg,
1725 ForwardingNotArg,
1726 ForwardingNotArg,
1727 ForwardingNotArg,
1728 ForwardingNotArg,
1729 ForwardingNotArg,
1730 ForwardingNotArg,
1731 ForwardingNotArg) const
1732{
1733 d_func();
1734}
1735
1736template <class t_PROT>
1737inline
1738void Signaler_SlotNode<t_PROT>::doInvoke(
1740 typename ArgumentType::ForwardingType1 arg1,
1741 ForwardingNotArg,
1742 ForwardingNotArg,
1743 ForwardingNotArg,
1744 ForwardingNotArg,
1745 ForwardingNotArg,
1746 ForwardingNotArg,
1747 ForwardingNotArg,
1748 ForwardingNotArg) const
1749{
1750 // NOTE: Does not forward
1751
1752 d_func(arg1);
1753}
1754
1755template <class t_PROT>
1756inline
1757void Signaler_SlotNode<t_PROT>::doInvoke(
1759 typename ArgumentType::ForwardingType1 arg1,
1760 typename ArgumentType::ForwardingType2 arg2,
1761 ForwardingNotArg,
1762 ForwardingNotArg,
1763 ForwardingNotArg,
1764 ForwardingNotArg,
1765 ForwardingNotArg,
1766 ForwardingNotArg,
1767 ForwardingNotArg) const
1768{
1769 // NOTE: Does not forward
1770
1771 d_func(arg1, arg2);
1772}
1773
1774template <class t_PROT>
1775inline
1776void Signaler_SlotNode<t_PROT>::doInvoke(
1778 typename ArgumentType::ForwardingType1 arg1,
1779 typename ArgumentType::ForwardingType2 arg2,
1780 typename ArgumentType::ForwardingType3 arg3,
1781 ForwardingNotArg,
1782 ForwardingNotArg,
1783 ForwardingNotArg,
1784 ForwardingNotArg,
1785 ForwardingNotArg,
1786 ForwardingNotArg) const
1787{
1788 // NOTE: Does not forward
1789
1790 d_func(arg1, arg2, arg3);
1791}
1792
1793template <class t_PROT>
1794inline
1795void Signaler_SlotNode<t_PROT>::doInvoke(
1797 typename ArgumentType::ForwardingType1 arg1,
1798 typename ArgumentType::ForwardingType2 arg2,
1799 typename ArgumentType::ForwardingType3 arg3,
1800 typename ArgumentType::ForwardingType4 arg4,
1801 ForwardingNotArg,
1802 ForwardingNotArg,
1803 ForwardingNotArg,
1804 ForwardingNotArg,
1805 ForwardingNotArg) const
1806{
1807 // NOTE: Does not forward
1808
1809 d_func(arg1, arg2, arg3, arg4);
1810}
1811
1812template <class t_PROT>
1813inline
1814void Signaler_SlotNode<t_PROT>::doInvoke(
1816 typename ArgumentType::ForwardingType1 arg1,
1817 typename ArgumentType::ForwardingType2 arg2,
1818 typename ArgumentType::ForwardingType3 arg3,
1819 typename ArgumentType::ForwardingType4 arg4,
1820 typename ArgumentType::ForwardingType5 arg5,
1821 ForwardingNotArg,
1822 ForwardingNotArg,
1823 ForwardingNotArg,
1824 ForwardingNotArg) const
1825{
1826 // NOTE: Does not forward
1827
1828 d_func(arg1, arg2, arg3, arg4, arg5);
1829}
1830
1831template <class t_PROT>
1832inline
1833void Signaler_SlotNode<t_PROT>::doInvoke(
1835 typename ArgumentType::ForwardingType1 arg1,
1836 typename ArgumentType::ForwardingType2 arg2,
1837 typename ArgumentType::ForwardingType3 arg3,
1838 typename ArgumentType::ForwardingType4 arg4,
1839 typename ArgumentType::ForwardingType5 arg5,
1840 typename ArgumentType::ForwardingType6 arg6,
1841 ForwardingNotArg,
1842 ForwardingNotArg,
1843 ForwardingNotArg) const
1844{
1845 // NOTE: Does not forward
1846
1847 d_func(arg1, arg2, arg3, arg4, arg5, arg6);
1848}
1849
1850template <class t_PROT>
1851inline
1852void Signaler_SlotNode<t_PROT>::doInvoke(
1854 typename ArgumentType::ForwardingType1 arg1,
1855 typename ArgumentType::ForwardingType2 arg2,
1856 typename ArgumentType::ForwardingType3 arg3,
1857 typename ArgumentType::ForwardingType4 arg4,
1858 typename ArgumentType::ForwardingType5 arg5,
1859 typename ArgumentType::ForwardingType6 arg6,
1860 typename ArgumentType::ForwardingType7 arg7,
1861 ForwardingNotArg,
1862 ForwardingNotArg) const
1863{
1864 // NOTE: Does not forward
1865
1866 d_func(arg1, arg2, arg3, arg4, arg5, arg6, arg7);
1867}
1868
1869template <class t_PROT>
1870inline
1871void Signaler_SlotNode<t_PROT>::doInvoke(
1873 typename ArgumentType::ForwardingType1 arg1,
1874 typename ArgumentType::ForwardingType2 arg2,
1875 typename ArgumentType::ForwardingType3 arg3,
1876 typename ArgumentType::ForwardingType4 arg4,
1877 typename ArgumentType::ForwardingType5 arg5,
1878 typename ArgumentType::ForwardingType6 arg6,
1879 typename ArgumentType::ForwardingType7 arg7,
1880 typename ArgumentType::ForwardingType8 arg8,
1881 ForwardingNotArg) const
1882{
1883 // NOTE: Does not forward
1884
1885 d_func(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
1886}
1887
1888template <class t_PROT>
1889inline
1890void Signaler_SlotNode<t_PROT>::doInvoke(
1892 typename ArgumentType::ForwardingType1 arg1,
1893 typename ArgumentType::ForwardingType2 arg2,
1894 typename ArgumentType::ForwardingType3 arg3,
1895 typename ArgumentType::ForwardingType4 arg4,
1896 typename ArgumentType::ForwardingType5 arg5,
1897 typename ArgumentType::ForwardingType6 arg6,
1898 typename ArgumentType::ForwardingType7 arg7,
1899 typename ArgumentType::ForwardingType8 arg8,
1900 typename ArgumentType::ForwardingType9 arg9) const
1901{
1902 // NOTE: Does not forward
1903
1904 d_func(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
1905}
1906
1907// CREATORS
1908template <class t_PROT>
1909template <class t_FUNC>
1911 const bsl::weak_ptr<SignalerNode>& signalerNodePtr,
1913 SlotMapKey slotMapKey,
1914 bslma::Allocator *allocator)
1915: d_slotMapKey(slotMapKey)
1916, d_isConnected(true)
1917, d_signalerNodePtr(signalerNodePtr)
1918, d_func(bsl::allocator_arg,
1919 allocator,
1920 BSLS_COMPILERFEATURES_FORWARD(t_FUNC, func))
1921{
1922 BSLS_ASSERT(!signalerNodePtr.expired());
1923 BSLS_ASSERT(allocator);
1924}
1925
1926// MANIPULATORS
1927template <class t_PROT>
1928inline
1930{
1931 if (!d_isConnected.testAndSwap(true, false)) {
1932 return; // RETURN
1933 }
1934
1935 // Notify the associated signaler
1936
1937 bsl::shared_ptr<SignalerNode> signalerNodePtr = d_signalerNodePtr.lock();
1938 if (signalerNodePtr) {
1939 signalerNodePtr->notifyDisconnected(d_slotMapKey);
1940 }
1941}
1942
1943template <class t_PROT>
1944inline
1946{
1947 const bool wasConnected = d_isConnected.testAndSwap(true, false);
1948
1949 // Notify the associated signaler
1950
1951 bsl::shared_ptr<SignalerNode> signalerNodePtr = d_signalerNodePtr.lock();
1952 if (signalerNodePtr) {
1953 if (wasConnected) {
1954 signalerNodePtr->notifyDisconnected(d_slotMapKey);
1955 }
1956
1957 // Synchronize with the call operator.
1958
1959 signalerNodePtr->synchronizeWait();
1960 }
1961}
1962
1963template <class t_PROT>
1964inline
1966{
1967 d_isConnected = false;
1968}
1969
1970// ACCESSORS
1971template <class t_PROT>
1972inline
1974 typename ArgumentType::ForwardingType1 arg1,
1975 typename ArgumentType::ForwardingType2 arg2,
1976 typename ArgumentType::ForwardingType3 arg3,
1977 typename ArgumentType::ForwardingType4 arg4,
1978 typename ArgumentType::ForwardingType5 arg5,
1979 typename ArgumentType::ForwardingType6 arg6,
1980 typename ArgumentType::ForwardingType7 arg7,
1981 typename ArgumentType::ForwardingType8 arg8,
1982 typename ArgumentType::ForwardingType9 arg9) const
1983{
1984 // The only way we are called is from a 'Signaler', which should exist
1985 // throughout the call and be holding a shared ptr to the 'Signaler_Node'.
1986
1987 BSLS_ASSERT(!d_signalerNodePtr.expired());
1988
1989 if (!d_isConnected) {
1990 // The slot was evidently disconnected by another thread. Do nothing.
1991
1992 return; // RETURN
1993 }
1994
1996
1998 arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
1999}
2000
2001template <class t_PROT>
2002inline
2004{
2005 return d_isConnected;
2006}
2007
2008 // -------------------
2009 // class Signaler_Node
2010 // -------------------
2011
2012// CREATORS
2013template <class t_PROT>
2015: d_signalerMutex()
2016, d_slotMap(allocator)
2017, d_keyId(0)
2018{
2019 BSLS_ASSERT(allocator);
2020}
2021
2022// MANIPULATORS
2023template <class t_PROT>
2024inline
2026 typename ArgumentType::ForwardingType1 arg1,
2027 typename ArgumentType::ForwardingType2 arg2,
2028 typename ArgumentType::ForwardingType3 arg3,
2029 typename ArgumentType::ForwardingType4 arg4,
2030 typename ArgumentType::ForwardingType5 arg5,
2031 typename ArgumentType::ForwardingType6 arg6,
2032 typename ArgumentType::ForwardingType7 arg7,
2033 typename ArgumentType::ForwardingType8 arg8,
2034 typename ArgumentType::ForwardingType9 arg9) const
2035{
2036 // Hold this mutex (in read mode), so that disconnects in 'wait' mode can
2037 // synchronize with the call operator by momentarily locking it for write.
2038
2040
2041 // 'slotHandle' points in to a node in the skiplist, which has a reference
2042 // count to prevent it from being deallocated & destroyed by another thread
2043 // as long as we have 'slotHandle' referring to it. The node may be
2044 // removed from the skip list, though, in which case its 'next' pointers
2045 // will be null.
2046
2047 SlotPairHandle slotHandle;
2048 if (d_slotMap.front(&slotHandle) != 0) {
2049 // No slots. Do nothing.
2050
2051 return; // RETURN
2052 }
2053
2054 do {
2055 const SlotNode *slotNodePtr = &*slotHandle.data();
2056 const SlotMapKey slotMapKey = slotHandle.key();
2057
2058 // invoke the slot
2059
2060 slotNodePtr->invoke(
2061 arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
2062
2063 if (0 != d_slotMap.skipForward(&slotHandle)) {
2064 // 'slot' has been removed from the skip list and we can't use the
2065 // 'next' pointers to get to the next node, but we can still access
2066 // 'slotMapKey' to tell us where we were and directly look up the
2067 // next slot after that.
2068
2069 if (0 != d_slotMap.findUpperBound(&slotHandle, slotMapKey)) {
2070 // No slots left. We're done.
2071
2072 return; // RETURN
2073 }
2074 }
2075 } while (slotHandle);
2076}
2077
2078template <class t_PROT>
2079template <class t_FUNC>
2082 int group)
2083{
2084 // create a key the slot will be indexed by
2085
2086 const SlotMapKey slotMapKey(group, ++d_keyId);
2087
2088 // create a slot
2089
2090 bsl::shared_ptr<SlotNode> slotNodePtr = bsl::allocate_shared<SlotNode>(
2091 d_slotMap.allocator(),
2092 this->weak_from_this(),
2093 BSLS_COMPILERFEATURES_FORWARD(t_FUNC, func),
2094 slotMapKey,
2095 d_slotMap.allocator());
2096
2097 // connect the slot
2098
2099 d_slotMap.addR(slotMapKey, slotNodePtr);
2100
2101 // return the connection
2102
2103 return SignalerConnection(slotNodePtr);
2104
2105}
2106
2107template <class t_PROT>
2109{
2110 SlotPairHandle slotHandle;
2111
2112 // disconnect all slots in the collection, one by one
2113
2114 while (d_slotMap.front(&slotHandle) == 0) {
2115 // notify the slot it's being disconnected
2116
2117 slotHandle.data()->notifyDisconnected();
2118
2119 // remove the slot from the collection
2120
2121 d_slotMap.remove(slotHandle);
2122 }
2123}
2124
2125template <class t_PROT>
2127{
2128 disconnectAllSlots();
2129 synchronizeWait();
2130}
2131
2132template <class t_PROT>
2134{
2135 // 'skipForward', below, may fail if a node is removed from the list while
2136 // we're visiting it, in which case we have to go back to the front and
2137 // start over.
2138
2139 SlotPairHandle slotHandle;
2140 const SlotMapKey boundary(group, 0);
2141 while (0 == d_slotMap.findLowerBound(&slotHandle, boundary) &&
2142 slotHandle.key().first == group) {
2143 do {
2144 // notify the slot it's being disconnected
2145
2146 slotHandle.data()->notifyDisconnected();
2147
2148 SlotPairHandle condemned(slotHandle);
2149
2150 if (0 != d_slotMap.skipForward(&slotHandle)) {
2151 slotHandle.release();
2152 }
2153
2154 // remove the slot from the collection
2155
2156 d_slotMap.remove(condemned);
2157 } while (slotHandle && slotHandle.key().first == group);
2158 }
2159}
2160
2161template <class t_PROT>
2163 int group) BSLS_KEYWORD_NOEXCEPT
2164{
2165 disconnectGroup(group);
2166 synchronizeWait();
2167}
2168
2169template <class t_PROT>
2172{
2173 typename KeyToSlotMap::PairHandle slotHandle;
2174
2175 if (d_slotMap.find(&slotHandle, slotMapKey) != 0) {
2176 // Slot was already removed, probably by some form of 'disconnect*'
2177 // called on the 'Signaler'. Do nothing.
2178
2179 return; // RETURN
2180 }
2181
2182 // remove the slot from the collection
2183
2184 d_slotMap.remove(slotHandle);
2185}
2186
2187template <class t_PROT>
2188inline
2193
2194// ACCESSORS
2195template <class t_PROT>
2196inline
2198{
2199 return d_slotMap.length();
2200}
2201
2202 // --------------
2203 // class Signaler
2204 // --------------
2205
2206// CREATORS
2207template <class t_PROT>
2209: d_signalerNodePtr(bsl::allocate_shared<Signaler_Node<t_PROT> >(
2210 basicAllocator,
2211 bslma::Default::allocator(basicAllocator)))
2212{
2213 // NOTHING
2214}
2215
2216template <class t_PROT>
2217inline
2219{
2220 d_signalerNodePtr->disconnectAllSlots();
2221}
2222
2223// MANIPULATORS
2224template <class t_PROT>
2225template <class t_FUNC>
2226inline
2229 int group)
2230{
2231 return d_signalerNodePtr->connect(BSLS_COMPILERFEATURES_FORWARD(t_FUNC,
2232 func),
2233 group);
2234}
2235
2236template <class t_PROT>
2237inline
2239{
2240 d_signalerNodePtr->disconnectAllSlots();
2241}
2242
2243template <class t_PROT>
2244inline
2246{
2247 d_signalerNodePtr->disconnectAllSlotsAndWait();
2248}
2249
2250template <class t_PROT>
2251inline
2253{
2254 d_signalerNodePtr->disconnectGroup(group);
2255}
2256
2257template <class t_PROT>
2258inline
2260{
2261 d_signalerNodePtr->disconnectGroupAndWait(group);
2262}
2263
2264// ACCESSORS
2265template <class t_PROT>
2266inline
2268{
2269 return d_signalerNodePtr->slotCount();
2270}
2271
2272 // ------------------------
2273 // class SignalerConnection
2274 // ------------------------
2275
2276// MANIPULATORS
2277inline
2279{
2280 d_slotNodeBasePtr.swap(other.d_slotNodeBasePtr);
2281}
2282
2283// FREE OPERATORS
2284inline
2285bool operator==(const SignalerConnection& lhs, const SignalerConnection& rhs)
2286{
2287 return lhs.d_slotNodeBasePtr.rep() == rhs.d_slotNodeBasePtr.rep();
2288}
2289
2290inline
2291bool operator<( const SignalerConnection& lhs, const SignalerConnection& rhs)
2292{
2293 return lhs.d_slotNodeBasePtr.owner_before(rhs.d_slotNodeBasePtr);
2294}
2295
2296// FREE FUNCTIONS
2297inline
2300{
2301 a.swap(b);
2302}
2303
2304 // -----------------------------
2305 // class SignalerConnectionGuard
2306 // -----------------------------
2307
2308// ACCESSORS
2309inline
2312{
2313 return d_connection;
2314}
2315
2316inline
2318{
2319 return d_waitOnDisconnect;
2320}
2321
2322// FREE FUNCTIONS
2323inline
2326{
2327 a.swap(b);
2328}
2329
2330} // close package namespace
2331
2332
2333#endif
2334
2335// ----------------------------------------------------------------------------
2336// NOTICE:
2337// Copyright (C) Bloomberg L.P., 2019
2338// All Rights Reserved.
2339// Property of Bloomberg L.P. (BLP)
2340// This software is made available solely pursuant to the
2341// terms of a BLP license agreement which governs its use.
2342// ----------------------------- END-OF-FILE ----------------------------------
2343
2344
2345/** @} */
2346/** @} */
2347/** @} */
#define BSLMF_NESTED_TRAIT_DECLARATION(t_TYPE, t_TRAIT)
Definition bslmf_nestedtraitdeclaration.h:231
Definition bdlcc_skiplist.h:804
SkipListPairHandle< SlotMapKey, bsl::shared_ptr< SlotNode > > PairHandle
Definition bdlcc_skiplist.h:828
Definition bdlmt_signaler.h:1291
bool waitOnDisconnect() const BSLS_KEYWORD_NOEXCEPT
Definition bdlmt_signaler.h:2317
const SignalerConnection & connection() const BSLS_KEYWORD_NOEXCEPT
Definition bdlmt_signaler.h:2310
SignalerConnectionGuard(bslmf::MovableRef< SignalerConnection > connection, bool waitOnDisconnect=false) BSLS_KEYWORD_NOEXCEPT
SignalerConnectionGuard(const SignalerConnection &connection, bool waitOnDisconnect=false)
BSLMF_NESTED_TRAIT_DECLARATION(SignalerConnectionGuard, bslmf::IsBitwiseMoveable)
Definition bdlmt_signaler.h:1171
SignalerConnection(bslmf::MovableRef< SignalerConnection > original) BSLS_KEYWORD_NOEXCEPT
SignalerConnection & operator=(bslmf::MovableRef< SignalerConnection > rhs) BSLS_KEYWORD_NOEXCEPT
SignalerConnection()
Create a SignalerConnection object having no associated slot.
void reset() BSLS_KEYWORD_NOEXCEPT
SignalerConnection & operator=(const SignalerConnection &rhs)
SignalerConnection(const SignalerConnection &original) BSLS_KEYWORD_NOEXCEPT
void swap(SignalerConnection &other) BSLS_KEYWORD_NOEXCEPT
Definition bdlmt_signaler.h:2278
Definition bdlmt_signaler.h:830
SignalerConnection connect(BSLS_COMPILERFEATURES_FORWARD_REF(t_FUNC) slot, int group)
Definition bdlmt_signaler.h:2080
void synchronizeWait() BSLS_KEYWORD_NOEXCEPT
Definition bdlmt_signaler.h:2189
void disconnectGroup(int group) BSLS_KEYWORD_NOEXCEPT
Definition bdlmt_signaler.h:2133
void disconnectAllSlots() BSLS_KEYWORD_NOEXCEPT
Definition bdlmt_signaler.h:2108
void notifyDisconnected(SlotMapKey slotMapKey) BSLS_KEYWORD_NOEXCEPT
Definition bdlmt_signaler.h:2170
void disconnectGroupAndWait(int group) BSLS_KEYWORD_NOEXCEPT
Definition bdlmt_signaler.h:2162
void invoke(typename ArgumentType::ForwardingType1 arg1, typename ArgumentType::ForwardingType2 arg2, typename ArgumentType::ForwardingType3 arg3, typename ArgumentType::ForwardingType4 arg4, typename ArgumentType::ForwardingType5 arg5, typename ArgumentType::ForwardingType6 arg6, typename ArgumentType::ForwardingType7 arg7, typename ArgumentType::ForwardingType8 arg8, typename ArgumentType::ForwardingType9 arg9) const
Definition bdlmt_signaler.h:2025
void disconnectAllSlotsAndWait() BSLS_KEYWORD_NOEXCEPT
Definition bdlmt_signaler.h:2126
bsl::size_t slotCount() const
Definition bdlmt_signaler.h:2197
Definition bdlmt_signaler.h:554
virtual ~Signaler_SlotNode_Base()
Virtual d'tor.
virtual bool isConnected() const =0
virtual void disconnectAndWait() BSLS_KEYWORD_NOEXCEPT=0
virtual void disconnect() BSLS_KEYWORD_NOEXCEPT=0
Definition bdlmt_signaler.h:602
void disconnectAndWait() BSLS_KEYWORD_NOEXCEPT BSLS_KEYWORD_OVERRIDE
Definition bdlmt_signaler.h:1945
bsl::pair< int, unsigned > SlotMapKey
Definition bdlmt_signaler.h:616
void notifyDisconnected() BSLS_KEYWORD_NOEXCEPT
Definition bdlmt_signaler.h:1965
void invoke(typename ArgumentType::ForwardingType1 arg1, typename ArgumentType::ForwardingType2 arg2, typename ArgumentType::ForwardingType3 arg3, typename ArgumentType::ForwardingType4 arg4, typename ArgumentType::ForwardingType5 arg5, typename ArgumentType::ForwardingType6 arg6, typename ArgumentType::ForwardingType7 arg7, typename ArgumentType::ForwardingType8 arg8, typename ArgumentType::ForwardingType9 arg9) const
Definition bdlmt_signaler.h:1973
void disconnect() BSLS_KEYWORD_NOEXCEPT BSLS_KEYWORD_OVERRIDE
Definition bdlmt_signaler.h:1929
bool isConnected() const BSLS_KEYWORD_OVERRIDE
Definition bdlmt_signaler.h:2003
~Signaler_SlotNode()=default
Destroy this object.
Definition bdlmt_signaler.h:1000
SignalerConnection connect(BSLS_COMPILERFEATURES_FORWARD_REF(t_FUNC) slot, int group=0)
Definition bdlmt_signaler.h:2227
void disconnectGroupAndWait(int group) BSLS_KEYWORD_NOEXCEPT
Definition bdlmt_signaler.h:2259
void disconnectGroup(int group) BSLS_KEYWORD_NOEXCEPT
Definition bdlmt_signaler.h:2252
void disconnectAllSlots() BSLS_KEYWORD_NOEXCEPT
Definition bdlmt_signaler.h:2238
void disconnectAllSlotsAndWait() BSLS_KEYWORD_NOEXCEPT
Definition bdlmt_signaler.h:2245
void ResultType
Definition bdlmt_signaler.h:1004
~Signaler()
Definition bdlmt_signaler.h:2218
bsl::size_t slotCount() const
Definition bdlmt_signaler.h:2267
Forward declaration.
Definition bslstl_function.h:946
Definition bslstl_pair.h:1280
Definition bslstl_sharedptr.h:1838
Definition bslstl_sharedptr.h:3773
void swap(weak_ptr &other) BSLS_KEYWORD_NOEXCEPT
Definition bslstl_sharedptr.h:6004
bool expired() const BSLS_KEYWORD_NOEXCEPT
Definition bslstl_sharedptr.h:6025
Definition bslma_allocator.h:545
Provide a namespace for the forwardToTarget function.
Definition bslmf_forwardingtype.h:456
Imp::Type Type
Definition bslmf_forwardingtype.h:441
Definition bslmf_movableref.h:752
Definition bslmt_readlockguard.h:287
Definition bslmt_readerwritermutex.h:244
Definition bslmt_writelockguard.h:221
Definition bsls_atomic.h:1490
bool testAndSwap(bool compareValue, bool swapValue)
Definition bsls_atomic.h:2500
Definition bsls_atomic.h:1050
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1976
#define BSLS_COMPILERFEATURES_FORWARD_REF(T)
Definition bsls_compilerfeatures.h:2343
#define BSLS_COMPILERFEATURES_FORWARD(T, V)
Definition bsls_compilerfeatures.h:2349
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
#define BSLS_KEYWORD_DELETED
Definition bsls_keyword.h:651
#define BSLS_KEYWORD_NOEXCEPT
Definition bsls_keyword.h:674
#define BSLS_KEYWORD_OVERRIDE
Definition bsls_keyword.h:695
Definition bdlmt_eventscheduler.h:550
Definition bdlat_valuetypefunctions.h:939
Definition baljsn_encoder_testtypes.h:76
Definition bdlbb_blob.h:579
Definition bdlmt_signaler.h:316
Forward< 5 >::Type ForwardingType5
Definition bdlmt_signaler.h:340
Forward< 6 >::Type ForwardingType6
Definition bdlmt_signaler.h:341
Forward< 4 >::Type ForwardingType4
Definition bdlmt_signaler.h:339
Forward< 9 >::Type ForwardingType9
Definition bdlmt_signaler.h:344
Forward< 3 >::Type ForwardingType3
Definition bdlmt_signaler.h:338
bslmf::ForwardingType< Signaler_NotArg >::Type ForwardingNotArg
Definition bdlmt_signaler.h:334
Forward< 1 >::Type ForwardingType1
Definition bdlmt_signaler.h:336
Forward< 2 >::Type ForwardingType2
Definition bdlmt_signaler.h:337
Forward< 7 >::Type ForwardingType7
Definition bdlmt_signaler.h:342
Forward< 8 >::Type ForwardingType8
Definition bdlmt_signaler.h:343
Definition bdlmt_signaler.h:356
Definition bdlmt_signaler.h:292
Definition bslmf_integralconstant.h:261
Definition bslma_usesbslmaallocator.h:344
Definition bslmf_functionpointertraits.h:147
Definition bslmf_isbitwisemoveable.h:718
Definition bslmf_typelist.h:1631