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  static void InsertProbe(const WeakProbePtr &probe);
295 
298  static void RemoveProbe(const WeakProbePtr &probe);
299 
357  template <class LPtr, class MethodPtr>
358  static TfNotice::Key
359  Register(LPtr const &listener, MethodPtr method) {
360  return _Register(_MakeDeliverer(listener, method));
361  }
362 
363  template <class LPtr, class MethodPtr, class SenderPtr>
364  static TfNotice::Key
365  Register(LPtr const &listener, MethodPtr method, SenderPtr const &sender) {
366  return _Register(_MakeDeliverer(listener, method, sender));
367  }
368 
369  template <class LPtr, class MethodPtr>
370  static TfNotice::Key
371  Register(LPtr const &listener, MethodPtr method,
372  const TfType &noticeType, const TfAnyWeakPtr &sender) {
373  return _Register(_MakeDeliverer(noticeType, listener, method, sender));
374  }
375 
384  TF_API
385  static bool Revoke(TfNotice::Key& key);
386 
392  TF_API
393  static void Revoke(TfNotice::Keys* keys);
394 
409  TF_API
410  size_t Send() const;
411 
426  template <typename SenderPtr>
427  size_t Send(SenderPtr const &s) const;
428 
435  TF_API
436  size_t SendWithWeakBase(const TfWeakBase *senderWeakBase,
437  const void *senderUniqueId,
438  const std::type_info &type) const;
439 
440  TF_API
441  virtual ~TfNotice();
442 
451  class Block {
452  public:
453  TF_API Block();
454  TF_API ~Block();
455  };
456 
457 private:
458  // Abstract base class for calling listeners.
459  // A typed-version derives (via templating) off this class.
460  class _DelivererBase : public TfWeakBase {
461  public:
462  _DelivererBase()
463  : _list(0), _active(true), _markedForRemoval(false)
464  {
465  }
466 
467  TF_API
468  virtual ~_DelivererBase();
469 
470  TF_API
471  void _BeginDelivery(const TfNotice &notice,
472  const TfWeakBase *sender,
473  const std::type_info &senderType,
474  const TfWeakBase *listener,
475  const std::type_info &listenerType,
476  const std::vector<TfNotice::WeakProbePtr> &probes);
477 
478  TF_API
479  void _EndDelivery(const std::vector<TfNotice::WeakProbePtr> &probes);
480 
481  // The derived class converts n to the proper type and delivers it by
482  // calling the listener's method. The function returns \c true,
483  // unless the listener has expired or been marked in active (i.e. by
484  // TfNotice::Revoke()), in which case the method call is skipped and
485  // \c false is returned.
486  virtual bool
487  _SendToListener(const TfNotice &n,
488  const TfType &type,
489  const TfWeakBase *s,
490  const void *senderUniqueId,
491  const std::type_info &senderType,
492  const std::vector<TfNotice::WeakProbePtr> &probes) = 0;
493 
494  void _Deactivate() {
495  _active = false;
496  }
497 
498  bool _IsActive() const {
499  return _active;
500  }
501 
502  void _MarkForRemoval() {
503  _markedForRemoval = true;
504  }
505 
506  // True if the entry has been added to the _deadEntries list for
507  // removal. Used to avoid adding it more than once to the list.
508  bool _IsMarkedForRemoval() const {
509  return _markedForRemoval;
510  }
511 
512  virtual TfType GetNoticeType() const = 0;
513 
514  virtual bool Delivers(TfType const &noticeType,
515  const TfWeakBase *sender) const = 0;
516 
517  virtual TfWeakBase const *GetSenderWeakBase() const = 0;
518 
519  virtual _DelivererBase *Clone() const = 0;
520 
521  protected:
522 
523  template <class ToNoticeType, class FromNoticeType>
524  static inline ToNoticeType const *
525  _CastNotice(FromNoticeType const *from) {
526  // Dynamic casting in deliverers is significant overhead, so only
527  // do error checking in debug builds.
528  if (TF_DEV_BUILD) {
529  if (!dynamic_cast<ToNoticeType const *>(from)) {
530  ToNoticeType const *castNotice =
531  TfSafeDynamic_cast<ToNoticeType const *>(from);
532  // this will abort with a clear error message if
533  // castNotice is NULL
534  TfNotice::_VerifyFailedCast(typeid(ToNoticeType),
535  *from, castNotice);
536  }
537  }
538  return static_cast<ToNoticeType const *>(from);
539  }
540 
541  private:
542  // Linkage to the containing _DelivererList in the Tf_NoticeRegistry
543  _DelivererList *_list;
544  _DelivererList::iterator _listIter;
545 
546  bool _active;
547  bool _markedForRemoval;
548 
549  friend class Tf_NoticeRegistry;
550  };
551 
552  template <class Derived>
553  class _StandardDeliverer : public _DelivererBase {
554  public:
555  virtual ~_StandardDeliverer() {}
556 
557  virtual TfType GetNoticeType() const {
558  typedef typename Derived::NoticeType NoticeType;
559  TfType ret = TfType::Find<NoticeType>();
560  if (ret.IsUnknown())
561  TF_FATAL_ERROR("notice type " + ArchGetDemangled<NoticeType>() +
562  " undefined in the TfType system");
563  return ret;
564  }
565 
566  virtual bool Delivers(TfType const &noticeType,
567  TfWeakBase const *sender) const {
568  Derived const *derived = this->AsDerived();
569  return noticeType.IsA(GetNoticeType()) &&
570  !derived->_sender.IsInvalid() &&
571  sender && derived->_sender.GetWeakBase() == sender;
572  }
573 
574  virtual TfWeakBase const *GetSenderWeakBase() const {
575  Derived const *derived = this->AsDerived();
576  return derived->_sender ? derived->_sender.GetWeakBase() : 0;
577  }
578 
579  virtual _DelivererBase *Clone() const {
580  Derived const *derived = this->AsDerived();
581  return new Derived(derived->_listener,
582  derived->_method,
583  derived->_sender,
584  GetNoticeType());
585  }
586 
587  virtual bool
588  _SendToListener(const TfNotice &notice,
589  const TfType &noticeType,
590  const TfWeakBase *sender,
591  const void *senderUniqueId,
592  const std::type_info &senderType,
593  const std::vector<TfNotice::WeakProbePtr> &probes)
594  {
595  Derived *derived = this->AsDerived();
596  typedef typename Derived::ListenerType ListenerType;
597  typedef typename Derived::NoticeType NoticeType;
598  ListenerType *listener = get_pointer(derived->_listener);
599 
600  if (listener && !derived->_sender.IsInvalid()) {
601  if (ARCH_UNLIKELY(!probes.empty())) {
602  TfWeakBase const *senderWeakBase = GetSenderWeakBase(),
603  *listenerWeakBase = derived->_listener.GetWeakBase();
604  _BeginDelivery(notice, senderWeakBase,
605  senderWeakBase ?
606  senderType : typeid(void),
607  listenerWeakBase,
608  typeid(ListenerType), probes);
609  }
610 
611  derived->
612  _InvokeListenerMethod(listener,
613  *_CastNotice<NoticeType>(&notice),
614  noticeType, sender,
615  senderUniqueId, senderType);
616 
617  if (ARCH_UNLIKELY(!probes.empty()))
618  _EndDelivery(probes);
619 
620  return true;
621  }
622  return false;
623  }
624 
625  private:
626  Derived *AsDerived() {
627  return static_cast<Derived *>(this);
628  }
629 
630  Derived const *AsDerived() const {
631  return static_cast<Derived const *>(this);
632  }
633  };
634 
635 
636  template <typename LPtr, typename SPtr, typename Method, typename Notice>
637  class _Deliverer :
638  public _StandardDeliverer<_Deliverer<LPtr, SPtr, Method, Notice> >
639  {
640  public:
641  typedef Notice NoticeType;
642  typedef typename LPtr::DataType ListenerType;
643  typedef Method MethodPtr;
644 
645  _Deliverer(LPtr const &listener,
646  MethodPtr const &methodPtr,
647  SPtr const &sender = SPtr(),
648  TfType const &noticeType = TfType())
649  : _listener(listener)
650  , _sender(sender)
651  , _method(methodPtr)
652  {
653  }
654 
655  void _InvokeListenerMethod(ListenerType *listener,
656  const NoticeType &notice,
657  const TfType &noticeType,
658  const TfWeakBase *,
659  const void *,
660  const std::type_info &)
661  {
662  (listener->*_method)(notice);
663  }
664 
665  LPtr _listener;
666  SPtr _sender;
667  MethodPtr _method;
668  };
669 
670  template <class LPtr, class Method>
671  class _RawDeliverer :
672  public _StandardDeliverer<_RawDeliverer<LPtr, Method> >
673  {
674  public:
675  typedef TfNotice NoticeType;
676  typedef typename LPtr::DataType ListenerType;
677  typedef Method MethodPtr;
678 
679  _RawDeliverer(LPtr const &listener,
680  MethodPtr const &methodPtr,
681  TfAnyWeakPtr const &sender,
682  TfType const &noticeType)
683  : _noticeType(noticeType),
684  _listener(listener),
685  _method(methodPtr),
686  _sender(sender)
687  {
688  }
689 
690  virtual TfType GetNoticeType() const {
691  return _noticeType;
692  }
693 
694  void _InvokeListenerMethod(ListenerType *listener,
695  const NoticeType &notice,
696  const TfType &noticeType,
697  const TfWeakBase *sender,
698  const void *senderUniqueId,
699  const std::type_info &senderType)
700  {
701  (listener->*_method)(notice, noticeType,
702  const_cast<TfWeakBase *>(sender),
703  senderUniqueId, senderType);
704  }
705 
706  TfType _noticeType;
707  LPtr _listener;
708  MethodPtr _method;
709  TfAnyWeakPtr _sender;
710  };
711 
712  template <class LPtr, class SPtr, class Method, class Notice>
713  class _DelivererWithSender :
714  public _StandardDeliverer<
715  _DelivererWithSender<LPtr, SPtr, Method, Notice>
716  >
717  {
718  public:
719  typedef Notice NoticeType;
720  typedef Method MethodPtr;
721  typedef typename LPtr::DataType ListenerType;
722 
723  typedef typename SPtr::DataType SenderType;
724 
725  _DelivererWithSender(LPtr const &listener,
726  MethodPtr const &methodPtr,
727  SPtr const &sender,
728  TfType const &noticeType = TfType())
729  : _listener(listener),
730  _sender(sender),
731  _method(methodPtr)
732  {
733  }
734 
735  void _InvokeListenerMethod(ListenerType *listener,
736  const NoticeType &notice,
737  const TfType &noticeType,
738  const TfWeakBase *sender,
739  const void *,
740  const std::type_info &)
741  {
742  SenderType *deliveredSender =
743  static_cast<SenderType *>(const_cast<TfWeakBase *>(sender));
744  SPtr deliveredSPtr(deliveredSender);
745  (listener->*_method)(notice, deliveredSPtr);
746  }
747 
748  LPtr _listener;
749  SPtr _sender;
750  MethodPtr _method;
751  };
752 
753 private:
754  // Internal non-templated function to install listeners.
755  TF_API
756  static Key _Register(_DelivererBase*);
757 
758  TF_API
759  static void _VerifyFailedCast(const std::type_info& toType,
760  const TfNotice& notice,
761  const TfNotice* castNotice);
762 
763  TF_API
764  size_t _Send(const TfWeakBase* sender,
765  const void *senderUniqueId,
766  const std::type_info & senderType) const;
767  TF_API
768  size_t _SendWithType(const TfType & noticeType,
769  const TfWeakBase* sender,
770  const void *senderUniqueId,
771  const std::type_info & senderType) const;
772 
773  friend class Tf_NoticeRegistry;
774 
775  // Befriend the wrapping so it can access _SendWithType() directly
776  // in order to provide dynamic downcasting of Python notice types.
777  friend class Tf_PyNotice;
778 };
779 
780 template <typename SenderPtr>
781 size_t
782 TfNotice::Send(SenderPtr const &s) const
783 {
784  const TfWeakBase *senderWeakBase = s ? s.GetWeakBase() : NULL;
785  return _Send(senderWeakBase, senderWeakBase ? s.GetUniqueIdentifier() : 0,
786  senderWeakBase ?
787  typeid(typename SenderPtr::DataType) : typeid(void));
788 }
789 
790 PXR_NAMESPACE_CLOSE_SCOPE
791 
792 #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
static void RemoveProbe(const WeakProbePtr &probe)
Remove a probe that was previously registered with InsertProbe.
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.
static void InsertProbe(const WeakProbePtr &probe)
Register a probe that will be invoked when notices are sent and delivered.
#define TF_FATAL_ERROR(fmt, args)
Issue a fatal error and end the program.
Definition: diagnostic.h:108
Blocks sending of all notices in current thread.
Definition: notice.h:451
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:359
Enable a concrete base class for use with TfWeakPtr.
Definition: weakBase.h:141