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 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 TF_NOTICE_H
25 #define 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 // TF_NOTICE_H
Handle-object returned by TfNotice::Register().
Definition: notice.h:256
TO TfSafeDynamic_cast(FROM *ptr)
Safely perform a dynamic cast.
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.
std::vector< Key > Keys
A TfNotice::Key container.
Definition: notice.h:289
Provides the ability to hold an arbitrary TfWeakPtr in a non-type-specific manner in order to observe...
Definition: anyWeakPtr.h:55
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...
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:111
TF_API bool IsA(TfType queryType) const
Return true if this type is the same as or derived from queryType.
Blocks sending of all notices in current thread.
Definition: notice.h:451
bool IsUnknown() const
Return true if this is the unknown type, representing a type unknown to the TfType system...
Definition: type.h:390
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 Send() const
Deliver the notice to interested listeners, returning the number of interested listeners.
TfType represents a dynamic runtime type.
Definition: type.h:70
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.
bool IsValid() const
Does this key refer to a valid notification?
Definition: notice.h:264
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:142