notice.h
Go to the documentation of this file.
1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 // names, trademarks, service marks, or product names of the Licensor
11 // and its affiliates, except as required to comply with Section 4(c) of
12 // the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 // http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 #ifndef PXR_BASE_TF_NOTICE_H
25 #define PXR_BASE_TF_NOTICE_H
26 
29 
30 #include "pxr/pxr.h"
31 #include "pxr/base/tf/api.h"
32 #include "pxr/base/tf/anyWeakPtr.h"
33 #include "pxr/base/tf/diagnostic.h"
34 #include "pxr/base/tf/type.h"
35 #include "pxr/base/tf/weakPtr.h"
36 #include "pxr/base/arch/demangle.h"
37 #include "pxr/base/arch/hints.h"
38 
39 #include <list>
40 #include <typeinfo>
41 
42 PXR_NAMESPACE_OPEN_SCOPE
43 
44 class Tf_NoticeRegistry;
45 
93 class TfNotice {
94 private:
95  class _DelivererBase;
97  typedef std::list<_DelivererBase*> _DelivererList;
98 
100  // Per-sender delivery, listener gets sender.
101  template <class LPtr, class L,
102  class Notice, class SPtr, class DeliveredSPtr>
103  static _DelivererBase *
104  _MakeDeliverer(LPtr const &listener,
105  void (L::*method)
106  (const Notice &, DeliveredSPtr const &),
107  SPtr const &sender) {
108  DeliveredSPtr weakSender(sender);
109  return new _DelivererWithSender<
110  LPtr, DeliveredSPtr,
111  void (L::*)(const Notice &, DeliveredSPtr const &),
112  Notice
113  >(listener, method, weakSender);
114  }
115 
116  template <class LPtr, class L,
117  class Notice, class SPtr, class DeliveredSPtr>
118  static _DelivererBase *
119  _MakeDeliverer(LPtr const &listener,
120  void (L::*method)
121  (const Notice &, DeliveredSPtr const &) const,
122  SPtr const &sender) {
123  DeliveredSPtr weakSender(sender);
124  return new _DelivererWithSender<
125  LPtr, DeliveredSPtr,
126  void (L::*)(const Notice &, DeliveredSPtr const &) const,
127  Notice
128  >(listener, method, weakSender);
129  }
130 
132  // Per-sender delivery, listener does not get sender.
133  template <class LPtr, class L, class SPtr, class Notice>
134  static _DelivererBase *
135  _MakeDeliverer(LPtr const &listener,
136  void (L::*method)(const Notice &),
137  SPtr const &sender) {
138  return new _Deliverer<
139  LPtr, SPtr, void (L::*)(const Notice &), Notice
140  >(listener, method, sender);
141  }
142 
143  template <class LPtr, class L, class SPtr, class Notice>
144  static _DelivererBase *
145  _MakeDeliverer(LPtr const &listener,
146  void (L::*method)(const Notice &) const,
147  SPtr const &sender) {
148  return new _Deliverer<
149  LPtr, SPtr, void (L::*)(const Notice &) const, Notice
150  >(listener, method, sender);
151  }
152 
154  // Global delivery.
155  template <class LPtr, class L, class Notice>
156  static _DelivererBase *
157  _MakeDeliverer(LPtr const &listener,
158  void (L::*method)(const Notice &)) {
159  return new _Deliverer<
160  LPtr, TfAnyWeakPtr, void (L::*)(const Notice &), Notice
161  >(listener, method);
162  }
163 
164  template <class LPtr, class L, class Notice>
165  static _DelivererBase *
166  _MakeDeliverer(LPtr const &listener,
167  void (L::*method)(const Notice &) const) {
168  return new _Deliverer<
169  LPtr, TfAnyWeakPtr, void (L::*)(const Notice &) const, Notice
170  >(listener, method);
171  }
172 
174  // Generic (raw) delivery.
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&),
183  TfAnyWeakPtr const &sender) {
184  return new _RawDeliverer<LPtr,
185  void (L::*)(const TfNotice &, const TfType &,
186  TfWeakBase *, const void *,
187  const std::type_info &)>
188  (listener, method, sender, noticeType);
189  }
190 
191  template <class LPtr, class L>
192  static _DelivererBase *
193  _MakeDeliverer(TfType const &noticeType,
194  LPtr const &listener,
195  void (L::*method)(const TfNotice &,
196  const TfType &,
197  TfWeakBase*, const void *,
198  const std::type_info&) const,
199  TfAnyWeakPtr const &sender)
200  {
201  return new _RawDeliverer<LPtr,
202  void (L::*)(const TfNotice &, const TfType &,
203  TfWeakBase *, const void *,
204  const std::type_info &) const>
205  (listener, method, sender, noticeType);
206  }
207 
208 
209 
210 public:
211 
212  class Probe;
214 
218  class Probe : public TfWeakBase {
219  public:
220  TF_API
221  virtual ~Probe() = 0;
222 
226  virtual void BeginSend(const TfNotice &notice,
227  const TfWeakBase *sender,
228  const std::type_info &senderType) = 0;
229 
232  virtual void EndSend() = 0;
233 
238  virtual void BeginDelivery(const TfNotice &notice,
239  const TfWeakBase *sender,
240  const std::type_info &senderType,
241  const TfWeakBase *listener,
242  const std::type_info &listenerType) = 0;
243 
247  virtual void EndDelivery() = 0;
248  };
249 
256  class Key {
257  public:
258  Key() {}
259 
264  bool IsValid() const {
265  return _deliverer && _deliverer->_IsActive();
266  }
267 
271  operator bool() const {
272  return IsValid();
273  }
274 
275  private:
276  Key(const _DelivererWeakPtr & d) : _deliverer(d) {}
277 
278  _DelivererWeakPtr _deliverer;
279 
280  friend class Tf_NoticeRegistry;
281  friend class TfNotice;
282  };
283 
289  typedef std::vector<Key> Keys;
290 
294  TF_API
295  static void InsertProbe(const WeakProbePtr &probe);
296 
299  TF_API
300  static void RemoveProbe(const WeakProbePtr &probe);
301 
359  template <class LPtr, class MethodPtr>
360  static TfNotice::Key
361  Register(LPtr const &listener, MethodPtr method) {
362  return _Register(_MakeDeliverer(listener, method));
363  }
364 
365  template <class LPtr, class MethodPtr, class SenderPtr>
366  static TfNotice::Key
367  Register(LPtr const &listener, MethodPtr method, SenderPtr const &sender) {
368  return _Register(_MakeDeliverer(listener, method, sender));
369  }
370 
371  template <class LPtr, class MethodPtr>
372  static TfNotice::Key
373  Register(LPtr const &listener, MethodPtr method,
374  const TfType &noticeType, const TfAnyWeakPtr &sender) {
375  return _Register(_MakeDeliverer(noticeType, listener, method, sender));
376  }
377 
386  TF_API
387  static bool Revoke(TfNotice::Key& key);
388 
394  TF_API
395  static void Revoke(TfNotice::Keys* keys);
396 
411  TF_API
412  size_t Send() const;
413 
428  template <typename SenderPtr>
429  size_t Send(SenderPtr const &s) const;
430 
437  TF_API
438  size_t SendWithWeakBase(const TfWeakBase *senderWeakBase,
439  const void *senderUniqueId,
440  const std::type_info &type) const;
441 
442  TF_API
443  virtual ~TfNotice();
444 
453  class Block {
454  public:
455  TF_API Block();
456  TF_API ~Block();
457  };
458 
459 private:
460  // Abstract base class for calling listeners.
461  // A typed-version derives (via templating) off this class.
462  class _DelivererBase : public TfWeakBase {
463  public:
464  _DelivererBase()
465  : _list(0), _active(true), _markedForRemoval(false)
466  {
467  }
468 
469  TF_API
470  virtual ~_DelivererBase();
471 
472  TF_API
473  void _BeginDelivery(const TfNotice &notice,
474  const TfWeakBase *sender,
475  const std::type_info &senderType,
476  const TfWeakBase *listener,
477  const std::type_info &listenerType,
478  const std::vector<TfNotice::WeakProbePtr> &probes);
479 
480  TF_API
481  void _EndDelivery(const std::vector<TfNotice::WeakProbePtr> &probes);
482 
483  // The derived class converts n to the proper type and delivers it by
484  // calling the listener's method. The function returns \c true,
485  // unless the listener has expired or been marked in active (i.e. by
486  // TfNotice::Revoke()), in which case the method call is skipped and
487  // \c false is returned.
488  virtual bool
489  _SendToListener(const TfNotice &n,
490  const TfType &type,
491  const TfWeakBase *s,
492  const void *senderUniqueId,
493  const std::type_info &senderType,
494  const std::vector<TfNotice::WeakProbePtr> &probes) = 0;
495 
496  void _Deactivate() {
497  _active = false;
498  }
499 
500  bool _IsActive() const {
501  return _active;
502  }
503 
504  void _MarkForRemoval() {
505  _markedForRemoval = true;
506  }
507 
508  // True if the entry has been added to the _deadEntries list for
509  // removal. Used to avoid adding it more than once to the list.
510  bool _IsMarkedForRemoval() const {
511  return _markedForRemoval;
512  }
513 
514  virtual TfType GetNoticeType() const = 0;
515 
516  virtual bool Delivers(TfType const &noticeType,
517  const TfWeakBase *sender) const = 0;
518 
519  virtual TfWeakBase const *GetSenderWeakBase() const = 0;
520 
521  virtual _DelivererBase *Clone() const = 0;
522 
523  protected:
524 
525  template <class ToNoticeType, class FromNoticeType>
526  static inline ToNoticeType const *
527  _CastNotice(FromNoticeType const *from) {
528  // Dynamic casting in deliverers is significant overhead, so only
529  // do error checking in debug builds.
530  if (TF_DEV_BUILD) {
531  if (!dynamic_cast<ToNoticeType const *>(from)) {
532  ToNoticeType const *castNotice =
533  TfSafeDynamic_cast<ToNoticeType const *>(from);
534  // this will abort with a clear error message if
535  // castNotice is NULL
536  TfNotice::_VerifyFailedCast(typeid(ToNoticeType),
537  *from, castNotice);
538  }
539  }
540  return static_cast<ToNoticeType const *>(from);
541  }
542 
543  private:
544  // Linkage to the containing _DelivererList in the Tf_NoticeRegistry
545  _DelivererList *_list;
546  _DelivererList::iterator _listIter;
547 
548  bool _active;
549  bool _markedForRemoval;
550 
551  friend class Tf_NoticeRegistry;
552  };
553 
554  template <class Derived>
555  class _StandardDeliverer : public _DelivererBase {
556  public:
557  virtual ~_StandardDeliverer() {}
558 
559  virtual TfType GetNoticeType() const {
560  typedef typename Derived::NoticeType NoticeType;
561  TfType ret = TfType::Find<NoticeType>();
562  if (ret.IsUnknown())
563  TF_FATAL_ERROR("notice type " + ArchGetDemangled<NoticeType>() +
564  " undefined in the TfType system");
565  return ret;
566  }
567 
568  virtual bool Delivers(TfType const &noticeType,
569  TfWeakBase const *sender) const {
570  Derived const *derived = this->AsDerived();
571  return noticeType.IsA(GetNoticeType()) &&
572  !derived->_sender.IsInvalid() &&
573  sender && derived->_sender.GetWeakBase() == sender;
574  }
575 
576  virtual TfWeakBase const *GetSenderWeakBase() const {
577  Derived const *derived = this->AsDerived();
578  return derived->_sender ? derived->_sender.GetWeakBase() : 0;
579  }
580 
581  virtual _DelivererBase *Clone() const {
582  Derived const *derived = this->AsDerived();
583  return new Derived(derived->_listener,
584  derived->_method,
585  derived->_sender,
586  GetNoticeType());
587  }
588 
589  virtual bool
590  _SendToListener(const TfNotice &notice,
591  const TfType &noticeType,
592  const TfWeakBase *sender,
593  const void *senderUniqueId,
594  const std::type_info &senderType,
595  const std::vector<TfNotice::WeakProbePtr> &probes)
596  {
597  Derived *derived = this->AsDerived();
598  typedef typename Derived::ListenerType ListenerType;
599  typedef typename Derived::NoticeType NoticeType;
600  ListenerType *listener = get_pointer(derived->_listener);
601 
602  if (listener && !derived->_sender.IsInvalid()) {
603  if (ARCH_UNLIKELY(!probes.empty())) {
604  TfWeakBase const *senderWeakBase = GetSenderWeakBase(),
605  *listenerWeakBase = derived->_listener.GetWeakBase();
606  _BeginDelivery(notice, senderWeakBase,
607  senderWeakBase ?
608  senderType : typeid(void),
609  listenerWeakBase,
610  typeid(ListenerType), probes);
611  }
612 
613  derived->
614  _InvokeListenerMethod(listener,
615  *_CastNotice<NoticeType>(&notice),
616  noticeType, sender,
617  senderUniqueId, senderType);
618 
619  if (ARCH_UNLIKELY(!probes.empty()))
620  _EndDelivery(probes);
621 
622  return true;
623  }
624  return false;
625  }
626 
627  private:
628  Derived *AsDerived() {
629  return static_cast<Derived *>(this);
630  }
631 
632  Derived const *AsDerived() const {
633  return static_cast<Derived const *>(this);
634  }
635  };
636 
637 
638  template <typename LPtr, typename SPtr, typename Method, typename Notice>
639  class _Deliverer :
640  public _StandardDeliverer<_Deliverer<LPtr, SPtr, Method, Notice> >
641  {
642  public:
643  typedef Notice NoticeType;
644  typedef typename LPtr::DataType ListenerType;
645  typedef Method MethodPtr;
646 
647  _Deliverer(LPtr const &listener,
648  MethodPtr const &methodPtr,
649  SPtr const &sender = SPtr(),
650  TfType const &noticeType = TfType())
651  : _listener(listener)
652  , _sender(sender)
653  , _method(methodPtr)
654  {
655  }
656 
657  void _InvokeListenerMethod(ListenerType *listener,
658  const NoticeType &notice,
659  const TfType &noticeType,
660  const TfWeakBase *,
661  const void *,
662  const std::type_info &)
663  {
664  (listener->*_method)(notice);
665  }
666 
667  LPtr _listener;
668  SPtr _sender;
669  MethodPtr _method;
670  };
671 
672  template <class LPtr, class Method>
673  class _RawDeliverer :
674  public _StandardDeliverer<_RawDeliverer<LPtr, Method> >
675  {
676  public:
677  typedef TfNotice NoticeType;
678  typedef typename LPtr::DataType ListenerType;
679  typedef Method MethodPtr;
680 
681  _RawDeliverer(LPtr const &listener,
682  MethodPtr const &methodPtr,
683  TfAnyWeakPtr const &sender,
684  TfType const &noticeType)
685  : _noticeType(noticeType),
686  _listener(listener),
687  _method(methodPtr),
688  _sender(sender)
689  {
690  }
691 
692  virtual TfType GetNoticeType() const {
693  return _noticeType;
694  }
695 
696  void _InvokeListenerMethod(ListenerType *listener,
697  const NoticeType &notice,
698  const TfType &noticeType,
699  const TfWeakBase *sender,
700  const void *senderUniqueId,
701  const std::type_info &senderType)
702  {
703  (listener->*_method)(notice, noticeType,
704  const_cast<TfWeakBase *>(sender),
705  senderUniqueId, senderType);
706  }
707 
708  TfType _noticeType;
709  LPtr _listener;
710  MethodPtr _method;
711  TfAnyWeakPtr _sender;
712  };
713 
714  template <class LPtr, class SPtr, class Method, class Notice>
715  class _DelivererWithSender :
716  public _StandardDeliverer<
717  _DelivererWithSender<LPtr, SPtr, Method, Notice>
718  >
719  {
720  public:
721  typedef Notice NoticeType;
722  typedef Method MethodPtr;
723  typedef typename LPtr::DataType ListenerType;
724 
725  typedef typename SPtr::DataType SenderType;
726 
727  _DelivererWithSender(LPtr const &listener,
728  MethodPtr const &methodPtr,
729  SPtr const &sender,
730  TfType const &noticeType = TfType())
731  : _listener(listener),
732  _sender(sender),
733  _method(methodPtr)
734  {
735  }
736 
737  void _InvokeListenerMethod(ListenerType *listener,
738  const NoticeType &notice,
739  const TfType &noticeType,
740  const TfWeakBase *sender,
741  const void *,
742  const std::type_info &)
743  {
744  SenderType *deliveredSender =
745  static_cast<SenderType *>(const_cast<TfWeakBase *>(sender));
746  SPtr deliveredSPtr(deliveredSender);
747  (listener->*_method)(notice, deliveredSPtr);
748  }
749 
750  LPtr _listener;
751  SPtr _sender;
752  MethodPtr _method;
753  };
754 
755 private:
756  // Internal non-templated function to install listeners.
757  TF_API
758  static Key _Register(_DelivererBase*);
759 
760  TF_API
761  static void _VerifyFailedCast(const std::type_info& toType,
762  const TfNotice& notice,
763  const TfNotice* castNotice);
764 
765  TF_API
766  size_t _Send(const TfWeakBase* sender,
767  const void *senderUniqueId,
768  const std::type_info & senderType) const;
769  TF_API
770  size_t _SendWithType(const TfType & noticeType,
771  const TfWeakBase* sender,
772  const void *senderUniqueId,
773  const std::type_info & senderType) const;
774 
775  friend class Tf_NoticeRegistry;
776 
777  // Befriend the wrapping so it can access _SendWithType() directly
778  // in order to provide dynamic downcasting of Python notice types.
779  friend class Tf_PyNotice;
780 };
781 
782 template <typename SenderPtr>
783 size_t
784 TfNotice::Send(SenderPtr const &s) const
785 {
786  const TfWeakBase *senderWeakBase = s ? s.GetWeakBase() : NULL;
787  return _Send(senderWeakBase, senderWeakBase ? s.GetUniqueIdentifier() : 0,
788  senderWeakBase ?
789  typeid(typename SenderPtr::DataType) : typeid(void));
790 }
791 
792 PXR_NAMESPACE_CLOSE_SCOPE
793 
794 #endif // PXR_BASE_TF_NOTICE_H
Handle-object returned by TfNotice::Register().
Definition: notice.h:256
bool IsValid() const
Does this key refer to a valid notification?
Definition: notice.h:264
The base class for objects used to notify interested parties (listeners) when events have occurred.
Definition: notice.h:93
virtual void BeginDelivery(const TfNotice &notice, const TfWeakBase *sender, const std::type_info &senderType, const TfWeakBase *listener, const std::type_info &listenerType)=0
This method is called just before notice is delivered to a listener.
Type independent WeakPtr holder class.
Low-level utilities for informing users of various internal and external diagnostic conditions.
TF_API bool IsA(TfType queryType) const
Return true if this type is the same as or derived from queryType.
std::vector< Key > Keys
A TfNotice::Key container.
Definition: notice.h:289
Compiler hints.
Pointer storage with deletion detection.
Demangle C++ typenames generated by the typeid() facility.
Provides the ability to hold an arbitrary TfWeakPtr in a non-type-specific manner in order to observe...
Definition: anyWeakPtr.h:54
TF_API size_t Send() const
Deliver the notice to interested listeners, returning the number of interested listeners.
Probe interface class which may be implemented and then registered via InsertProbe to introspect abou...
Definition: notice.h:218
static TF_API bool Revoke(TfNotice::Key &key)
Revoke interest by a listener.
#define TF_FATAL_ERROR(fmt, args)
Issue a fatal error and end the program.
Definition: diagnostic.h:108
static TF_API void RemoveProbe(const WeakProbePtr &probe)
Remove a probe that was previously registered with InsertProbe.
static TF_API void InsertProbe(const WeakProbePtr &probe)
Register a probe that will be invoked when notices are sent and delivered.
Blocks sending of all notices in current thread.
Definition: notice.h:453
virtual void EndSend()=0
This method is called after the notice in the corresponding BeginSend call has been delivered to all ...
virtual void EndDelivery()=0
This method is called after the notice in the corresponding BeginDelivery call has finished being pro...
TF_API size_t SendWithWeakBase(const TfWeakBase *senderWeakBase, const void *senderUniqueId, const std::type_info &type) const
Variant of Send() that takes a specific sender in the form of a TfWeakBase pointer and a typeid.
TfType represents a dynamic runtime type.
Definition: type.h:64
bool IsUnknown() const
Return true if this is the unknown type, representing a type unknown to the TfType system.
Definition: type.h:388
virtual void BeginSend(const TfNotice &notice, const TfWeakBase *sender, const std::type_info &senderType)=0
This method is called just before notice is sent to any listeners.
static TfNotice::Key Register(LPtr const &listener, MethodPtr method)
Register a listener as being interested in a TfNotice.
Definition: notice.h:361
Enable a concrete base class for use with TfWeakPtr.
Definition: weakBase.h:141