HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
HOM_IterableList.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 __HOM_IterableList_h__
10 #define __HOM_IterableList_h__
11 
12 #include "HOM_API.h"
13 #include "HOM_Defines.h"
14 #include "HOM_Errors.h"
15 #include "HOM_Module.h"
16 #include <string>
17 #include <vector>
18 #include <stdexcept>
19 
20 // In the general case, __getitem__ returns a pointer to a newly allocated
21 // object. For "native" data types like strings and numbers, though, we
22 // don't want to tell swig that it returns a pointer to one of those types.
23 // (If we do, calling tuple() or list() on an IterableList of strings gives
24 // lists of "<Swig Object of type 'std::string *' at 0x85feca0>" and warnings
25 // about memory leaks.) So, we specialize this class to return those types by
26 // value.
27 //
28 // Note that we always tell swig that __getitem__ always returns a new object,
29 // even if it's returning an int/float/double/string by value. There's no
30 // harm in doing that, and it simplifies the macro a little.
31 
32 // We could throw a std::out_of_range exception from __getitem__ and have
33 // swig catch that and in turn raise a python IndexError exception. However,
34 // unwinding the stack from the exception turns out to be extremely slow
35 // and the exception is thrown so much because that's how python knows to
36 // stop iterating, that throwing the C++ exception dramatically slow things
37 // down. The time needed to iterate through the vertices of a bunch of
38 // primitives, for example, is roughly doubled. So, instead of throwing that
39 // exception we use %extend to add a method that returns a PyObject*, and
40 // we set the python IndexError exception ourselves.
41 #ifdef SWIG
42 #define GETITEM_SWIG_EXTENSION \
43 %extend { \
44  /* TODO: We don't suppport slice objects as the key. */ \
45  %newobject __getitem__; \
46  InterpreterObject __getitem__(int key) \
47  { \
48  int length = self->__len__(); \
49  if (key < 0) \
50  key += length; \
51  if (key < 0 || key >= length) \
52  { \
53  PyErr_SetString(PyExc_IndexError, "Invalid index"); \
54  return NULL; \
55  } \
56  return HOMconvertValueForInterpreter( \
57  self->getItemWithValidIndex(key), SWIG_POINTER_OWN); \
58  } \
59 }
60 #else
61 #define GETITEM_SWIG_EXTENSION
62 #endif
63 
64 #define DEFINE_HOM_ITERABLE_LIST(template_parm, template_type, specialization, getitem_type) \
65 template <template_parm> \
66 class HOM_IterableList specialization \
67 { \
68 public: \
69  HOM_IterableList() \
70  { HOM_CONSTRUCT_OBJECT(this) } \
71  HOM_IterableList(const HOM_IterableList<template_type> &) \
72  { HOM_CONSTRUCT_OBJECT(this) } \
73  virtual ~HOM_IterableList() \
74  { HOM_DESTRUCT_OBJECT(this) } \
75 \
76  /* Note that we don't need to implement __iter__, since for loops will */ \
77  /* work if they find __getitem__. */ \
78  GETITEM_SWIG_EXTENSION \
79  \
80  virtual int __len__() = 0; \
81  virtual std::string __repr__() = 0; \
82 \
83  SWIGOUT(%ignore getItemWithValidIndex;) \
84  virtual getitem_type getItemWithValidIndex(int key) = 0; \
85 };
86 
87 // Swig doesn't like it when you skip macro parameters, so we use empty
88 // comments instead.
89 DEFINE_HOM_ITERABLE_LIST(typename T, T, /**/, T*)
90 DEFINE_HOM_ITERABLE_LIST(/**/, int, <int>, int)
91 DEFINE_HOM_ITERABLE_LIST(/**/, float, <float>, float)
92 DEFINE_HOM_ITERABLE_LIST(/**/, double, <double>, double)
93 DEFINE_HOM_ITERABLE_LIST(/**/, std::string, <std::string>, std::string)
94 
95 #undef DEFINE_HOM_ITERABLE_LIST
96 #undef GETITEM_SWIG_EXTENSION
97 
98 #endif
#define DEFINE_HOM_ITERABLE_LIST(template_parm, template_type, specialization, getitem_type)