NVIDIA NvNeural SDK  2022.2
GPU inference framework for NVIDIA Nsight Deep Learning Designer
RefObject.h
Go to the documentation of this file.
1 /*
2 * SPDX-FileCopyrightText: Copyright (c) 2020-2021 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3 * SPDX-License-Identifier: MIT
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23 
25 
26 #ifndef NVNEURAL_REFOBJ_H
27 #define NVNEURAL_REFOBJ_H
28 
29 #if __has_include(<typeinfo>)
30 #include <typeinfo>
31 #endif
32 #include <atomic>
33 #include <utility>
34 
39 #define NVNEURAL_REFOBJ_REFERENCE_CALLBACKS 0
40 
41 namespace nvneural {
42 
43 ILogger* DefaultLogger(); // forward declaration from CoreHelpers.h
44 
45 namespace refobj {
46 
53 
61 {
63  struct BaseType {};
64 
66  template<typename TObject>
67  static void* querySingleInterface(IRefObject::TypeId, TObject*)
68  {
69  return nullptr;
70  }
71 
73  template<typename TObject>
74  static const void* querySingleInterface(IRefObject::TypeId, const TObject*)
75  {
76  return nullptr;
77  }
78 
80  static const bool EnableLogging = false;
81 };
82 
91 template<typename TBaseType>
92 struct PublicBase final
93 {
97  using BaseType = TBaseType;
98 
104 
106  template<typename TObject>
107  static void* querySingleInterface(IRefObject::TypeId, TObject*)
108  {
109  return nullptr;
110  }
111 
113  template<typename TObject>
114  static const void* querySingleInterface(IRefObject::TypeId, const TObject*)
115  {
116  return nullptr;
117  }
118 
120 
122  static const bool EnableLogging = true;
123 };
124 
134 template<typename TInterface>
135 struct Implements final
136 {
140  using BaseType = TInterface;
141 
152 
158  template<typename TObject>
159  static void* querySingleInterface(IRefObject::TypeId interfaceId, TObject* me)
160  {
161  if (interfaceId == InterfaceOf<TInterface>::value)
162  {
163  return static_cast<TInterface*>(me);
164  }
165  return nullptr;
166  }
167 
173  template<typename TObject>
174  static const void* querySingleInterface(IRefObject::TypeId interfaceId, const TObject* me)
175  {
176  if (interfaceId == InterfaceOf<TInterface>::value)
177  {
178  return static_cast<const TInterface*>(me);
179  }
180  return nullptr;
181  }
182 
184 
186  static const bool EnableLogging = true;
187 };
188 
204 template<typename TInterface, typename TIntermediateType>
206 {
207  // Sanity-check that TInterface is an indirect base class of TIntermediateType.
208  static_assert(std::is_base_of<TInterface, TIntermediateType>::value, "Interface is not a base of the intermediate type");
209 
215  struct BaseType {};
216 
227 
233  template<typename TObject>
234  static void* querySingleInterface(IRefObject::TypeId interfaceId, TObject* me)
235  {
236  if (interfaceId == InterfaceOf<TInterface>::value)
237  {
238  return static_cast<TInterface*>(static_cast<TIntermediateType*>(me));
239  }
240  return nullptr;
241  }
242 
248  template<typename TObject>
249  static const void* querySingleInterface(IRefObject::TypeId interfaceId, const TObject* me)
250  {
251  if (interfaceId == InterfaceOf<TInterface>::value)
252  {
253  return static_cast<const TInterface*>(static_cast<const TIntermediateType*>(me));
254  }
255  return nullptr;
256  }
258 
260  static const bool EnableLogging = true;
261 };
262 
264 
334 template<typename... ParameterList>
335 struct RefObjectBase : public ParameterList::BaseType...
336 {
339  {
340  if (LoggingEnabled)
341  {
342  logLifetimeChange("%p: Creating", this);
343  }
344  }
345 
349  IRefObject::RefCount addRef() const noexcept override
350  {
351  const auto newRefCount = ++m_refCount;
352 
353  if (LoggingEnabled)
354  {
355  logLifetimeChange("%p: %s: Increment ref count to %d", this, thisTypeName(), newRefCount);
356  }
357 
358 #if NVNEURAL_REFOBJ_REFERENCE_CALLBACKS
359  addRefCallback();
360 #endif
361 
362  return newRefCount;
363  }
364 
368  IRefObject::RefCount release() const noexcept override
369  {
370  const auto newRefCount = --m_refCount;
371 
372  if (LoggingEnabled)
373  {
374  logLifetimeChange("%p: %s: Decrement ref count to %d", this, thisTypeName(), newRefCount);
375  }
376 
377 #if NVNEURAL_REFOBJ_REFERENCE_CALLBACKS
378  releaseCallback();
379 #endif
380  if (!newRefCount)
381  {
382  if (LoggingEnabled)
383  {
384  logLifetimeChange("%p: %s: Destroying", this, thisTypeName());
385  }
386  delete this;
387  }
388  return newRefCount;
389  }
390 
401  void* queryInterface(IRefObject::TypeId interfaceId) noexcept override
402  {
403  // Special handling for IRefObject, because we know we support that one
404  if (interfaceId == IRefObject::typeID)
405  {
406  addRef();
407  return this;
408  }
409 
410  // Expanding ParameterList into a series of (ParameterList1*) nullptr, (ParameterList2*) nullptr, ...
411  // arguments allows us to use a classically recursive queryInterfaceImpl helper function and terminate
412  // normally when we get down to zero remaining arguments; parameterizing as qii<PL...>(iid) doesn't
413  // allow us to define a termination case; qii<PL...>(iid) and qii(iid) both handle the zero-argument
414  // overload scenario and result in ambiguous overload errors.
415  const auto pResult = queryInterfaceImpl(interfaceId, static_cast<ParameterList*>(nullptr)...);
416  return pResult;
417  }
418 
420  const void* queryInterface(IRefObject::TypeId interfaceId) const noexcept override
421  {
422  // Special handling for IRefObject, because we know we support that one
423  if (interfaceId == IRefObject::typeID)
424  {
425  addRef();
426  return this;
427  }
428 
429  // Expanding ParameterList into a series of (ParameterList1*) nullptr, (ParameterList2*) nullptr, ...
430  // arguments allows us to use a classically recursive queryInterfaceImpl helper function and terminate
431  // normally when we get down to zero remaining arguments; parameterizing as qii<PL...>(iid) doesn't
432  // allow us to define a termination case; qii<PL...>(iid) and qii(iid) both handle the zero-argument
433  // overload scenario and result in ambiguous overload errors.
434  const auto pResult = queryInterfaceImpl(interfaceId, static_cast<ParameterList*>(nullptr)...);
435  return pResult;
436  }
437 
438 private:
439  template<typename ImplementsHelper, typename... OtherHelpers>
440  constexpr static bool enableLoggingImpl(ImplementsHelper* /*thisInterface*/, OtherHelpers... others)
441  {
442  if (!ImplementsHelper::EnableLogging)
443  {
444  return false;
445  }
446  return enableLoggingImpl(others...);
447  }
448  constexpr static bool enableLoggingImpl()
449  {
450  return true;
451  }
452  constexpr static const bool LoggingEnabled = enableLoggingImpl(static_cast<ParameterList*>(nullptr)...);
453 
463  template<typename ImplementsHelper, typename... OtherHelpers>
464  void* queryInterfaceImpl(IRefObject::TypeId interfaceId, ImplementsHelper* /*thisInterface*/, OtherHelpers... others)
465  {
466  void* const pResult = ImplementsHelper::querySingleInterface(interfaceId, this);
467  if (pResult)
468  {
469  addRef();
470  return pResult;
471  }
472  return queryInterfaceImpl(interfaceId, others...);
473  }
474 
476  template<typename ImplementsHelper, typename... OtherHelpers>
477  const void* queryInterfaceImpl(IRefObject::TypeId interfaceId, ImplementsHelper* /*thisInterface*/, OtherHelpers... others) const
478  {
479  const void* const pResult = ImplementsHelper::querySingleInterface(interfaceId, this);
480  if (pResult)
481  {
482  addRef();
483  return pResult;
484  }
485  return queryInterfaceImpl(interfaceId, others...);
486  }
487 
489  void* queryInterfaceImpl(IRefObject::TypeId)
490  {
491  return nullptr;
492  }
493 
495  const void* queryInterfaceImpl(IRefObject::TypeId) const
496  {
497  return nullptr;
498  }
499 
504  template<typename... TFormatArgs>
505  static void logLifetimeChange(const char* pFormatString, TFormatArgs... formatArgs)
506  {
507  const ILogger::VerbosityLevel logVerbosity = 3;
508 
509  // Even the null DefaultLogger may not have constructed fully yet; it too
510  // might be implemented using RefObjectBase.
511  if (const auto pLogger = DefaultLogger())
512  {
513  pLogger->log(logVerbosity, pFormatString, formatArgs...);
514  }
515  }
516 
518  const char* thisTypeName() const
519  {
520 #if __cpp_rtti
521  // abi::__cxa_demangle in <cxxabi.h> would be interesting here, but
522  // involves a round-trip through the dynamic allocator.
523  // (There's no way to prevent realloc() from happening on small buffers.)
524  // For now, just use obfuscated names in GCC builds. Most top-level (i.e.,
525  // not RefObjectBase<X<T>,X<T2>,Y<T3,T4>,...> variant) class names have
526  // been fairly easy to recognize in obfuscated form so far.
527  return typeid(*this).name();
528 #else
529  // Degrade predictably if RTTI is disabled
530  return "<>";
531 #endif
532  }
533 
534 #if NVNEURAL_REFOBJ_REFERENCE_CALLBACKS
535  virtual void addRefCallback() const { }
536  virtual void releaseCallback() const { }
537 #endif
538 
540  mutable std::atomic<IRefObject::RefCount> m_refCount{1u};
541 };
542 
543 }} // namespace nvneural::refobj
544 
545 #endif // NVNEURAL_REFOBJ_H
ILogger * DefaultLogger()
Returns a pointer to the default logger for this module.
Definition: Logging.cpp:38
std::int32_t VerbosityLevel
Typedef for verbosity levels.
Definition: CoreTypes.h:424
static const TypeId typeID
Interface TypeId for InterfaceOf purposes.
Definition: CoreTypes.h:352
std::uint64_t TypeId
Every interface must define a unique TypeId. This should be randomized.
Definition: CoreTypes.h:349
std::uint32_t RefCount
Typedef used to track the number of active references to an object.
Definition: CoreTypes.h:346
Helper template to aid retrieval of interface IDs.
Definition: CoreTypes.h:403
No base types are provided by this trait.
Definition: RefObject.h:63
Disables log messages when the object refcount changes.
Definition: RefObject.h:61
static void * querySingleInterface(IRefObject::TypeId, TObject *)
No interfaces are provided by this trait.
Definition: RefObject.h:67
static const bool EnableLogging
Prevents logging messages.
Definition: RefObject.h:80
static const void * querySingleInterface(IRefObject::TypeId, const TObject *)
No interfaces are provided by this trait.
Definition: RefObject.h:74
Helper class for RefObjectBase indicating direct inheritance.
Definition: RefObject.h:136
static const void * querySingleInterface(IRefObject::TypeId interfaceId, const TObject *me)
Const querySingleInterface implementation.
Definition: RefObject.h:174
static const bool EnableLogging
This trait normally allows lifecycle logging.
Definition: RefObject.h:186
TInterface BaseType
Provide TInterface as a recommended base type.
Definition: RefObject.h:140
static void * querySingleInterface(IRefObject::TypeId interfaceId, TObject *me)
Non-const querySingleInterface implementation.
Definition: RefObject.h:159
Provide an empty struct as a recommended base type.
Definition: RefObject.h:215
Helper class for RefObjectBase indicating interface support without direct inheritance.
Definition: RefObject.h:206
static const void * querySingleInterface(IRefObject::TypeId interfaceId, const TObject *me)
Const querySingleInterface implementation.
Definition: RefObject.h:249
static const bool EnableLogging
This trait normally allows lifecycle logging.
Definition: RefObject.h:260
static void * querySingleInterface(IRefObject::TypeId interfaceId, TObject *me)
Non-const querySingleInterface implementation.
Definition: RefObject.h:234
Helper class for RefObjectBase indicating direct inheritance without providing interfaces.
Definition: RefObject.h:93
TBaseType BaseType
Provide TBaseType as a base type.
Definition: RefObject.h:97
static const bool EnableLogging
This trait normally allows lifecycle logging.
Definition: RefObject.h:122
static void * querySingleInterface(IRefObject::TypeId, TObject *)
Non-const querySingleInterface implementation. Returns nullptr.
Definition: RefObject.h:107
static const void * querySingleInterface(IRefObject::TypeId, const TObject *)
Const querySingleInterface implementation. Returns nullptr.
Definition: RefObject.h:114
Parameterized base class implementing common IRefObject operations.
Definition: RefObject.h:336
RefObjectBase()
Default constructor. Logs object creation.
Definition: RefObject.h:338
void * queryInterface(IRefObject::TypeId interfaceId) noexcept
Retrieves a new object interface pointer.
Definition: RefObject.h:401
IRefObject::RefCount addRef() const noexcept
Increment the object's reference count.
Definition: RefObject.h:349
IRefObject::RefCount release() const noexcept
Decrements the object's reference count and destroys the object if the reference count reaches zero.
Definition: RefObject.h:368
const void * queryInterface(IRefObject::TypeId interfaceId) const noexcept
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: RefObject.h:420