HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
APEX_Buffer.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  * NAME: APEX_Buffer.h (APEX Library, C++)
7  *
8  * COMMENTS:
9  */
10 
11 #ifndef __APEX_BUFFER_H__
12 #define __APEX_BUFFER_H__
13 
14 #include "APEX_API.h"
15 #include "APEX_COW.h"
16 #include "APEX_Types.h"
17 
18 #include <UT/UT_Array.h>
19 #include <UT/UT_Assert.h>
20 #include <UT/UT_Debug.h>
21 #include <UT/UT_Format.h>
22 #include <UT/UT_NonCopyable.h>
23 #include <UT/UT_Optional.h>
24 #include <UT/UT_StringArray.h>
25 #include <UT/UT_StringHolder.h>
26 #include <UT/UT_WorkBuffer.h>
27 #include <SYS/SYS_Types.h>
28 
29 #include <utility>
30 
31 /*
32 
33 We currently support data on the buffer that requires a node compilation
34 to initialize (such as SOP_VerbParms etc.), this could very likely be
35 refactored to be placed in a node's callback::RunData argument, but still yet
36 to investigate fully.
37 
38 A possible thought here is to have a special tag for data types such as this
39 and separate out their storage so we keep the data that cannot be mem copied
40 away from those that can.
41 
42 */
43 
44 namespace apex
45 {
46 
47 class APEX_Argument;
48 
49 /*
50 Any type information (size_t) is taken directly from the APEX_TypeDefinition subclass.
51 */
52 
53 /// Expandable storage of arbitrary runtime types for APEX program state. Indexed by @ref APEX_Buffer.
55 {
56 public:
58  {
59  myTypeDefinition = typedfn;
60  }
61 
63  {
64  clear();
65  }
66  void clear();
67  void allocate(exint size);
68 
69  void *storage() { return myData; }
70  void *data(exint index = 0);
71  const APEX_TypeDefinitionBase *typeDefinition() { return myTypeDefinition; }
72 
73 private:
74  // There's some redundancy here if the parent APEX_Buffer
75  // stored these in a map... we could just store
76  // a flat array of APEX_TypedBuffer's on the APEX_Buffer
77  // and do any lookups using this member.
78  const APEX_TypeDefinitionBase *myTypeDefinition = nullptr;
79 
80  // Our actual data storage - std::pmr::monotonic_allocator is maybe worth looking into?
81  // as these buffers will only grow during graph compilation and will not ever resize
82  // until they are wiped clean by a graph definition change.
83  void *myData = nullptr;
84 };
85 
87 #define APEX_INVALID_DATAID -1
88 /*
89 The buffer should not deal with typeIds?
90 These are not guaranteed and so can only be resolved by a given
91 APEX_Registry, or collection thereof. So any APIs dealing with typeIds
92 need to resolve the APEX_TypeDefinition subclass against a registry before
93 querying the buffer.
94 */
95 
96 /// Holds all of the memory for execution state of a compiled APEX graph.
98 {
99 public:
101  {}
102 
103  /// Get a new unique data ID.
104  static APEX_DataID nextDataId();
105 
106  void clear()
107  {
108  myTypedBuffers.clear();
109  myIsLocked = false;
110  }
111 
112  /// Get the type-specific storage for a given type, or @c nullptr if not found.
114  {
115  for (auto &buf : myTypedBuffers)
116  {
117  if (buf.typeDefinition() == type_defn)
118  return &buf;
119  }
120  return nullptr;
121  }
122 
124  {
125  if (index < 0 || index >= myTypedBuffers.size())
126  return nullptr;
127  return &myTypedBuffers[index];
128  }
129 
130  /// Get the index at which a given type is stored in this buffer, or -1 if not present.
132  {
133  exint result = 0;
134  for (auto &buf : myTypedBuffers)
135  {
136  if (buf.typeDefinition() == type_defn)
137  {
138  break;
139  }
140  result++;
141  }
142  if (result >= myTypedBuffers.size())
143  return -1;
144  return result;
145  }
146 
147  /// Allocate a type-specific storage buffer of the given type of the given size. Returns the index
148  /// of the new storage.
150  {
151  exint type_index = typeIndex(type_defn);
152  if (type_index > -1)
153  {
154  UTdebugPrint("Attempt to allocate multiple buffers of the same type!");
155  return type_index;
156  }
157  exint t_buf_idx = myTypedBuffers.emplace_back(type_defn);
158  myTypedBuffers[t_buf_idx].allocate(size);
159  return t_buf_idx;
160  }
161 
162  /// Extend the type-specific storage buffer of the given type by one element and return an ApexArgument tracking it.
163  APEX_Argument append(const APEX_TypeDefinitionBase *type_defn);
164 
165  /// Set the value of the given argument in this buffer to the value. The type of the argument must support copying.
166  void set(APEX_Argument &arg, void *value);
167  /// Prevent further modifications to the layout of this buffer.
168  void lock() { myIsLocked = true; }
169  // This relies on the source of the APEX_TypeDefinition to be static
170  // UT_Map<APEX_TypeDefinitionBase *, APEX_TypedBuffer> myTypedBuffers;
171 private:
172  UT_Array<APEX_TypedBuffer> myTypedBuffers;
173  bool myIsLocked = false;
174 };
175 
176 /// Represents a location for a single object inside of an APEX_Buffer.
178 {
179 public:
180  APEX_Buffer *buffer = nullptr;
181  const APEX_TypeDefinitionBase *type_defn = nullptr;
182  exint offset = -1;
183 
184  bool isValid() const
185  {
186  return buffer && type_defn && (offset > -1);
187  }
188 
189  void *getVoidPtr()
190  {
191  if (!buffer)
192  return nullptr;
193  APEX_TypedBuffer *typed_buffer = buffer->findTypedBuffer(type_defn);
194  if (!typed_buffer || offset < 0)
195  return nullptr;
196  return typed_buffer->data(offset);
197  }
198 
199  const void *getVoidPtr() const
200  {
201  if (!buffer)
202  return nullptr;
203  APEX_TypedBuffer *typed_buffer = buffer->findTypedBuffer(type_defn);
204  if (!typed_buffer || offset < 0)
205  return nullptr;
206  return typed_buffer->data(offset);
207  }
208 };
209 
210 /// Represents a location for a single object inside of an APEX_Buffer while keeping track of some notion
211 /// of the data's freshness. Used by parameter dictionaries for cheap output caching.
213 {
214 public:
216 
217  APEX_DataID dataId() const { return myDataId; }
218  void bumpDataId() { myDataId = APEX_Buffer::nextDataId(); }
219  void copyDataId(const APEX_TrackedArgument &other) { myDataId = other.dataId(); }
220 };
221 
222 /// Check if a callback argument holds an instance of the given type.
223 template <typename T>
224 static bool
225 isType(const APEX_Argument &arg)
226 {
227  const APEX_TypeDefinitionBase *test_type = findTypeDef<T>();
228  return arg.type_defn == test_type;
229 }
230 
231 /// Return the address of the data contained in the passed argument if it is of the provided type,
232 /// otherwise return nullptr. APEX equivalent of @c dynamic_cast.
233 template <typename T>
234 static T *
235 castArg(APEX_Argument *arg)
236 {
237  if (!isType<T>(*arg))
238  return nullptr;
239  void *arg_ptr = arg->getVoidPtr();
240  return reinterpret_cast<T *>(arg_ptr);
241 }
242 
243 /// Return the address of the data contained in the passed argument if it is of the provided type,
244 /// otherwise return nullptr. APEX equivalent of @c dynamic_cast.
245 template <typename T>
246 static const T *
247 castArg(const APEX_Argument *arg)
248 {
249  if (!isType<T>(*arg))
250  return nullptr;
251  const void *arg_ptr = arg->getVoidPtr();
252  return reinterpret_cast<const T *>(arg_ptr);
253 }
254 
255 /// Returns an optional of the requested argument's value
256 template <typename T>
257 static UT_Optional<T>
258 castArgValue(APEX_Argument &arg)
259 {
261 
262  T *value = castArg<T>(&arg);
263  if (value)
264  result = *value;
265 
266  return result;
267 }
268 
269 /// Specialization for bools to allow conversion from integers
270 template <>
271 inline UT_Optional<Bool>
272 castArgValue(APEX_Argument &arg)
273 {
275 
276  if (Bool *value = castArg<Bool>(&arg))
277  result = *value;
278  else if (Int *value = castArg<Int>(&arg))
279  result = (*value != 0);
280 
281  return result;
282 }
283 
284 /// Specialization for ints to allow conversion from bools
285 template <>
286 inline UT_Optional<Int>
287 castArgValue(APEX_Argument &arg)
288 {
290 
291  if (Int *value = castArg<Int>(&arg))
292  result = *value;
293  else if (Bool *value = castArg<Bool>(&arg))
294  result = (*value? 1 : 0);
295 
296  return result;
297 }
298 
299 /// Safely copy data from one argument to another. Returns true if the copy actually occurred.
300 static bool
301 copyArgData(APEX_Argument *dst, const APEX_Argument *src, bool allow_implicit_conversion=false)
302 {
303  UT_ASSERT(dst->isValid());
304  UT_ASSERT(src->isValid());
305 
306  void *dst_ptr = dst->getVoidPtr();
307  const void *src_ptr = src->getVoidPtr();
308  if (dst->type_defn != src->type_defn)
309  {
310  if (!allow_implicit_conversion)
311  return false;
312 
313  if (isType<Bool>(*dst) && isType<Int>(*src))
314  {
315  // Int to bool conversion
316  Int val_int = *castArg<Int>(src);
317  Bool val_bool = val_int != 0;
318  Bool &dst_val = *castArg<Bool>(dst);
319  dst_val = val_bool;
320  return true;
321  }
322  else if (isType<Int>(*dst) && isType<Bool>(*src))
323  {
324  // Bool to int conversion
325  Bool val_bool = *castArg<Bool>(src);
326  Int val_int = val_bool? 1 : 0;
327  Int &dst_val = *castArg<Int>(dst);
328  dst_val = val_int;
329  return true;
330  }
331 
332  return false;
333  }
334  if (!dst->type_defn->isCopyable())
335  return false;
336  if (dst_ptr == src_ptr)
337  return false;
338  dst->type_defn->setData(dst_ptr, src_ptr);
339  return true;
340 }
341 
342 /// Returns the value of the argument as a string.
344 APEXformatArg(const APEX_Argument *arg);
345 
346 /// Takes a formatting string, and an array of arguments, and writes the
347 /// formatted string to the result.
348 APEX_API void
350  String &result,
351  const String &format_str,
353 
354 } // end namespace apex
355 
356 #endif // __APEX_BUFFER_H__
#define UTdebugPrint(...)
Definition: UT_Debug.h:146
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glcorearb.h:2540
APEX_DataID dataId() const
Definition: APEX_Buffer.h:217
static APEX_DataID nextDataId()
Get a new unique data ID.
const APEX_TypeDefinitionBase * typeDefinition()
Definition: APEX_Buffer.h:71
GLboolean * data
Definition: glcorearb.h:131
GLsizei const GLfloat * value
Definition: glcorearb.h:824
Expandable storage of arbitrary runtime types for APEX program state. Indexed by APEX_Buffer.
Definition: APEX_Buffer.h:54
#define APEX_API
Definition: APEX_API.h:21
int64 exint
Definition: SYS_Types.h:125
**But if you need a result
Definition: thread.h:622
void * data(exint index=0)
APEX_API void APEXformatString(String &result, const String &format_str, const UT_Array< const APEX_Argument * > &args)
auto arg(const Char *name, const T &arg) -> detail::named_arg< Char, T >
Definition: core.h:1859
GLuint buffer
Definition: glcorearb.h:660
Holds all of the memory for execution state of a compiled APEX graph.
Definition: APEX_Buffer.h:97
std::optional< T > UT_Optional
Definition: UT_Optional.h:26
GLintptr offset
Definition: glcorearb.h:665
int64 APEX_DataID
Definition: APEX_Buffer.h:86
constexpr auto set(type rhs) -> int
Definition: core.h:610
APEX_TypedBuffer(const APEX_TypeDefinitionBase *typedfn)
Definition: APEX_Buffer.h:57
long long int64
Definition: SYS_Types.h:116
UT_StringHolder String
Definition: APEX_Include.h:63
void copyDataId(const APEX_TrackedArgument &other)
Definition: APEX_Buffer.h:219
APEX_TypedBuffer * findTypedBuffer(const APEX_TypeDefinitionBase *type_defn)
Get the type-specific storage for a given type, or nullptr if not found.
Definition: APEX_Buffer.h:113
GLsizeiptr size
Definition: glcorearb.h:664
const void * getVoidPtr() const
Definition: APEX_Buffer.h:199
GLenum GLenum dst
Definition: glcorearb.h:1793
exint Int
Definition: APEX_Include.h:61
void lock()
Prevent further modifications to the layout of this buffer.
Definition: APEX_Buffer.h:168
GLuint index
Definition: glcorearb.h:786
bool Bool
Definition: APEX_Include.h:60
Type-safe formatting, modeled on the Python str.format function.
exint typeIndex(const APEX_TypeDefinitionBase *type_defn)
Get the index at which a given type is stored in this buffer, or -1 if not present.
Definition: APEX_Buffer.h:131
**If you just want to fire and args
Definition: thread.h:618
exint allocate(const APEX_TypeDefinitionBase *type_defn, exint size)
Definition: APEX_Buffer.h:149
#define UT_ASSERT(ZZ)
Definition: UT_Assert.h:165
APEX_API UT_StringHolder APEXformatArg(const APEX_Argument *arg)
Returns the value of the argument as a string.
Represents a location for a single object inside of an APEX_Buffer.
Definition: APEX_Buffer.h:177
bool isValid() const
Definition: APEX_Buffer.h:184
GLenum src
Definition: glcorearb.h:1793
APEX_TypedBuffer * getTypedBuffer(exint index)
Definition: APEX_Buffer.h:123