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