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 <utility>
26 
27 /**
28  * Base class for a PDGT type system, which consists of a table of EnumType ->
29  * PDGT_Registered type. The number of entries in the table is defined by the
30  * number of distinct entries in the EnumType enumeration.
31  *
32  * The type registry is the central place that holds the registered type
33  * objects, as well as logic needed to load them from shared libraries or
34  * Python definitions.
35  */
36 template <typename EnumType, int EnumSize>
38 {
39 public:
40  /// Self type def
42 
43 protected:
44  /// PDGT_BaseType spiicalization for this type registry
46 
47  /// Shared ptr to a registered PDG type
49 
50  /// Map of type name to shared ptr
52 
53 protected:
54 
55  /// Construct is protected since only this class and
56  /// subclasses can create instances of itself.
57  PDGT_TypeRegistry(const UT_StringHolder& dso_function,
58  const UT_StringHolder& module_name)
59  : myInitFlag(false)
60  , myDSOFunction(dso_function)
61  , myModuleName(module_name)
62  , myEnableRegistration(true)
63  {
64  }
65 
66 public:
67  virtual ~PDGT_TypeRegistry() {}
68 
69  /// Standard initialization of the types, which loads built in Python
70  /// modules first, then user defined Python types, then C++ types. The
71  /// reason for this being a method and not part of construction is there
72  /// certain use cases that want to have an empty type table, for example
73  /// unit testing or users with entirely custom nodes.
75  bool skip_python=false)
76  {
77  if (myInitFlag)
78  return true;
79 
80  bool success = true;
81  if (!skip_python)
82  success &= registerPythonModules(errors);
83 
84  success &= registerDSOTypes();
85 
86  myInitFlag = true;
87  return success;
88  }
89 
90  /// Clears and deletes everything in the type registry
91  void clear()
92  {
93  for (int i = 0; i < EnumSize; i++)
94  myTypes[i].clear();
95  }
96 
97  /// Enables or disables custom type registration
99  {
100  myEnableRegistration = enabled;
101  }
102 
103  /// Registers a type using a pointer to the type object. Errors are
104  /// returned in the error buffer parameter
105  template <typename RegType, typename... Args>
106  RegType* registerType(UT_WorkBuffer& errors,
107  const UT_StringHolder& name,
108  Args&&... args)
109  {
110  if (!myEnableRegistration)
111  return nullptr;
112 
113  if (name.isEmpty())
114  {
115  errors.appendFormat("Empty type name");
116  return nullptr;
117  }
118 
119  TypeMap& type_map = myTypes[(int)(RegType::Enum)];
120  BaseType* existing_type =
121  registeredType(RegType::Enum, name);
122 
123  if (existing_type)
124  {
125  errors.appendFormat(
126  "A type already exists with the name {}",
127  name);
128  return nullptr;
129  }
130 
131  RegType* new_type = new RegType(
132  name, std::forward<Args>(args)...);
133  type_map[name] = pdg_BaseTypePtr(new_type);
134  if (!new_type->initialize(errors))
135  {
136  if (errors.length() > 0)
137  errors.append(". ");
138  errors.appendFormat(
139  "Failed to initialize type {}", name);
140  type_map.erase(name);
141  return nullptr;
142  }
143 
144  handleLogMessage(
146  new_type->displayName(),
147  "ADD");
148 
149  return new_type;
150  }
151 
152  /// Registers a type that implements it's construction logic in a function,
153  /// rather than a custom class
154  template <typename RegType, typename... Args>
155  RegType* registerFuncType(UT_WorkBuffer& errors,
156  const UT_StringHolder& name,
157  typename RegType::Function func,
158  Args&&... args)
159  {
160  RegType* reg_type = registerType<RegType>(
161  errors, name, std::forward<Args>(args)...);
162 
163  if (!reg_type)
164  return nullptr;
165 
166  reg_type->setFunction(func);
167  return reg_type;
168  }
169 
170  /// Registers a type that uses the simple built-in function, which creates
171  /// and instance of the type using it's constructor and does no additional
172  /// logic
173  template <typename RegType, typename ClassType, typename... Args>
175  const UT_StringHolder& name,
176  Args&&... args)
177  {
178  return registerFuncType<RegType>(
179  errors,
180  name,
181  &RegType::template typeInit<ClassType>,
182  std::forward<Args>(args)...);
183  }
184 
185  /// Registers an alias for an existing type
186  bool registerTypeAlias(EnumType type,
187  const UT_StringHolder& name,
188  const UT_StringHolder& alias,
189  bool deprecated=false)
190  {
191  TypeMap& type_map = myTypes[(int)(type)];
192 
193  if (type_map.contains(alias))
194  return false;
195 
196  auto iter = type_map.find(name);
197  if (iter == type_map.end())
198  return false;
199 
201  message.format("{} -> {}", name, alias);
202  handleLogMessage(
204  message,
205  "ALIAS");
206 
207  if (deprecated)
208  deprecateType(type, alias);
209 
210  myTypes[(int)(type)][alias] = iter->second;
211  myAliases[(int)(type)].insert(alias);
212 
213  return true;
214  }
215 
216  /// Adds parent types to the type object.
218  const UT_StringArray& parent_names,
219  UT_WorkBuffer& errors)
220  {
221  EnumType reg_type = type->type();
222  for (auto&& parent_name : parent_names)
223  {
224  BaseType* parent = registeredType(
225  reg_type, parent_name);
226  if (!parent)
227  {
228  errors.appendFormat(
229  "{} not a valid type name",
230  parent_name);
231  return false;
232  }
233 
234  type->addParent(parent, true);
235  }
236 
237  return true;
238  }
239 
240  /// Directly adds a parent type, if it's valid
242  BaseType* parent,
243  UT_WorkBuffer& errors)
244  {
245  if (!parent)
246  {
247  errors.appendFormat(
248  "Empty parent type for '{}'",
249  type->typeName());
250  return false;
251  }
252 
253  if (type->type() != parent->type())
254  {
255  errors.appendFormat(
256  "Invalid parent type '{}' for '{}",
257  parent->typeName(),
258  type->typeName());
259  return false;
260  }
261 
262  type->addParent(parent, true);
263  return true;
264  }
265 
266  /// Loads and registers types compiled as a shared library
267  bool registerDSOTypes(const UT_StringHolder& dso_path)
268  {
269  return PDGT_Utils::loadDSO(
270  dso_path, myDSOFunction, (void*)this);
271  }
272 
273  /// Loads and registers types that are in DSOs on the PDG shared library
274  /// path, e.g. <dso_path>/pdg
276  {
277  return PDGT_Utils::loadDSO(
278  myDSOFunction, (void*)this);
279  }
280 
281  /// Registers all Python types on the PDG/types search path
283  {
285  myModuleName, errors);
286  }
287 
288  /// Registers a Python module by absolute path
290  UT_WorkBuffer& errors)
291  {
293  myModuleName, path, errors);
294  }
295 
296  /// Reloads a Python module by name
298  bool reregister,
299  UT_WorkBuffer& errors)
300  {
302  myModuleName, path, reregister, errors);
303  }
304 
305  /// Returns a generic type object for a given registered type and typename
307  const UT_StringHolder& name) const
308  {
309  auto iter = myTypes[(int)(type)].find(name);
310  if (iter == myTypes[(int)(type)].end())
311  return nullptr;
312 
313  if (myDeprecatedTypes[(int)(type)].contains(name))
314  {
315  handleLogMessage(
317  name,
318  "DEPRECATED");
319  }
320 
321  return iter->second.get();
322  }
323 
324  /// Deprecated a type name, so that accessing it will issue an warning
325  void deprecateType(EnumType type, const UT_StringHolder& name)
326  {
327  myDeprecatedTypes[(int)(type)].insert(name);
328  }
329 
330  /// Returns the set of all existing type names for registered type
331  UT_StringArray typeNames(EnumType type, bool include_aliases=false) const
332  {
333  const auto& aliases = myAliases[(int)(type)];
334 
335  UT_StringArray type_names;
336  for (auto&& entry : myTypes[(int)(type)])
337  {
338  if (!include_aliases)
339  {
340  if (aliases.contains(entry.first))
341  continue;
342  }
343 
344  type_names.append(entry.first);
345  }
346 
347  return type_names;
348  }
349 
350 private:
351  /// Handles reporting log messages, implemented by concrete subclass so
352  /// they can use their own logging mechanism
353  virtual void handleLogMessage(
355  const UT_StringHolder& message,
356  const UT_StringHolder& tag) const {}
357 
358 private:
359  TypeMap myTypes[EnumSize];
360  UT_StringSet myDeprecatedTypes[EnumSize];
361  UT_StringSet myAliases[EnumSize];
362  UT_StringHolder myDSOFunction;
363  UT_StringHolder myModuleName;
364  bool myInitFlag;
365  bool myEnableRegistration;
366 };
367 
368 #endif
GLuint GLsizei const GLchar * message
Definition: glcorearb.h:2543
typedef int(APIENTRYP RE_PFNGLXSWAPINTERVALSGIPROC)(int)
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.
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
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
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
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
bool standardInit(UT_WorkBuffer &errors, bool skip_python=false)
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
static bool loadPythonModules(const UT_StringHolder &type_module, UT_WorkBuffer &errors)
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
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