HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PDGT_TypeRegistry.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_TYPE_REGISTRY_H__
10 #define __PDGT_TYPE_REGISTRY_H__
11 
12 #include "PDGT_API.h"
13 
14 #include "PDGT_BaseType.h"
15 #include "PDGT_Types.h"
16 #include "PDGT_Utils.h"
17 
18 #include <UT/UT_SharedPtr.h>
19 #include <UT/UT_StringArray.h>
20 #include <UT/UT_StringHolder.h>
21 #include <UT/UT_StringMap.h>
22 #include <UT/UT_StringSet.h>
23 #include <UT/UT_WorkBuffer.h>
24 
25 #include <SYS/SYS_Time.h>
26 
27 #include <utility>
28 
29 /**
30  * Base class for a PDGT type system, which consists of a table of EnumType ->
31  * PDGT_Registered type. The number of entries in the table is defined by the
32  * number of distinct entries in the EnumType enumeration.
33  *
34  * The type registry is the central place that holds the registered type
35  * objects, as well as logic needed to load them from shared libraries or
36  * Python definitions.
37  */
38 template <typename EnumType, int EnumSize>
40 {
41 public:
42  /// Self type def
44 
45 protected:
46  /// PDGT_BaseType spiicalization for this type registry
48 
49  /// Shared ptr to a registered PDG type
51 
52  /// Map of type name to shared ptr
54 
55 protected:
56 
57  /// Construct is protected since only this class and
58  /// subclasses can create instances of itself.
59  PDGT_TypeRegistry(const UT_StringHolder& dso_function,
60  const UT_StringHolder& module_name)
61  : myDSOFunction(dso_function)
62  , myModuleName(module_name)
63  , myApplicationType(PDGT_ApplicationType::eUnknown)
64  , myInitFlag(false)
65  , myEnableRegistration(true)
66  {
67  }
68 
69 public:
70  virtual ~PDGT_TypeRegistry() {}
71 
72  /// Standard initialization of the types, which loads built in Python
73  /// modules first, then user defined Python types, then C++ types. The
74  /// reason for this being a method and not part of construction is there
75  /// certain use cases that want to have an empty type table, for example
76  /// unit testing or users with entirely custom nodes.
78  PDGT_ApplicationType app_type,
79  bool skip_python=false)
80  {
81  if (myInitFlag)
82  return true;
83 
84 
85  fpreal start = SYStime();
86 
87  myApplicationType = app_type;
88  bool success = true;
89  if (!skip_python)
90  success &= registerPythonModules(errors);
91 
92  success &= registerDSOTypes();
93  myInitFlag = true;
94 
96  buffer.format("Total Time {}s", SYStime()-start);
97  handleLogMessage(
99  buffer.buffer(),
100  "LOAD DONE");
101 
102  return success;
103  }
104 
105  /// Clears and deletes everything in the type registry
106  void clear()
107  {
108  for (int i = 0; i < EnumSize; i++)
109  myTypes[i].clear();
110  }
111 
112  /// Enables or disables custom type registration
114  {
115  myEnableRegistration = enabled;
116  }
117 
118  /// Registers a type using a pointer to the type object. Errors are
119  /// returned in the error buffer parameter
120  template <typename RegType, typename... Args>
121  RegType* registerType(UT_WorkBuffer& errors,
122  const UT_StringHolder& name,
123  Args&&... args)
124  {
125  if (!myEnableRegistration)
126  return nullptr;
127 
128  if (name.isEmpty())
129  {
130  errors.appendFormat("Empty type name");
131  return nullptr;
132  }
133 
134  TypeMap& type_map = myTypes[(int)(RegType::Enum)];
135  BaseType* existing_type =
136  registeredType(RegType::Enum, name);
137 
138  if (existing_type)
139  {
140  errors.appendFormat(
141  "A type already exists with the name {}",
142  name);
143  return nullptr;
144  }
145 
146  RegType* new_type = new RegType(
147  name, std::forward<Args>(args)...);
148  type_map[name] = pdg_BaseTypePtr(new_type);
149  if (!new_type->initialize(errors))
150  {
151  if (errors.length() > 0)
152  errors.append(". ");
153  errors.appendFormat(
154  "Failed to initialize type {}", name);
155  type_map.erase(name);
156  return nullptr;
157  }
158 
159  handleLogMessage(
161  new_type->displayName(),
162  "ADD");
163 
164  return new_type;
165  }
166 
167  /// Registers a type that implements it's construction logic in a function,
168  /// rather than a custom class
169  template <typename RegType, typename... Args>
170  RegType* registerFuncType(UT_WorkBuffer& errors,
171  const UT_StringHolder& name,
172  typename RegType::Function func,
173  Args&&... args)
174  {
175  RegType* reg_type = registerType<RegType>(
176  errors, name, std::forward<Args>(args)...);
177 
178  if (!reg_type)
179  return nullptr;
180 
181  reg_type->setFunction(func);
182  return reg_type;
183  }
184 
185  /// Registers a type that uses the simple built-in function, which creates
186  /// and instance of the type using it's constructor and does no additional
187  /// logic
188  template <typename RegType, typename ClassType, typename... Args>
190  const UT_StringHolder& name,
191  Args&&... args)
192  {
193  return registerFuncType<RegType>(
194  errors,
195  name,
196  &RegType::template typeInit<ClassType>,
197  std::forward<Args>(args)...);
198  }
199 
200  /// Registers an alias for an existing type
201  bool registerTypeAlias(EnumType type,
202  const UT_StringHolder& name,
203  const UT_StringHolder& alias,
204  bool deprecated=false)
205  {
206  TypeMap& type_map = myTypes[(int)(type)];
207 
208  if (type_map.contains(alias))
209  return false;
210 
211  auto iter = type_map.find(name);
212  if (iter == type_map.end())
213  return false;
214 
216  message.format("{} -> {}", name, alias);
217  handleLogMessage(
219  message,
220  "ALIAS");
221 
222  if (deprecated)
223  deprecateType(type, alias);
224 
225  myTypes[(int)(type)][alias] = iter->second;
226  myAliases[(int)(type)].insert(alias);
227 
228  return true;
229  }
230 
231  /// Adds parent types to the type object.
233  const UT_StringArray& parent_names,
234  UT_WorkBuffer& errors)
235  {
236  EnumType reg_type = type->type();
237  for (auto&& parent_name : parent_names)
238  {
239  BaseType* parent = registeredType(
240  reg_type, parent_name);
241  if (!parent)
242  {
243  errors.appendFormat(
244  "{} not a valid type name",
245  parent_name);
246  return false;
247  }
248 
249  type->addParent(parent, true);
250  }
251 
252  return true;
253  }
254 
255  /// Directly adds a parent type, if it's valid
257  BaseType* parent,
258  UT_WorkBuffer& errors)
259  {
260  if (!parent)
261  {
262  errors.appendFormat(
263  "Empty parent type for '{}'",
264  type->typeName());
265  return false;
266  }
267 
268  if (type->type() != parent->type())
269  {
270  errors.appendFormat(
271  "Invalid parent type '{}' for '{}",
272  parent->typeName(),
273  type->typeName());
274  return false;
275  }
276 
277  type->addParent(parent, true);
278  return true;
279  }
280 
281  /// Loads and registers types compiled as a shared library
282  bool registerDSOTypes(const UT_StringHolder& dso_path)
283  {
284  return PDGT_Utils::loadDSO(
285  dso_path, myDSOFunction, (void*)this);
286  }
287 
288  /// Loads and registers types that are in DSOs on the PDG shared library
289  /// path, e.g. <dso_path>/pdg
291  {
292  return PDGT_Utils::loadDSO(
293  myDSOFunction, (void*)this);
294  }
295 
296  /// Registers all Python types on the PDG/types search path
298  {
300  myModuleName, errors);
301  }
302 
303  /// Registers a Python module by absolute path
305  UT_WorkBuffer& errors)
306  {
308  myModuleName, path, errors);
309  }
310 
311  /// Reloads a Python module by name
313  bool reregister,
314  UT_WorkBuffer& errors)
315  {
317  myModuleName, path, reregister, errors);
318  }
319 
320  /// Returns a generic type object for a given registered type and typename
322  const UT_StringHolder& name) const
323  {
324  auto iter = myTypes[(int)(type)].find(name);
325  if (iter == myTypes[(int)(type)].end())
326  return nullptr;
327 
328  if (myDeprecatedTypes[(int)(type)].contains(name))
329  {
330  handleLogMessage(
332  name,
333  "DEPRECATED");
334  }
335 
336  return iter->second.get();
337  }
338 
339  /// Deprecated a type name, so that accessing it will issue an warning
340  void deprecateType(EnumType type, const UT_StringHolder& name)
341  {
342  myDeprecatedTypes[(int)(type)].insert(name);
343  }
344 
345  /// Returns the set of all existing type names for registered type
346  UT_StringArray typeNames(EnumType type, bool include_aliases=false) const
347  {
348  const auto& aliases = myAliases[(int)(type)];
349 
350  UT_StringArray type_names;
351  for (auto&& entry : myTypes[(int)(type)])
352  {
353  if (!include_aliases)
354  {
355  if (aliases.contains(entry.first))
356  continue;
357  }
358 
359  type_names.append(entry.first);
360  }
361 
362  return type_names;
363  }
364 
365  /// Returns the application type, as determined when the type table
366  /// was initialized
369  { return myApplicationType; }
370 
371 private:
372  /// Handles reporting log messages, implemented by concrete subclass so
373  /// they can use their own logging mechanism
374  virtual void handleLogMessage(
376  const UT_StringHolder& message,
377  const UT_StringHolder& tag) const {}
378 
379 private:
380  TypeMap myTypes[EnumSize];
381  UT_StringSet myDeprecatedTypes[EnumSize];
382  UT_StringSet myAliases[EnumSize];
383  UT_StringHolder myDSOFunction;
384  UT_StringHolder myModuleName;
385 
387  myApplicationType;
388 
389  bool myInitFlag;
390  bool myEnableRegistration;
391 };
392 
393 #endif
GLuint GLsizei const GLchar * message
Definition: glcorearb.h:2543
typedef int(APIENTRYP RE_PFNGLXSWAPINTERVALSGIPROC)(int)
PDGT_ApplicationType applicationType() const
bool reloadPythonModule(const UT_StringHolder &path, bool reregister, UT_WorkBuffer &errors)
Reloads a Python module by name.
SYS_FORCE_INLINE exint length() const
BaseType * registeredType(EnumType type, const UT_StringHolder &name) const
Returns a generic type object for a given registered type and typename.
bool registerPythonModules(UT_WorkBuffer &errors)
Registers all Python types on the PDG/types search path.
GLuint start
Definition: glcorearb.h:475
GLsizei const GLchar *const * path
Definition: glcorearb.h:3341
RegType * registerType(UT_WorkBuffer &errors, const UT_StringHolder &name, Args &&...args)
bool isEmpty() const
Same as !isstring()
UT_StringArray typeNames(EnumType type, bool include_aliases=false) const
Returns the set of all existing type names for registered type.
GLint level
Definition: glcorearb.h:108
SYS_FORCE_INLINE const char * buffer() const
void clear()
Clears and deletes everything in the type registry.
void addParent(const PDGT_BaseType *type, bool recurse=true)
Definition: PDGT_BaseType.h:98
void setRegistrationEnabled(bool enabled)
Enables or disables custom type registration.
bool registerPythonPath(const UT_StringHolder &path, UT_WorkBuffer &errors)
Registers a Python module by absolute path.
const UT_StringHolder & typeName() const
Definition: PDGT_BaseType.h:65
GLenum GLenum GLsizei const GLuint GLboolean enabled
Definition: glcorearb.h:2539
PDGT_TypeErrorLevel
Error level typedef.
Definition: PDGT_Types.h:13
GLuint buffer
Definition: glcorearb.h:660
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
GLuint GLuint end
Definition: glcorearb.h:475
#define PDGT_API_TMPL
Definition: PDGT_API.h:24
bool standardInit(UT_WorkBuffer &errors, PDGT_ApplicationType app_type, bool skip_python=false)
virtual ~PDGT_TypeRegistry()
static bool loadDSO(const UT_StringHolder &dso_path, const UT_StringHolder &dso_function, void *dso_arg)
iterator erase(const_iterator pos)
Definition: UT_StringMap.h:58
bool addParentType(BaseType *type, BaseType *parent, UT_WorkBuffer &errors)
Directly adds a parent type, if it's valid.
RegType * registerSimpleType(UT_WorkBuffer &errors, const UT_StringHolder &name, Args &&...args)
static bool loadPythonPath(const UT_StringHolder &type_module, const UT_StringHolder &path, UT_WorkBuffer &errors)
Loads PDG types from a Python module at a specifc path on the system.
GLuint const GLchar * name
Definition: glcorearb.h:786
SYS_API fpreal SYStime()
bool addParentTypes(BaseType *type, const UT_StringArray &parent_names, UT_WorkBuffer &errors)
Adds parent types to the type object.
bool registerTypeAlias(EnumType type, const UT_StringHolder &name, const UT_StringHolder &alias, bool deprecated=false)
Registers an alias for an existing type.
exint append()
Definition: UT_Array.h:142
void deprecateType(EnumType type, const UT_StringHolder &name)
Deprecated a type name, so that accessing it will issue an warning.
PDGT_TypeRegistry(const UT_StringHolder &dso_function, const UT_StringHolder &module_name)
size_t format(const char *fmt, const Args &...args)
GLenum func
Definition: glcorearb.h:783
PDGT_ApplicationType
Definition: PDGT_Types.h:32
static bool loadPythonModules(const UT_StringHolder &type_module, UT_WorkBuffer &errors)
fpreal64 fpreal
Definition: SYS_Types.h:277
SYS_FORCE_INLINE void append(char character)
bool registerDSOTypes(const UT_StringHolder &dso_path)
Loads and registers types compiled as a shared library.
**If you just want to fire and args
Definition: thread.h:609
RegType * registerFuncType(UT_WorkBuffer &errors, const UT_StringHolder &name, typename RegType::Function func, Args &&...args)
UT_SharedPtr< BaseType > pdg_BaseTypePtr
Shared ptr to a registered PDG type.
EnumType type() const
Definition: PDGT_BaseType.h:77
bool OIIO_UTIL_API contains(string_view a, string_view b)
Does 'a' contain the string 'b' within it?
type
Definition: core.h:1059
The application type has yet to be determined.
static bool reloadPythonModule(const UT_StringHolder &type_module, const UT_StringHolder &python_module, bool reregister, UT_WorkBuffer &errors)
Reloads the PDG type from the specified Python module.
bool contains(const key_type &key) const
Returns true if a value with the key is contained in the map.
Definition: UT_Map.h:159