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