HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
notice.h
Go to the documentation of this file.
1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the terms set forth in the LICENSE.txt file available at
5 // https://openusd.org/license.
6 //
7 #ifndef PXR_BASE_TF_NOTICE_H
8 #define PXR_BASE_TF_NOTICE_H
9 
10 /// \file tf/notice.h
11 /// \ingroup group_tf_Notification
12 
13 #include "pxr/pxr.h"
14 #include "pxr/base/tf/api.h"
15 #include "pxr/base/tf/anyWeakPtr.h"
16 #include "pxr/base/tf/diagnostic.h"
17 #include "pxr/base/tf/mallocTag.h"
18 #include "pxr/base/tf/scoped.h"
19 #include "pxr/base/tf/type.h"
20 #include "pxr/base/tf/weakPtr.h"
21 #include "pxr/base/arch/demangle.h"
22 #include "pxr/base/arch/hints.h"
23 
24 #include <atomic>
25 #include <list>
26 #include <optional>
27 #include <typeinfo>
28 
30 
31 class Tf_NoticeRegistry;
32 
33 /// \class TfNotice
34 /// \ingroup group_tf_Notification
35 ///
36 /// The base class for objects used to notify interested parties (listeners)
37 /// when events have occurred. The TfNotice class also serves as a container
38 /// for various dispatching routines such as Register() and Send().
39 ///
40 /// See \ref page_tf_Notification in the C++ API reference for a detailed
41 /// description of the notification system.
42 ///
43 /// \section pycode_TfNotice Python Example: Registering For and Sending
44 /// Notices The following code provides examples of how to set up a Notice
45 /// listener connection (represented in Python by the Listener class),
46 /// including creating and sending notices, registering to receive notices,
47 /// and breaking a listener connection.
48 /// \code{.py}
49 /// # To create a new notice type:
50 /// class APythonClass(Tf.Notice):
51 /// '''TfNotice sent when APythonClass does something of interest.'''
52 /// pass
53 /// Tf.Type.Define(APythonClass)
54 ///
55 /// # An interested listener can register to receive notices from all
56 /// # senders, or from a particular type of sender.
57 ///
58 /// # To send a notice to all registered listeners:;
59 /// APythonClass().SendGlobally()
60 ///
61 /// # To send a notice to listeners who register with a specific sender:
62 /// APythonClass().Send(self)
63 ///
64 /// # To register for the notice from any sender:
65 /// my_listener = Tf.Notice.RegisterGlobally(APythonClass, self._HandleNotice)
66 ///
67 /// # To register for the notice from a specific sender
68 /// my_listener = Tf.Notice.Register(APythonClass, self._HandleNotice, sender)
69 ///
70 /// def _HandleNotice(self, notice, sender):
71 /// '''callback function for handling a notice'''
72 /// # do something when the notice arrives
73 ///
74 /// # To revoke interest in a notice
75 /// my_listener.Revoke()
76 /// \endcode
77 ///
78 /// For more on using notices in Python, see the Editor With Notices tutorial.
79 ///
80 class TfNotice {
81 private:
82  class _DelivererBase;
84  typedef std::list<_DelivererBase*> _DelivererList;
85 
86  ////////////////////////////////////////////////////////////////////////
87  // Per-sender delivery, listener gets sender.
88  template <class LPtr, class L,
89  class Notice, class SPtr, class DeliveredSPtr>
90  static _DelivererBase *
91  _MakeDeliverer(LPtr const &listener,
92  void (L::*method)
93  (const Notice &, DeliveredSPtr const &),
94  SPtr const &sender) {
95  DeliveredSPtr weakSender(sender);
96  return new _DelivererWithSender<
97  LPtr, DeliveredSPtr,
98  void (L::*)(const Notice &, DeliveredSPtr const &),
99  Notice
100  >(listener, method, weakSender);
101  }
102 
103  template <class LPtr, class L,
104  class Notice, class SPtr, class DeliveredSPtr>
105  static _DelivererBase *
106  _MakeDeliverer(LPtr const &listener,
107  void (L::*method)
108  (const Notice &, DeliveredSPtr const &) const,
109  SPtr const &sender) {
110  DeliveredSPtr weakSender(sender);
111  return new _DelivererWithSender<
112  LPtr, DeliveredSPtr,
113  void (L::*)(const Notice &, DeliveredSPtr const &) const,
114  Notice
115  >(listener, method, weakSender);
116  }
117 
118  ////////////////////////////////////////////////////////////////////////
119  // Per-sender delivery, listener does not get sender.
120  template <class LPtr, class L, class SPtr, class Notice>
121  static _DelivererBase *
122  _MakeDeliverer(LPtr const &listener,
123  void (L::*method)(const Notice &),
124  SPtr const &sender) {
125  return new _Deliverer<
126  LPtr, SPtr, void (L::*)(const Notice &), Notice
127  >(listener, method, sender);
128  }
129 
130  template <class LPtr, class L, class SPtr, class Notice>
131  static _DelivererBase *
132  _MakeDeliverer(LPtr const &listener,
133  void (L::*method)(const Notice &) const,
134  SPtr const &sender) {
135  return new _Deliverer<
136  LPtr, SPtr, void (L::*)(const Notice &) const, Notice
137  >(listener, method, sender);
138  }
139 
140  ////////////////////////////////////////////////////////////////////////
141  // Global delivery.
142  template <class LPtr, class L, class Notice>
143  static _DelivererBase *
144  _MakeDeliverer(LPtr const &listener,
145  void (L::*method)(const Notice &)) {
146  return new _Deliverer<
147  LPtr, TfAnyWeakPtr, void (L::*)(const Notice &), Notice
148  >(listener, method);
149  }
150 
151  template <class LPtr, class L, class Notice>
152  static _DelivererBase *
153  _MakeDeliverer(LPtr const &listener,
154  void (L::*method)(const Notice &) const) {
155  return new _Deliverer<
156  LPtr, TfAnyWeakPtr, void (L::*)(const Notice &) const, Notice
157  >(listener, method);
158  }
159 
160  ////////////////////////////////////////////////////////////////////////
161  // Generic (raw) delivery.
162  template <class LPtr, class L>
163  static _DelivererBase *
164  _MakeDeliverer(TfType const &noticeType,
165  LPtr const &listener,
166  void (L::*method)(const TfNotice &,
167  const TfType &,
168  TfWeakBase*, const void *,
169  const std::type_info&),
170  TfAnyWeakPtr const &sender) {
171  return new _RawDeliverer<LPtr,
172  void (L::*)(const TfNotice &, const TfType &,
173  TfWeakBase *, const void *,
174  const std::type_info &)>
175  (listener, method, sender, noticeType);
176  }
177 
178  template <class LPtr, class L>
179  static _DelivererBase *
180  _MakeDeliverer(TfType const &noticeType,
181  LPtr const &listener,
182  void (L::*method)(const TfNotice &,
183  const TfType &,
184  TfWeakBase*, const void *,
185  const std::type_info&) const,
186  TfAnyWeakPtr const &sender)
187  {
188  return new _RawDeliverer<LPtr,
189  void (L::*)(const TfNotice &, const TfType &,
190  TfWeakBase *, const void *,
191  const std::type_info &) const>
192  (listener, method, sender, noticeType);
193  }
194 
195 
196 
197 public:
198 
199  class Probe;
201 
202  /// Probe interface class which may be implemented and then registered via
203  /// \c InsertProbe to introspect about notices as they are sent and
204  /// delivered.
205  class Probe : public TfWeakBase {
206  public:
207  TF_API
208  virtual ~Probe() = 0;
209 
210  /// This method is called just before \p notice is sent to any
211  /// listeners. \p sender is NULL if \p notice is sent globally. In
212  /// this case, \p senderType will be typeid(void).
213  virtual void BeginSend(const TfNotice &notice,
214  const TfWeakBase *sender,
215  const std::type_info &senderType) = 0;
216 
217  /// This method is called after the notice in the corresponding \c
218  /// BeginSend call has been delivered to all listeners.
219  virtual void EndSend() = 0;
220 
221  /// This method is called just before \p notice is
222  /// delivered to a listener. \p sender is NULL if \p notice is
223  /// sent globally or the listener is global. In this case, \p
224  /// senderType will be typeid(void).
225  virtual void BeginDelivery(const TfNotice &notice,
226  const TfWeakBase *sender,
227  const std::type_info &senderType,
228  const TfWeakBase *listener,
229  const std::type_info &listenerType) = 0;
230 
231  /// This method is called after the notice in the
232  /// corresponding \c BeginDelivery call has finished being
233  /// processed by its listener.
234  virtual void EndDelivery() = 0;
235  };
236 
237  /// Handle-object returned by \c TfNotice::Register().
238  ///
239  /// When a listener is registered by \c TfNotice::Register(), an object of
240  /// type \c TfNotice::Key is returned; this key object can be given to \c
241  /// Revoke() to subsequently unregister the listener with respect to that
242  /// particular notice type and callback method.
243  class Key {
244  public:
245  Key() {}
246 
247  /// Does this key refer to a valid notification?
248  ///
249  /// \c IsValid will return true if this key refers to a currently
250  /// active notification. Revoking the key will make it invalid again.
251  bool IsValid() const {
252  return _deliverer && _deliverer->_IsActive();
253  }
254 
255  /// Does this key refer to a valid notification?
256  ///
257  /// The boolean operator is identical to \c IsValid() above.
258  operator bool() const {
259  return IsValid();
260  }
261 
262  private:
263  Key(const _DelivererWeakPtr & d) : _deliverer(d) {}
264 
265  _DelivererWeakPtr _deliverer;
266 
267  friend class Tf_NoticeRegistry;
268  friend class TfNotice;
269  };
270 
271  /// A \c TfNotice::Key container.
272  ///
273  /// Many listeners listen for several notices and must revoke interest for
274  /// those several notices at once. These listeners can put all of the
275  /// keys into a \c TfNotice::Keys then call \c Revoke() on it.
276  typedef std::vector<Key> Keys;
277 
278  /// Register a probe that will be invoked when notices are sent and
279  /// delivered.
280  /// \see TfNotice::Probe
281  TF_API
282  static void InsertProbe(const WeakProbePtr &probe);
283 
284  /// Remove a probe that was previously registered with \c InsertProbe.
285  /// \see TfNotice::Probe
286  TF_API
287  static void RemoveProbe(const WeakProbePtr &probe);
288 
289  /// Register a listener as being interested in a \c TfNotice.
290  ///
291  /// Registration of interest in a notice class \c N automatically
292  /// registers interest in all classes derived from \c N. When a notice of
293  /// appropriate type is received, the listening object's member-function
294  /// \p method is called with the notice.
295  ///
296  /// Supports several forms of registration.
297  ///
298  /// - Listening for a notice from a particular sender.
299  ///
300  /// \code
301  /// // Listener does not receive sender.
302  /// void Listener::_HandleNotice(SomeNotice const &notice) [const];
303  /// Register(listenerPtr, &Listener::_HandleNotice, senderPtr);
304  ///
305  /// // Listener receives sender.
306  /// void Listener::_HandleNoticeSender(SomeNotice const &notice,
307  /// SenderPtr const &sender) [const];
308  /// Register(listenerPtr, &Listener::_HandleNoticeSender, senderPtr);
309  /// \endcode
310  ///
311  /// - Listening for a notice globally. Prefer listening to a notice from a
312  /// particular sender whenever possible (as above).
313  ///
314  /// \code
315  /// void Listener::_HandleGlobalNotice(SomeNotice const &notice) [const];
316  /// Register(listenerPtr, &Listener::_HandleGlobalNotice);
317  /// \endcode
318  ///
319  /// - Listening for a notice dynamically, with a type that is unknown at
320  /// compile-time. This facility is used for some internal mechanisms,
321  /// such as bridging notice delivery into Python, and is not meant for
322  /// public consumption.
323  ///
324  /// \code
325  /// void Listener::_HandleGenericNotice(TfNotice const &notice,
326  /// TfType const &noticeType,
327  /// TfWeakBase *sender,
328  /// void const *senderUniqueId,
329  /// std::type_info const &senderType)
330  /// [const];
331  /// Register(listenerPtr,
332  /// &Listener::_HandleGenericNotice, noticeType, senderPtr);
333  /// \endcode
334  ///
335  /// The listener being registered must be pointed to by a \c
336  /// TfWeakPtrFacade, like a TfWeakPtr or another TfWeakPtrFacade-based
337  /// Handle. The sender being registered for (if any) must also be pointed
338  /// to by a \c TfWeakPtrFacade.
339  ///
340  /// Note that the notification center only holds onto the listening object
341  /// via a \c TfWeakPtr. That is, it does not influence the lifetime of
342  /// that object.
343  ///
344  /// To reverse the registration, call \c Key::Revoke() on the \c Key
345  /// object returned by this call.
346  template <class LPtr, class MethodPtr>
347  static TfNotice::Key
348  Register(LPtr const &listener, MethodPtr method) {
349  TfAutoMallocTag tag("Tf", "Tf_NoticeRegistry::_Register");
350  return _Register(_MakeDeliverer(listener, method));
351  }
352 
353  template <class LPtr, class MethodPtr, class SenderPtr>
354  static TfNotice::Key
355  Register(LPtr const &listener, MethodPtr method, SenderPtr const &sender) {
356  TfAutoMallocTag tag("Tf", "Tf_NoticeRegistry::_Register");
357  return _Register(_MakeDeliverer(listener, method, sender));
358  }
359 
360  template <class LPtr, class MethodPtr>
361  static TfNotice::Key
362  Register(LPtr const &listener, MethodPtr method,
363  const TfType &noticeType, const TfAnyWeakPtr &sender) {
364  TfAutoMallocTag tag("Tf", "Tf_NoticeRegistry::_Register");
365  return _Register(_MakeDeliverer(noticeType, listener, method, sender));
366  }
367 
368  /// Revoke interest by a listener.
369  ///
370  /// This revokes interest by the listener for the particular notice type
371  /// and call-back method for which this key was created.
372  ///
373  /// \c Revoke will return a bool value indicating whether or not the key
374  /// was successfully revoked. Subsequent calls to \c Revoke with the same
375  /// key will return false.
376  TF_API
377  static bool Revoke(TfNotice::Key& key);
378 
379  /// Revoke interest by listeners.
380  ///
381  /// This revokes interest by the listeners for the particular
382  /// notice types and call-back methods for which the keys were
383  /// created. It then clears the keys container.
384  TF_API
385  static void Revoke(TfNotice::Keys* keys);
386 
387  /// Revoke interest by a listener.
388  ///
389  /// This revokes interest by the listener for the particular notice type
390  /// and call-back method for which this key was created.
391  ///
392  /// \c Revoke will return a bool value indicating whether or not the key
393  /// was successfully revoked. Subsequent calls to \c Revoke with the same
394  /// key will return false. This will not return while any threads are
395  /// invoking the handler.
396  TF_API
397  static bool RevokeAndWait(TfNotice::Key& key);
398 
399  /// Revoke interest by listeners.
400  ///
401  /// This revokes interest by the listeners for the particular
402  /// notice types and call-back methods for which the keys were
403  /// created. It then clears the keys container. This will not return
404  /// while any threads are invoking any handlers.
405  TF_API
406  static void RevokeAndWait(TfNotice::Keys* keys);
407 
408  /// Deliver the notice to interested listeners, returning the number
409  /// of interested listeners.
410  ///
411  /// For most clients it is recommended to use the Send(sender) version of
412  /// Send() rather than this one. Clients that use this form of Send
413  /// will prevent listeners from being able to register to receive notices
414  /// based on the sender of the notice.
415  ///
416  /// ONLY listeners that registered globally will get the notice.
417  ///
418  /// Listeners are invoked synchronously and in arbitrary order. The value
419  /// returned is the total number of times the notice was sent to listeners.
420  /// Note that a listener is called in the thread in which \c Send() is called
421  /// and \e not necessarily in the thread that \c Register() was called in.
422  TF_API
423  size_t Send() const;
424 
425  /// Deliver the notice to interested listeners, returning the number of
426  /// interested listeners.
427  ///
428  /// This is the recommended form of Send. It takes the sender as an
429  /// argument.
430  ///
431  /// Listeners that registered for the given sender AND listeners that
432  /// registered globally will get the notice.
433  ///
434  /// Listeners are invoked synchronously and in arbitrary order. The value
435  /// returned is the total number of times the notice was sent to
436  /// listeners. Note that a listener is called in the thread in which \c
437  /// Send() is called and \e not necessarily in the thread that \c
438  /// Register() was called in.
439  template <typename SenderPtr>
440  size_t Send(SenderPtr const &s) const;
441 
442  /// Variant of Send() that takes a specific sender in the form of a
443  /// TfWeakBase pointer and a typeid.
444  ///
445  /// This version is used by senders who don't have static knowledge of
446  /// sender's type, but have access to its weak base pointer and its
447  /// typeid.
448  TF_API
449  size_t SendWithWeakBase(const TfWeakBase *senderWeakBase,
450  const void *senderUniqueId,
451  const std::type_info &type) const;
452 
453  TF_API
454  virtual ~TfNotice();
455 
456  /// Blocks sending of all notices in current thread.
457  ///
458  /// \note This is intended to be temporary and should NOT be used.
459  ///
460  /// While one or more \c TfNotice::Block is instantiated, any call to \c
461  /// TfNotice::Send in the current thread will be silently ignored. This
462  /// will continue until all \c TfNotice::Block objects are destroyed.
463  /// Notices that are sent when blocking is active will *not* be resent.
464  class Block {
465  public:
466  TF_API Block();
467  TF_API ~Block();
468  };
469 
470 private:
471  // Abstract base class for calling listeners.
472  // A typed-version derives (via templating) off this class.
473  class _DelivererBase : public TfWeakBase {
474  public:
475  _DelivererBase()
476  : _list(0), _active(true), _markedForRemoval(false)
477  {
478  }
479 
480  TF_API
481  virtual ~_DelivererBase();
482 
483  TF_API
484  void _BeginDelivery(const TfNotice &notice,
485  const TfWeakBase *sender,
486  const std::type_info &senderType,
487  const TfWeakBase *listener,
488  const std::type_info &listenerType,
489  const std::vector<TfNotice::WeakProbePtr> &probes);
490 
491  TF_API
492  void _EndDelivery(const std::vector<TfNotice::WeakProbePtr> &probes);
493 
494  // The derived class converts n to the proper type and delivers it by
495  // calling the listener's method. The function returns \c true,
496  // unless the listener has expired or been marked in active (i.e. by
497  // TfNotice::Revoke()), in which case the method call is skipped and
498  // \c false is returned.
499  virtual bool
500  _SendToListenerImpl(const TfNotice &n,
501  const TfType &type,
502  const TfWeakBase *s,
503  const void *senderUniqueId,
504  const std::type_info &senderType,
505  const std::vector<TfNotice::WeakProbePtr> &) = 0;
506 
507  void _Deactivate() {
508  _active = false;
509  }
510 
511  bool _IsActive() const {
512  return _active;
513  }
514 
515  void _MarkForRemoval() {
516  _markedForRemoval = true;
517  }
518 
519  // True if the entry has been added to the _deadEntries list for
520  // removal. Used to avoid adding it more than once to the list.
521  bool _IsMarkedForRemoval() const {
522  return _markedForRemoval;
523  }
524 
525  virtual TfType GetNoticeType() const = 0;
526 
527  virtual bool Delivers(TfType const &noticeType,
528  const TfWeakBase *sender) const = 0;
529 
530  virtual TfWeakBase const *GetSenderWeakBase() const = 0;
531 
532  virtual _DelivererBase *Clone() const = 0;
533 
534  // Increment the busy count around the actual delivery.
535  bool _SendToListener(const TfNotice &n,
536  const TfType &type,
537  const TfWeakBase *s,
538  const void *senderUniqueId,
539  const std::type_info &senderType,
540  const std::vector<TfNotice::WeakProbePtr> &probes)
541  {
542  // Increment the number of sends in progress.
543  if (_busy.fetch_add(1, std::memory_order_release) & _waitBit) {
544  // We're waiting to revoke this listener and we haven't
545  // started the real send yet so act like we already revoked.
546  // If we didn't check if we were waiting then it's possible
547  // to enter this function but not yet increment, have wait
548  // see the count is zero and return, then have this function
549  // increment and do the real send after having supposedly
550  // waited for all sends to complete.
551  _busy.fetch_add(-1, std::memory_order_release);
552  return false;
553  }
554 
555  // Ensure we decrement the count even if the delivery throws.
556  TfScoped cleanup([this]() {
557  // Decrement the number of sends in progress.
558  _busy.fetch_add(-1, std::memory_order_release);
559  });
560 
561  const auto result =
562  _SendToListenerImpl(n, type,
563  s, senderUniqueId, senderType, probes);
564  return result;
565  }
566 
567  // Spin wait until no deliveries are in progress. This is used when
568  // revoking a listener so we set the _waitBit in _busy permanently.
569  void _WaitForSendsToFinish()
570  {
571  // Mark this listener as waiting for sends to finish and check if
572  // any send is in progress.
573  if (_busy.fetch_or(_waitBit, std::memory_order_release)) {
574  // At least one send was in progress.
575  _WaitUntilNotSending();
576  }
577  }
578 
579  protected:
580 
581  template <class ToNoticeType, class FromNoticeType>
582  static inline ToNoticeType const *
583  _CastNotice(FromNoticeType const *from) {
584  // Dynamic casting in deliverers is significant overhead, so only
585  // do error checking in debug builds.
586  if (TF_DEV_BUILD) {
587  if (!dynamic_cast<ToNoticeType const *>(from)) {
588  ToNoticeType const *castNotice =
589  TfSafeDynamic_cast<ToNoticeType const *>(from);
590  // this will abort with a clear error message if
591  // castNotice is NULL
592  TfNotice::_VerifyFailedCast(typeid(ToNoticeType),
593  *from, castNotice);
594  }
595  }
596  return static_cast<ToNoticeType const *>(from);
597  }
598 
599  private:
600  // Wait until there are no sends in progress.
601  void _WaitUntilNotSending();
602 
603  private:
604  // Linkage to the containing _DelivererList in the Tf_NoticeRegistry
605  _DelivererList *_list;
606  _DelivererList::iterator _listIter;
607 
608  bool _active;
609  bool _markedForRemoval;
610  std::atomic<int> _busy{0};
611 
612  static constexpr int _waitBit = 0x80000000;
613 
614  friend class Tf_NoticeRegistry;
615  };
616 
617  template <class Derived>
618  class _StandardDeliverer : public _DelivererBase {
619  public:
620  virtual ~_StandardDeliverer() {}
621 
622  virtual TfType GetNoticeType() const {
623  typedef typename Derived::NoticeType NoticeType;
624  TfType ret = TfType::Find<NoticeType>();
625  if (ret.IsUnknown())
626  TF_FATAL_ERROR("notice type " + ArchGetDemangled<NoticeType>() +
627  " undefined in the TfType system");
628  return ret;
629  }
630 
631  virtual bool Delivers(TfType const &noticeType,
632  TfWeakBase const *sender) const {
633  Derived const *derived = this->AsDerived();
634  return noticeType.IsA(GetNoticeType()) &&
635  !derived->_sender.IsInvalid() &&
636  sender && derived->_sender.GetWeakBase() == sender;
637  }
638 
639  virtual TfWeakBase const *GetSenderWeakBase() const {
640  Derived const *derived = this->AsDerived();
641  return derived->_sender ? derived->_sender.GetWeakBase() : 0;
642  }
643 
644  virtual _DelivererBase *Clone() const {
645  Derived const *derived = this->AsDerived();
646  return new Derived(derived->_listener,
647  derived->_method,
648  derived->_sender,
649  GetNoticeType());
650  }
651 
652  virtual bool
653  _SendToListenerImpl(const TfNotice &notice,
654  const TfType &noticeType,
655  const TfWeakBase *sender,
656  const void *senderUniqueId,
657  const std::type_info &senderType,
658  const std::vector<TfNotice::WeakProbePtr> &probes)
659  {
660  Derived *derived = this->AsDerived();
661  typedef typename Derived::ListenerType ListenerType;
662  typedef typename Derived::NoticeType NoticeType;
663  ListenerType *listener = get_pointer(derived->_listener);
664 
665  if (listener && !derived->_sender.IsInvalid()) {
666 
667  std::optional<TfScoped<>> endDeliveryScope;
668  if (ARCH_UNLIKELY(!probes.empty())) {
669  TfWeakBase const *senderWeakBase = GetSenderWeakBase(),
670  *listenerWeakBase = derived->_listener.GetWeakBase();
671  _BeginDelivery(notice, senderWeakBase,
672  senderWeakBase ?
673  senderType : typeid(void),
674  listenerWeakBase,
675  typeid(ListenerType), probes);
676 
677  // Ensure _EndDelivery is called even if the listener
678  // throws.
679  endDeliveryScope.emplace([this, &probes]() {
680  _EndDelivery(probes);
681  });
682  }
683 
684  derived->
685  _InvokeListenerMethod(listener,
686  *_CastNotice<NoticeType>(&notice),
687  noticeType, sender,
688  senderUniqueId, senderType);
689 
690  return true;
691  }
692  return false;
693  }
694 
695  private:
696  Derived *AsDerived() {
697  return static_cast<Derived *>(this);
698  }
699 
700  Derived const *AsDerived() const {
701  return static_cast<Derived const *>(this);
702  }
703  };
704 
705 
706  template <typename LPtr, typename SPtr, typename Method, typename Notice>
707  class _Deliverer :
708  public _StandardDeliverer<_Deliverer<LPtr, SPtr, Method, Notice> >
709  {
710  public:
711  typedef Notice NoticeType;
712  typedef typename LPtr::DataType ListenerType;
713  typedef Method MethodPtr;
714 
715  _Deliverer(LPtr const &listener,
716  MethodPtr const &methodPtr,
717  SPtr const &sender = SPtr(),
718  TfType const &noticeType = TfType())
719  : _listener(listener)
720  , _sender(sender)
721  , _method(methodPtr)
722  {
723  }
724 
725  void _InvokeListenerMethod(ListenerType *listener,
726  const NoticeType &notice,
727  const TfType &noticeType,
728  const TfWeakBase *,
729  const void *,
730  const std::type_info &)
731  {
732  (listener->*_method)(notice);
733  }
734 
735  LPtr _listener;
736  SPtr _sender;
737  MethodPtr _method;
738  };
739 
740  template <class LPtr, class Method>
741  class _RawDeliverer :
742  public _StandardDeliverer<_RawDeliverer<LPtr, Method> >
743  {
744  public:
745  typedef TfNotice NoticeType;
746  typedef typename LPtr::DataType ListenerType;
747  typedef Method MethodPtr;
748 
749  _RawDeliverer(LPtr const &listener,
750  MethodPtr const &methodPtr,
751  TfAnyWeakPtr const &sender,
752  TfType const &noticeType)
753  : _noticeType(noticeType),
754  _listener(listener),
755  _method(methodPtr),
756  _sender(sender)
757  {
758  }
759 
760  virtual TfType GetNoticeType() const {
761  return _noticeType;
762  }
763 
764  void _InvokeListenerMethod(ListenerType *listener,
765  const NoticeType &notice,
766  const TfType &noticeType,
767  const TfWeakBase *sender,
768  const void *senderUniqueId,
769  const std::type_info &senderType)
770  {
771  (listener->*_method)(notice, noticeType,
772  const_cast<TfWeakBase *>(sender),
773  senderUniqueId, senderType);
774  }
775 
776  TfType _noticeType;
777  LPtr _listener;
778  MethodPtr _method;
779  TfAnyWeakPtr _sender;
780  };
781 
782  template <class LPtr, class SPtr, class Method, class Notice>
783  class _DelivererWithSender :
784  public _StandardDeliverer<
785  _DelivererWithSender<LPtr, SPtr, Method, Notice>
786  >
787  {
788  public:
789  typedef Notice NoticeType;
790  typedef Method MethodPtr;
791  typedef typename LPtr::DataType ListenerType;
792 
793  typedef typename SPtr::DataType SenderType;
794 
795  _DelivererWithSender(LPtr const &listener,
796  MethodPtr const &methodPtr,
797  SPtr const &sender,
798  TfType const &noticeType = TfType())
799  : _listener(listener),
800  _sender(sender),
801  _method(methodPtr)
802  {
803  }
804 
805  void _InvokeListenerMethod(ListenerType *listener,
806  const NoticeType &notice,
807  const TfType &noticeType,
808  const TfWeakBase *sender,
809  const void *,
810  const std::type_info &)
811  {
812  SenderType *deliveredSender =
813  static_cast<SenderType *>(const_cast<TfWeakBase *>(sender));
814  SPtr deliveredSPtr(deliveredSender);
815  (listener->*_method)(notice, deliveredSPtr);
816  }
817 
818  LPtr _listener;
819  SPtr _sender;
820  MethodPtr _method;
821  };
822 
823 private:
824  // Internal non-templated function to install listeners.
825  TF_API
826  static Key _Register(_DelivererBase*);
827 
828  TF_API
829  static void _VerifyFailedCast(const std::type_info& toType,
830  const TfNotice& notice,
831  const TfNotice* castNotice);
832 
833  TF_API
834  size_t _Send(const TfWeakBase* sender,
835  const void *senderUniqueId,
836  const std::type_info & senderType) const;
837  TF_API
838  size_t _SendWithType(const TfType & noticeType,
839  const TfWeakBase* sender,
840  const void *senderUniqueId,
841  const std::type_info & senderType) const;
842 
843  friend class Tf_NoticeRegistry;
844 
845  // Befriend the wrapping so it can access _SendWithType() directly
846  // in order to provide dynamic downcasting of Python notice types.
847  friend class Tf_PyNotice;
848 };
849 
850 template <typename SenderPtr>
851 size_t
852 TfNotice::Send(SenderPtr const &s) const
853 {
854  const TfWeakBase *senderWeakBase = s ? s.GetWeakBase() : NULL;
855  return _Send(senderWeakBase, senderWeakBase ? s.GetUniqueIdentifier() : 0,
856  senderWeakBase ?
857  typeid(typename SenderPtr::DataType) : typeid(void));
858 }
859 
861 
862 #endif // PXR_BASE_TF_NOTICE_H
virtual TF_API ~Probe()=0
virtual void BeginSend(const TfNotice &notice, const TfWeakBase *sender, const std::type_info &senderType)=0
bool IsUnknown() const
Definition: type.h:374
#define TF_API
Definition: api.h:23
void
Definition: png.h:1083
virtual TF_API ~TfNotice()
#define PXR_NAMESPACE_OPEN_SCOPE
Definition: pxr.h:73
static TfNotice::Key Register(LPtr const &listener, MethodPtr method)
Definition: notice.h:348
friend class Tf_NoticeRegistry
Definition: notice.h:843
static TF_API void InsertProbe(const WeakProbePtr &probe)
GLdouble s
Definition: glad.h:3009
**But if you need a result
Definition: thread.h:622
OutGridT const XformOp bool bool
Y * get_pointer(TfWeakPtrFacade< X, Y > const &p)
Definition: weakPtrFacade.h:63
#define ARCH_UNLIKELY(x)
Definition: hints.h:30
GLdouble n
Definition: glcorearb.h:2008
GLint GLint GLsizei GLint GLenum GLenum type
Definition: glcorearb.h:108
virtual void EndSend()=0
TF_API size_t SendWithWeakBase(const TfWeakBase *senderWeakBase, const void *senderUniqueId, const std::type_info &type) const
static TF_API void RemoveProbe(const WeakProbePtr &probe)
static TF_API bool Revoke(TfNotice::Key &key)
#define TF_FATAL_ERROR
std::vector< Key > Keys
Definition: notice.h:276
TfRefPtr< typename D::DataType > TfSafeDynamic_cast(const TfRefPtr< T > &ptr)
Definition: refPtr.h:1216
virtual void EndDelivery()=0
static TF_API bool RevokeAndWait(TfNotice::Key &key)
static TfNotice::Key Register(LPtr const &listener, MethodPtr method, const TfType &noticeType, const TfAnyWeakPtr &sender)
Definition: notice.h:362
friend class Tf_PyNotice
Definition: notice.h:847
FS_API bool cleanup(UT_StringArray &removed, UT_StringArray &error_files, exint &memory_freed, bool dry_run, const char *override_path=nullptr)
friend class Tf_NoticeRegistry
Definition: notice.h:267
virtual void BeginDelivery(const TfNotice &notice, const TfWeakBase *sender, const std::type_info &senderType, const TfWeakBase *listener, const std::type_info &listenerType)=0
bool IsValid() const
Definition: notice.h:251
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:74
Definition: type.h:47
TF_API bool IsA(TfType queryType) const
TF_API size_t Send() const
TfWeakPtr< Probe > WeakProbePtr
Definition: notice.h:199
static TfNotice::Key Register(LPtr const &listener, MethodPtr method, SenderPtr const &sender)
Definition: notice.h:355
TF_API void const * GetUniqueIdentifier() const