HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PDGT_RegisteredType.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * COMMENTS:
7  */
8 
9 #ifndef __PDGT_REGISTERED_TYPE_H__
10 #define __PDGT_REGISTERED_TYPE_H__
11 
12 #include "PDGT_API.h"
13 #include "PDGT_BaseType.h"
14 
15 #include <UT/UT_ConcurrentVector.h>
16 #include <UT/UT_Function.h>
17 #include <UT/UT_SharedPtr.h>
18 #include <UT/UT_WeakPtr.h>
19 #include <UT/UT_WorkBuffer.h>
20 
21 class PDGT_ValueArgs;
22 
23 /**
24  * This class represents a concrete type in a type system. It subclasses from
25  * PDGT_BaseType, and defines a number of new template arguments that describe
26  * the type. These include:
27  *
28  * The Class, which is the backing C++ class that this type will produce.
29  * For example, the PDG_NodeCallbackType produces instances of the
30  * PDG_NodeCallback class.
31  *
32  * The pointer type. If the pointer type is a shared pointer, this object
33  * will be able to safely tracking the list of instances created.
34  * Otherwise, instance tracking will be disabled and attempts to use the
35  * reload functionality will error out.
36  *
37  * The specfic entry in the EnumType that's associated with this type,
38  * for example PDG_RegistrationType::eNode.
39  *
40  * The variadic argument pack of constructor arguments that are needed to
41  * create instances of Class using type object.
42  *
43  * By default, a registered type expects to be given a functor to use to
44  * construct Class instances. A default functor which simply calls `new Class`
45  * with the appropriate args is already included. It is also possible to
46  * completely override the functor-based constructor and instead redefine the
47  * `instantiate` function to perform construction logic. This is done for
48  * Python-backed node/scheduler types in PDG, which implement part their
49  * construction logic in the PYPDG module using pybind11.
50  *
51  * An instance of this class provides three main pieces of functionality:
52  *
53  * The ability to construct new instances of Class, using logic defined
54  * by the type object and the input Args...
55  *
56  * Optional thread safe tracking of all instances of the type that have
57  * been created.
58  *
59  * And, assuming the tracking is enabled, the ability to run some sort of
60  * reloading logic. For example, for PDG nodes defined in Python, this
61  * functionality can be used to reload the Python module and recreate
62  * any underlying PyObjects used by the node callback type.
63  */
64 template <typename Class, typename Pointer, typename EnumType, EnumType Type, typename... Args>
66 {
67 public:
68  /// The factory function type, which returns a new instance of Class as a
69  /// Pointer.
70  using Function = UT_Function<Pointer (
73  const PDGT_ValueArgs& extra_args,
74  Args...)>;
75 
76  /// Array of instances that refer to Class objects created using this type.
77  /// The array contains weak references, which is why instance tracking can
78  /// only be enabled when Pointer is some sort of shared_ptr type.
79  using Instances = UT_ConcurrentVector<UT_WeakPtr<Class>>;
80 
81  /// The enum entry this registered type is associated with, from the
82  /// EnumType declared as a template argument.
83  static constexpr EnumType Enum = Type;
84 
85 
87  const UT_StringHolder& label,
89  bool track_instances)
90  : PDGT_BaseType<EnumType>(name, label, lang, Type)
91  , myTrackInstances(track_instances)
92  , myIsPrivate(false)
93  {
94  }
95 
96  ~PDGT_RegisteredType() override {}
97 
98  /// Constructs a new instance of Class using this registered type. If the
99  /// Pointer type is a raw pointer, the caller takes owernship of the object.
100  /// Otherwise, if Pointer is a shared pointer type, the ownership is of
101  /// course bound to the lifetime of that shared pointer. The caller is
102  /// responsible for making sure that they keep it alive for as long as
103  /// they need it.
104  Pointer instance(UT_WorkBuffer& errors,
105  const PDGT_ValueArgs& extra_args,
106  Args... args) const
107  {
108  Pointer instance =
109  instantiate(errors, extra_args, args...);
110  addInstance(instance);
111  return instance;
112  }
113 
114  /// Reloads a particular instance of Class, using this type object. This
115  /// is a "re-initialize" call, to reset whatever state in the Class*
116  /// instance is dependent on this type object.
118  const PDGT_ValueArgs& extra_args,
119  Class* instance,
120  Args... args) const
121  {
122  return reload(errors, extra_args, instance,
123  args...);
124  }
125 
126  /// Reloads this type object itself, and requests that each existing
127  /// instance of Class also resets itself. If Pointer is not a shared pointer
128  /// type, there will be no instances to reset.
129  bool reloadType(UT_WorkBuffer& errors)
130  {
131  bool result = reload(errors);
132  for (auto&& instance : myInstances)
133  {
134  if (auto p = instance.lock())
135  {
136  p->setReloading(true);
137  result &= p->reloadInstance(errors);
138  p->setReloading(false);
139  }
140  }
141  return result;
142  }
143 
144  /// Returns the combined memory usage of all instances of this type
145  int64 instanceMemoryUsage() const override
146  {
147  int64 mem = 0;
148  for (auto&& instance : myInstances)
149  {
150  if (auto p = instance.lock())
151  mem += p->getMemoryUsage(true);
152  }
153 
154  return mem;
155  }
156 
157  /// Sets the factory function to use when contructing Class instances.
158  void setFunction(const Function& function)
159  { myFunction = function; }
160 
161  /// Sets the isPrivate flag
162  void setIsPrivate(bool is_private)
163  { myIsPrivate = is_private; }
164 
165  /// Returns true if the type is private
166  bool isPrivate() const
167  { return myIsPrivate; }
168 
169  /// Default factory method, which simple allocates a new instance of
170  /// ConcreteType, which much be Class or some subclass of it. The object
171  /// is returned as Pointer.
172  template <typename ConcreteType>
173  static Pointer typeInit(const PDGT_BaseType<EnumType>* type,
174  UT_WorkBuffer& errors,
175  const PDGT_ValueArgs& extra_args,
176  Args... args)
177  {
178  return Pointer(
179  new ConcreteType(type, extra_args, args...));
180  }
181 
182 protected:
183  /// These methods conditionally enable instance tracking. We can only safely
184  /// keep weak-refs to the instances if our Pointer type is a shared ptr, so
185  /// an overload to addInstance that's conditional on that being the case
186  /// is required. It's also possible to disable instance tracking with a
187  /// member variable, so that gets checked in the codepath that may actually
188  /// append an instance to our tracking vector.
189  template <typename P = Pointer>
190  typename std::enable_if<std::is_same<P, UT_SharedPtr<Class>>::value>::type
191  addInstance(P instance) const
192  {
193  if (myTrackInstances)
194  myInstances.push_back(instance);
195  }
196  template <typename P = Pointer>
197  typename std::enable_if<!std::is_same<P, UT_SharedPtr<Class>>::value>::type
198  addInstance(P instance) const
199  {
200  }
201 
203  {
204  return instance.lock();
205  }
206 
207 
208  /// This function is responsible for constructing an instance of Class. It
209  /// uses the functor by default, but subclasses are permitted to redefine
210  /// it to construct objects in a different way.
211  virtual Pointer instantiate(UT_WorkBuffer& errors,
212  const PDGT_ValueArgs& extra_args,
213  Args... variadic_args) const
214  {
215  if (!myFunction)
216  {
217  errors.appendFormat(
218  "Incomplete or invalid type '{}'",
220  }
221 
222  return myFunction(this, errors, extra_args,
223  variadic_args...);
224  }
225 
226  /// This function is responsible for reloading this type object itself.
227  /// For example, for a Python-backed node as defined in the PYPDG module,
228  /// this function will reload the underlying Python module.
229  virtual bool reload(UT_WorkBuffer& errors)
230  {
231  errors.format(
232  "Type '{}' does not support reloading",
234  return false;
235  }
236 
237  /// This function is responsible for reloading a particular instance of
238  /// Class created using this type object. By default, it does nothing, but
239  /// subclasses that wish to support reloading should customize it. For
240  /// example, the PYPDG subclass will use this hook to reconstruct the Py
241  /// Object inside of a PDG_NodeCallback, when reloading that instance.
242  virtual bool reload(UT_WorkBuffer& errors,
243  const PDGT_ValueArgs& extra_args,
244  Class* instance,
245  Args... variadic_args) const
246  {
247  errors.format(
248  "Instances of type '{}' cannot be reloaded",
250  return false;
251  }
252 
253 private:
254  Function myFunction;
255  mutable Instances myInstances;
256  bool myTrackInstances;
257  bool myIsPrivate;
258 };
259 
260 #endif
void setFunction(const Function &function)
Sets the factory function to use when contructing Class instances.
bool reloadType(UT_WorkBuffer &errors)
PXL_API void reload()
Reload the configuration.
virtual Pointer instantiate(UT_WorkBuffer &errors, const PDGT_ValueArgs &extra_args, Args...variadic_args) const
GLuint GLsizei const GLchar * label
Definition: glcorearb.h:2545
void setIsPrivate(bool is_private)
Sets the isPrivate flag.
UT_ConcurrentVector< UT_WeakPtr< Class >> Instances
virtual bool reload(UT_WorkBuffer &errors, const PDGT_ValueArgs &extra_args, Class *instance, Args...variadic_args) const
**But if you need a result
Definition: thread.h:613
int64 instanceMemoryUsage() const override
Returns the combined memory usage of all instances of this type.
bool reloadInstance(UT_WorkBuffer &errors, const PDGT_ValueArgs &extra_args, Class *instance, Args...args) const
std::enable_if<!std::is_same< P, UT_SharedPtr< Class > >::value >::type addInstance(P instance) const
static Pointer typeInit(const PDGT_BaseType< EnumType > *type, UT_WorkBuffer &errors, const PDGT_ValueArgs &extra_args, Args...args)
Pointer instance(UT_WorkBuffer &errors, const PDGT_ValueArgs &extra_args, Args...args) const
size_t appendFormat(const char *fmt, const Args &...args)
std::shared_ptr< T > UT_SharedPtr
Wrapper around std::shared_ptr.
Definition: UT_SharedPtr.h:36
#define PDGT_API_TMPL
Definition: PDGT_API.h:24
long long int64
Definition: SYS_Types.h:116
virtual bool reload(UT_WorkBuffer &errors)
GLuint const GLchar * name
Definition: glcorearb.h:786
UT_Array< PDGT_Value > Args
std::function< T > UT_Function
Definition: UT_Function.h:37
size_t format(const char *fmt, const Args &...args)
UT_SharedPtr< Class > lockInstance(UT_WeakPtr< Class > instance) const
**If you just want to fire and args
Definition: thread.h:609
UT_Function< Pointer(const PDGT_BaseType< EnumType > *, UT_WorkBuffer &, const PDGT_ValueArgs &extra_args, Args...)> Function
std::enable_if< std::is_same< P, UT_SharedPtr< Class > >::value >::type addInstance(P instance) const
Definition: core.h:1131
PDGT_RegisteredType(const UT_StringHolder &name, const UT_StringHolder &label, typename PDGT_BaseType< EnumType >::Language lang, bool track_instances)
type
Definition: core.h:1059
std::weak_ptr< T > UT_WeakPtr
Definition: UT_SharedPtr.h:49
bool isPrivate() const
Returns true if the type is private.